+++ /dev/null
-#!/usr/bin/env node
-
-var mime = require('./mime.js');
-var file = process.argv[2];
-var type = mime.lookup(file);
-
-process.stdout.write(type + '\n');
-
--- /dev/null
+../mime/cli.js
\ No newline at end of file
--- /dev/null
+../node-static/bin/cli.js
\ No newline at end of file
--- /dev/null
+../wscat/bin/wscat
\ No newline at end of file
--- /dev/null
+Copyright (c) 2010-14 Alexis Sellier
+
+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.
--- /dev/null
+node-static
+===========
+
+> a simple, *rfc 2616 compliant* file streaming module for [node](http://nodejs.org)
+
+node-static understands and supports *conditional GET* and *HEAD* requests.
+node-static was inspired by some of the other static-file serving modules out there,
+such as node-paperboy and antinode.
+
+Synopsis
+--------
+
+```js
+var static = require('node-static');
+
+//
+// Create a node-static server instance to serve the './public' folder
+//
+var file = new static.Server('./public');
+
+require('http').createServer(function (request, response) {
+ request.addListener('end', function () {
+ //
+ // Serve files!
+ //
+ file.serve(request, response);
+ }).resume();
+}).listen(8080);
+```
+
+API
+---
+
+### Creating a node-static Server #
+
+Creating a file server instance is as simple as:
+
+```js
+new static.Server();
+```
+
+This will serve files in the current directory. If you want to serve files in a specific
+directory, pass it as the first argument:
+
+```js
+new static.Server('./public');
+```
+
+You can also specify how long the client is supposed to cache the files node-static serves:
+
+```js
+new static.Server('./public', { cache: 3600 });
+```
+
+This will set the `Cache-Control` header, telling clients to cache the file for an hour.
+This is the default setting.
+
+### Serving files under a directory #
+
+To serve files under a directory, simply call the `serve` method on a `Server` instance, passing it
+the HTTP request and response object:
+
+```js
+var static = require('node-static');
+
+var fileServer = new static.Server('./public');
+
+require('http').createServer(function (request, response) {
+ request.addListener('end', function () {
+ fileServer.serve(request, response);
+ }).resume();
+}).listen(8080);
+```
+
+### Serving specific files #
+
+If you want to serve a specific file, like an error page for example, use the `serveFile` method:
+
+```js
+fileServer.serveFile('/error.html', 500, {}, request, response);
+```
+
+This will serve the `error.html` file, from under the file root directory, with a `500` status code.
+For example, you could serve an error page, when the initial request wasn't found:
+
+```js
+require('http').createServer(function (request, response) {
+ request.addListener('end', function () {
+ fileServer.serve(request, response, function (e, res) {
+ if (e && (e.status === 404)) { // If the file wasn't found
+ fileServer.serveFile('/not-found.html', 404, {}, request, response);
+ }
+ });
+ }).resume();
+}).listen(8080);
+```
+
+More on intercepting errors bellow.
+
+### Intercepting errors & Listening #
+
+An optional callback can be passed as last argument, it will be called every time a file
+has been served successfully, or if there was an error serving the file:
+
+```js
+var static = require('node-static');
+
+var fileServer = new static.Server('./public');
+
+require('http').createServer(function (request, response) {
+ request.addListener('end', function () {
+ fileServer.serve(request, response, function (err, result) {
+ if (err) { // There was an error serving the file
+ console.error("Error serving " + request.url + " - " + err.message);
+
+ // Respond to the client
+ response.writeHead(err.status, err.headers);
+ response.end();
+ }
+ });
+ }).resume();
+}).listen(8080);
+```
+
+Note that if you pass a callback, and there is an error serving the file, node-static
+*will not* respond to the client. This gives you the opportunity to re-route the request,
+or handle it differently.
+
+For example, you may want to interpret a request as a static request, but if the file isn't found,
+send it to an application.
+
+If you only want to *listen* for errors, you can use *event listeners*:
+
+```js
+fileServer.serve(request, response).addListener('error', function (err) {
+ console.error("Error serving " + request.url + " - " + err.message);
+});
+```
+
+With this method, you don't have to explicitly send the response back, in case of an error.
+
+### Options when creating an instance of `Server` #
+
+#### `cache` #
+
+Sets the `Cache-Control` header.
+
+example: `{ cache: 7200 }`
+
+Passing a number will set the cache duration to that number of seconds.
+Passing `false` will disable the `Cache-Control` header.
+
+> Defaults to `3600`
+
+
+#### `serverInfo` #
+
+Sets the `Server` header.
+
+example: `{ serverInfo: "myserver" }`
+
+> Defaults to `node-static/{version}`
+
+#### `headers` #
+
+Sets response headers.
+
+example: `{ 'X-Hello': 'World!' }`
+
+> defaults to `{}`
+
+#### `gzip` #
+
+Enable support for sending compressed responses. This will enable a check for a
+file with the same name plus '.gz' in the same folder. If the compressed file is
+found and the client has indicated support for gzip file transfer, the contents
+of the .gz file will be sent in place of the uncompressed file along with a
+Content-Encoding: gzip header to inform the client the data has been compressed.
+
+example: `{ gzip: true }`
+example: `{ gzip: /^\/text/ }`
+
+Passing `true` will enable this check for all files.
+Passing a RegExp instance will only enable this check if the content-type of the
+respond would match that RegExp using its test() method.
+
+> Defaults to `false`
+
+#### `indexFile` #
+
+Choose a custom index file when serving up directories.
+
+example: `{ indexFile: "index.htm" }`
+
+> Defaults to `index.html`
+
+
+Command Line Interface
+----------------------
+
+`node-static` also provides a CLI.
+
+### Installation #
+
+```sh
+$ npm install -g node-static
+```
+
+### Example Usage #
+
+```sh
+# serve up the current directory
+$ static
+serving "." at http://127.0.0.1:8080
+
+# serve up a different directory
+$ static public
+serving "public" at http://127.0.0.1:8080
+
+# specify additional headers (this one is useful for development)
+$ static -H '{"Cache-Control": "no-cache, must-revalidate"}'
+serving "." at http://127.0.0.1:8080
+
+# set cache control max age
+$ static -c 7200
+serving "." at http://127.0.0.1:8080
+
+# expose the server to your local network
+$ static -a 0.0.0.0
+serving "." at http://0.0.0.0:8080
+
+# show help message, including all options
+$ static -h
+```
--- /dev/null
+This is ApacheBench, Version 2.3 <$Revision: 655654 $>
+Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
+Licensed to The Apache Software Foundation, http://www.apache.org/
+
+Benchmarking 127.0.0.1 (be patient)
+
+
+Server Software: node-static/0.3.0
+Server Hostname: 127.0.0.1
+Server Port: 8080
+
+Document Path: /lib/node-static.js
+Document Length: 6038 bytes
+
+Concurrency Level: 20
+Time taken for tests: 2.323 seconds
+Complete requests: 10000
+Failed requests: 0
+Write errors: 0
+Total transferred: 63190000 bytes
+HTML transferred: 60380000 bytes
+Requests per second: 4304.67 [#/sec] (mean)
+Time per request: 4.646 [ms] (mean)
+Time per request: 0.232 [ms] (mean, across all concurrent requests)
+Transfer rate: 26563.66 [Kbytes/sec] received
+
+Connection Times (ms)
+ min mean[+/-sd] median max
+Connect: 0 0 0.2 0 3
+Processing: 1 4 1.4 4 28
+Waiting: 1 4 1.3 4 18
+Total: 2 5 1.5 4 28
+
+Percentage of the requests served within a certain time (ms)
+ 50% 4
+ 66% 5
+ 75% 5
+ 80% 5
+ 90% 5
+ 95% 6
+ 98% 8
+ 99% 9
+ 100% 28 (longest request)
--- /dev/null
+#!/usr/bin/env node
+
+var fs = require('fs'),
+ tty = require('tty'),
+ statik = require('./../lib/node-static');
+
+ var argv = require('optimist')
+ .usage([
+ 'USAGE: $0 [-p <port>] [<directory>]',
+ 'simple, rfc 2616 compliant file streaming module for node']
+ .join('\n\n'))
+ .option('port', {
+ alias: 'p',
+ 'default': 8080,
+ description: 'TCP port at which the files will be served'
+ })
+ .option('host-address', {
+ alias: 'a',
+ 'default': '127.0.0.1',
+ description: 'the local network interface at which to listen'
+ })
+ .option('cache', {
+ alias: 'c',
+ description: '"Cache-Control" header setting, defaults to 3600'
+ })
+ .option('version', {
+ alias: 'v',
+ description: 'node-static version'
+ })
+ .option('headers', {
+ alias: 'H',
+ description: 'additional headers (in JSON format)'
+ })
+ .option('header-file', {
+ alias: 'f',
+ description: 'JSON file of additional headers'
+ })
+ .option('gzip', {
+ alias: 'z',
+ description: 'enable compression (tries to serve file of same name plus \'.gz\')'
+ })
+ .option('spa', {
+ description: 'serve the content as a single page app by redirecting all non-file requests to the index html file'
+ })
+ .option('indexFile', {
+ alias: 'i',
+ 'default': 'index.html',
+ description: 'specify a custom index file when serving up directories'
+ })
+ .option('help', {
+ alias: 'h',
+ description: 'display this help message'
+ })
+ .argv;
+
+ var dir = argv._[0] || '.';
+
+ var colors = require('colors');
+
+ var log = function(request, response, statusCode) {
+ var d = new Date();
+ var seconds = d.getSeconds() < 10? '0'+d.getSeconds() : d.getSeconds(),
+ datestr = d.getHours() + ':' + d.getMinutes() + ':' + seconds,
+ line = datestr + ' [' + response.statusCode + ']: ' + request.url,
+ colorized = line;
+ if (tty.isatty(process.stdout.fd))
+ colorized = (response.statusCode >= 500) ? line.red.bold :
+ (response.statusCode >= 400) ? line.red :
+ line;
+ console.log(colorized);
+ };
+
+ var file, options;
+
+if (argv.help) {
+ require('optimist').showHelp(console.log);
+ process.exit(0);
+}
+
+if (argv.version) {
+ console.log('node-static', statik.version.join('.'));
+ process.exit(0);
+}
+
+if (argv.cache) {
+ (options = options || {}).cache = argv.cache;
+}
+
+if (argv.headers) {
+ (options = options || {}).headers = JSON.parse(argv.headers);
+}
+
+if (argv['header-file']) {
+ (options = options || {}).headers =
+ JSON.parse(fs.readFileSync(argv['header-file']));
+}
+
+if (argv.gzip) {
+ (options = options || {}).gzip = true;
+}
+
+if (argv.indexFile) {
+ (options = options || {}).indexFile = argv['indexFile'];
+}
+
+file = new(statik.Server)(dir, options);
+
+require('http').createServer(function (request, response) {
+ request.addListener('end', function () {
+ var callback = function(e, rsp) {
+ if (e && e.status === 404) {
+ response.writeHead(e.status, e.headers);
+ response.end("Not Found");
+ log(request, response);
+ } else {
+ log(request, response);
+ }
+ };
+
+ if (argv['spa'] && request.url.indexOf(".") == -1) {
+ file.serveFile(argv['indexFile'], 200, {}, request, response);
+ } else {
+ file.serve(request, response, callback);
+ }
+ }).resume();
+}).listen(+argv.port, argv['host-address']);
+
+console.log('serving "' + dir + '" at http://' + argv['host-address'] + ':' + argv.port);
+if (argv.spa) {
+ console.log('serving as a single page app (all non-file requests redirect to ' + argv['indexFile'] +')');
+}
--- /dev/null
+var static = require('../lib/node-static');
+
+//
+// Create a node-static server to serve the current directory
+//
+var file = new static.Server('.', { cache: 7200, headers: {'X-Hello':'World!'} });
+
+require('http').createServer(function (request, response) {
+ file.serve(request, response, function (err, res) {
+ if (err) { // An error as occured
+ console.error("> Error serving " + request.url + " - " + err.message);
+ response.writeHead(err.status, err.headers);
+ response.end();
+ } else { // The file was served successfully
+ console.log("> " + request.url + " - " + res.message);
+ }
+ });
+}).listen(8080);
+
+console.log("> node-static is listening on http://127.0.0.1:8080");
--- /dev/null
+var fs = require('fs')
+ , events = require('events')
+ , buffer = require('buffer')
+ , http = require('http')
+ , url = require('url')
+ , path = require('path')
+ , mime = require('mime')
+ , util = require('./node-static/util');
+
+// Current version
+var version = [0, 7, 9];
+
+var Server = function (root, options) {
+ if (root && (typeof(root) === 'object')) { options = root; root = null }
+
+ // resolve() doesn't normalize (to lowercase) drive letters on Windows
+ this.root = path.normalize(path.resolve(root || '.'));
+ this.options = options || {};
+ this.cache = 3600;
+
+ this.defaultHeaders = {};
+ this.options.headers = this.options.headers || {};
+
+ this.options.indexFile = this.options.indexFile || "index.html";
+
+ if ('cache' in this.options) {
+ if (typeof(this.options.cache) === 'number') {
+ this.cache = this.options.cache;
+ } else if (! this.options.cache) {
+ this.cache = false;
+ }
+ }
+
+ if ('serverInfo' in this.options) {
+ this.serverInfo = this.options.serverInfo.toString();
+ } else {
+ this.serverInfo = 'node-static/' + version.join('.');
+ }
+
+ this.defaultHeaders['server'] = this.serverInfo;
+
+ if (this.cache !== false) {
+ this.defaultHeaders['cache-control'] = 'max-age=' + this.cache;
+ }
+
+ for (var k in this.defaultHeaders) {
+ this.options.headers[k] = this.options.headers[k] ||
+ this.defaultHeaders[k];
+ }
+};
+
+Server.prototype.serveDir = function (pathname, req, res, finish) {
+ var htmlIndex = path.join(pathname, this.options.indexFile),
+ that = this;
+
+ fs.stat(htmlIndex, function (e, stat) {
+ if (!e) {
+ var status = 200;
+ var headers = {};
+ var originalPathname = decodeURI(url.parse(req.url).pathname);
+ if (originalPathname.length && originalPathname.charAt(originalPathname.length - 1) !== '/') {
+ return finish(301, { 'Location': originalPathname + '/' });
+ } else {
+ that.respond(null, status, headers, [htmlIndex], stat, req, res, finish);
+ }
+ } else {
+ // Stream a directory of files as a single file.
+ fs.readFile(path.join(pathname, 'index.json'), function (e, contents) {
+ if (e) { return finish(404, {}) }
+ var index = JSON.parse(contents);
+ streamFiles(index.files);
+ });
+ }
+ });
+ function streamFiles(files) {
+ util.mstat(pathname, files, function (e, stat) {
+ if (e) { return finish(404, {}) }
+ that.respond(pathname, 200, {}, files, stat, req, res, finish);
+ });
+ }
+};
+
+Server.prototype.serveFile = function (pathname, status, headers, req, res) {
+ var that = this;
+ var promise = new(events.EventEmitter);
+
+ pathname = this.resolve(pathname);
+
+ fs.stat(pathname, function (e, stat) {
+ if (e) {
+ return promise.emit('error', e);
+ }
+ that.respond(null, status, headers, [pathname], stat, req, res, function (status, headers) {
+ that.finish(status, headers, req, res, promise);
+ });
+ });
+ return promise;
+};
+
+Server.prototype.finish = function (status, headers, req, res, promise, callback) {
+ var result = {
+ status: status,
+ headers: headers,
+ message: http.STATUS_CODES[status]
+ };
+
+ headers['server'] = this.serverInfo;
+
+ if (!status || status >= 400) {
+ if (callback) {
+ callback(result);
+ } else {
+ if (promise.listeners('error').length > 0) {
+ promise.emit('error', result);
+ }
+ else {
+ res.writeHead(status, headers);
+ res.end();
+ }
+ }
+ } else {
+ // Don't end the request here, if we're streaming;
+ // it's taken care of in `prototype.stream`.
+ if (status !== 200 || req.method !== 'GET') {
+ res.writeHead(status, headers);
+ res.end();
+ }
+ callback && callback(null, result);
+ promise.emit('success', result);
+ }
+};
+
+Server.prototype.servePath = function (pathname, status, headers, req, res, finish) {
+ var that = this,
+ promise = new(events.EventEmitter);
+
+ pathname = this.resolve(pathname);
+
+ // Make sure we're not trying to access a
+ // file outside of the root.
+ if (pathname.indexOf(that.root) === 0) {
+ fs.stat(pathname, function (e, stat) {
+ if (e) {
+ finish(404, {});
+ } else if (stat.isFile()) { // Stream a single file.
+ that.respond(null, status, headers, [pathname], stat, req, res, finish);
+ } else if (stat.isDirectory()) { // Stream a directory of files.
+ that.serveDir(pathname, req, res, finish);
+ } else {
+ finish(400, {});
+ }
+ });
+ } else {
+ // Forbidden
+ finish(403, {});
+ }
+ return promise;
+};
+
+Server.prototype.resolve = function (pathname) {
+ return path.resolve(path.join(this.root, pathname));
+};
+
+Server.prototype.serve = function (req, res, callback) {
+ var that = this,
+ promise = new(events.EventEmitter),
+ pathname;
+
+ var finish = function (status, headers) {
+ that.finish(status, headers, req, res, promise, callback);
+ };
+
+ try {
+ pathname = decodeURI(url.parse(req.url).pathname);
+ }
+ catch(e) {
+ return process.nextTick(function() {
+ return finish(400, {});
+ });
+ }
+
+ process.nextTick(function () {
+ that.servePath(pathname, 200, {}, req, res, finish).on('success', function (result) {
+ promise.emit('success', result);
+ }).on('error', function (err) {
+ promise.emit('error');
+ });
+ });
+ if (! callback) { return promise }
+};
+
+/* Check if we should consider sending a gzip version of the file based on the
+ * file content type and client's Accept-Encoding header value.
+ */
+Server.prototype.gzipOk = function (req, contentType) {
+ var enable = this.options.gzip;
+ if(enable &&
+ (typeof enable === 'boolean' ||
+ (contentType && (enable instanceof RegExp) && enable.test(contentType)))) {
+ var acceptEncoding = req.headers['accept-encoding'];
+ return acceptEncoding && acceptEncoding.indexOf("gzip") >= 0;
+ }
+ return false;
+}
+
+/* Send a gzipped version of the file if the options and the client indicate gzip is enabled and
+ * we find a .gz file mathing the static resource requested.
+ */
+Server.prototype.respondGzip = function (pathname, status, contentType, _headers, files, stat, req, res, finish) {
+ var that = this;
+ if (files.length == 1 && this.gzipOk(req, contentType)) {
+ var gzFile = files[0] + ".gz";
+ fs.stat(gzFile, function (e, gzStat) {
+ if (!e && gzStat.isFile()) {
+ var vary = _headers['Vary'];
+ _headers['Vary'] = (vary && vary != 'Accept-Encoding' ? vary + ', ' : '') + 'Accept-Encoding';
+ _headers['Content-Encoding'] = 'gzip';
+ stat.size = gzStat.size;
+ files = [gzFile];
+ }
+ that.respondNoGzip(pathname, status, contentType, _headers, files, stat, req, res, finish);
+ });
+ } else {
+ // Client doesn't want gzip or we're sending multiple files
+ that.respondNoGzip(pathname, status, contentType, _headers, files, stat, req, res, finish);
+ }
+}
+
+Server.prototype.parseByteRange = function (req, stat) {
+ var byteRange = {
+ from: 0,
+ to: 0,
+ valid: false
+ }
+
+ var rangeHeader = req.headers['range'];
+ var flavor = 'bytes=';
+
+ if (rangeHeader) {
+ if (rangeHeader.indexOf(flavor) == 0 && rangeHeader.indexOf(',') == -1) {
+ /* Parse */
+ rangeHeader = rangeHeader.substr(flavor.length).split('-');
+ byteRange.from = parseInt(rangeHeader[0]);
+ byteRange.to = parseInt(rangeHeader[1]);
+
+ /* Replace empty fields of differential requests by absolute values */
+ if (isNaN(byteRange.from) && !isNaN(byteRange.to)) {
+ byteRange.from = stat.size - byteRange.to;
+ byteRange.to = stat.size ? stat.size - 1 : 0;
+ } else if (!isNaN(byteRange.from) && isNaN(byteRange.to)) {
+ byteRange.to = stat.size ? stat.size - 1 : 0;
+ }
+
+ /* General byte range validation */
+ if (!isNaN(byteRange.from) && !!byteRange.to && 0 <= byteRange.from && byteRange.from < byteRange.to) {
+ byteRange.valid = true;
+ } else {
+ console.warn("Request contains invalid range header: ", rangeHeader);
+ }
+ } else {
+ console.warn("Request contains unsupported range header: ", rangeHeader);
+ }
+ }
+ return byteRange;
+}
+
+Server.prototype.respondNoGzip = function (pathname, status, contentType, _headers, files, stat, req, res, finish) {
+ var mtime = Date.parse(stat.mtime),
+ key = pathname || files[0],
+ headers = {},
+ clientETag = req.headers['if-none-match'],
+ clientMTime = Date.parse(req.headers['if-modified-since']),
+ startByte = 0,
+ length = stat.size,
+ byteRange = this.parseByteRange(req, stat);
+
+ /* Handle byte ranges */
+ if (files.length == 1 && byteRange.valid) {
+ if (byteRange.to < length) {
+
+ // Note: HTTP Range param is inclusive
+ startByte = byteRange.from;
+ length = byteRange.to - byteRange.from + 1;
+ status = 206;
+
+ // Set Content-Range response header (we advertise initial resource size on server here (stat.size))
+ headers['Content-Range'] = 'bytes ' + byteRange.from + '-' + byteRange.to + '/' + stat.size;
+
+ } else {
+ byteRange.valid = false;
+ console.warn("Range request exceeds file boundaries, goes until byte no", byteRange.to, "against file size of", length, "bytes");
+ }
+ }
+
+ /* In any case, check for unhandled byte range headers */
+ if (!byteRange.valid && req.headers['range']) {
+ console.error(new Error("Range request present but invalid, might serve whole file instead"));
+ }
+
+ // Copy default headers
+ for (var k in this.options.headers) { headers[k] = this.options.headers[k] }
+ // Copy custom headers
+ for (var k in _headers) { headers[k] = _headers[k] }
+
+ headers['Etag'] = JSON.stringify([stat.ino, stat.size, mtime].join('-'));
+ headers['Date'] = new(Date)().toUTCString();
+ headers['Last-Modified'] = new(Date)(stat.mtime).toUTCString();
+ headers['Content-Type'] = contentType;
+ headers['Content-Length'] = length;
+
+ for (var k in _headers) { headers[k] = _headers[k] }
+
+ // Conditional GET
+ // If the "If-Modified-Since" or "If-None-Match" headers
+ // match the conditions, send a 304 Not Modified.
+ if ((clientMTime || clientETag) &&
+ (!clientETag || clientETag === headers['Etag']) &&
+ (!clientMTime || clientMTime >= mtime)) {
+ // 304 response should not contain entity headers
+ ['Content-Encoding',
+ 'Content-Language',
+ 'Content-Length',
+ 'Content-Location',
+ 'Content-MD5',
+ 'Content-Range',
+ 'Content-Type',
+ 'Expires',
+ 'Last-Modified'].forEach(function (entityHeader) {
+ delete headers[entityHeader];
+ });
+ finish(304, headers);
+ } else {
+ res.writeHead(status, headers);
+
+ this.stream(key, files, length, startByte, res, function (e) {
+ if (e) { return finish(500, {}) }
+ finish(status, headers);
+ });
+ }
+};
+
+Server.prototype.respond = function (pathname, status, _headers, files, stat, req, res, finish) {
+ var contentType = _headers['Content-Type'] ||
+ mime.lookup(files[0]) ||
+ 'application/octet-stream';
+
+ if(this.options.gzip) {
+ this.respondGzip(pathname, status, contentType, _headers, files, stat, req, res, finish);
+ } else {
+ this.respondNoGzip(pathname, status, contentType, _headers, files, stat, req, res, finish);
+ }
+}
+
+Server.prototype.stream = function (pathname, files, length, startByte, res, callback) {
+
+ (function streamFile(files, offset) {
+ var file = files.shift();
+
+ if (file) {
+ file = path.resolve(file) === path.normalize(file) ? file : path.join(pathname || '.', file);
+
+ // Stream the file to the client
+ fs.createReadStream(file, {
+ flags: 'r',
+ mode: 0666,
+ start: startByte,
+ end: startByte + (length ? length - 1 : 0)
+ }).on('data', function (chunk) {
+ // Bounds check the incoming chunk and offset, as copying
+ // a buffer from an invalid offset will throw an error and crash
+ if (chunk.length && offset < length && offset >= 0) {
+ offset += chunk.length;
+ }
+ }).on('close', function () {
+ streamFile(files, offset);
+ }).on('error', function (err) {
+ callback(err);
+ console.error(err);
+ }).pipe(res, { end: false });
+ } else {
+ res.end();
+ callback(null, offset);
+ }
+ })(files.slice(0), 0);
+};
+
+// Exports
+exports.Server = Server;
+exports.version = version;
+exports.mime = mime;
+
+
+
--- /dev/null
+var fs = require('fs')
+ , path = require('path');
+
+exports.mstat = function (dir, files, callback) {
+ (function mstat(files, stats) {
+ var file = files.shift();
+
+ if (file) {
+ fs.stat(path.join(dir, file), function (e, stat) {
+ if (e) {
+ callback(e);
+ } else {
+ mstat(files, stats.concat([stat]));
+ }
+ });
+ } else {
+ callback(null, {
+ size: stats.reduce(function (total, stat) {
+ return total + stat.size;
+ }, 0),
+ mtime: stats.reduce(function (latest, stat) {
+ return latest > stat.mtime ? latest : stat.mtime;
+ }, 0),
+ ino: stats.reduce(function (total, stat) {
+ return total + stat.ino;
+ }, 0)
+ });
+ }
+ })(files.slice(0), []);
+};
--- /dev/null
+MIT License
+
+Original Library
+ - Copyright (c) Marak Squires
+
+Additional Functionality
+ - Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.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.
--- /dev/null
+# colors.js
+[![Build Status](https://travis-ci.org/Marak/colors.js.svg?branch=master)](https://travis-ci.org/Marak/colors.js)
+[![version](https://img.shields.io/npm/v/colors.svg)](https://www.npmjs.org/package/colors)
+[![dependencies](https://david-dm.org/Marak/colors.js.svg)](https://david-dm.org/Marak/colors.js)
+[![devDependencies](https://david-dm.org/Marak/colors.js/dev-status.svg)](https://david-dm.org/Marak/colors.js#info=devDependencies)
+
+Please check out the [roadmap](ROADMAP.md) for upcoming features and releases. Please open Issues to provide feedback, and check the `develop` branch for the latest bleeding-edge updates.
+
+## get color and style in your node.js console
+
+![Demo](https://raw.githubusercontent.com/Marak/colors.js/master/screenshots/colors.png)
+
+## Installation
+
+ npm install colors
+
+## colors and styles!
+
+### text colors
+
+ - black
+ - red
+ - green
+ - yellow
+ - blue
+ - magenta
+ - cyan
+ - white
+ - gray
+ - grey
+
+### bright text colors
+
+ - brightRed
+ - brightGreen
+ - brightYellow
+ - brightBlue
+ - brightMagenta
+ - brightCyan
+ - brightWhite
+
+### background colors
+
+ - bgBlack
+ - bgRed
+ - bgGreen
+ - bgYellow
+ - bgBlue
+ - bgMagenta
+ - bgCyan
+ - bgWhite
+ - bgGray
+ - bgGrey
+
+### bright background colors
+
+ - bgBrightRed
+ - bgBrightGreen
+ - bgBrightYellow
+ - bgBrightBlue
+ - bgBrightMagenta
+ - bgBrightCyan
+ - bgBrightWhite
+
+### styles
+
+ - reset
+ - bold
+ - dim
+ - italic
+ - underline
+ - inverse
+ - hidden
+ - strikethrough
+
+### extras
+
+ - rainbow
+ - zebra
+ - america
+ - trap
+ - random
+
+
+## Usage
+
+By popular demand, `colors` now ships with two types of usages!
+
+The super nifty way
+
+```js
+var colors = require('colors');
+
+console.log('hello'.green); // outputs green text
+console.log('i like cake and pies'.underline.red) // outputs red underlined text
+console.log('inverse the color'.inverse); // inverses the color
+console.log('OMG Rainbows!'.rainbow); // rainbow
+console.log('Run the trap'.trap); // Drops the bass
+
+```
+
+or a slightly less nifty way which doesn't extend `String.prototype`
+
+```js
+var colors = require('colors/safe');
+
+console.log(colors.green('hello')); // outputs green text
+console.log(colors.red.underline('i like cake and pies')) // outputs red underlined text
+console.log(colors.inverse('inverse the color')); // inverses the color
+console.log(colors.rainbow('OMG Rainbows!')); // rainbow
+console.log(colors.trap('Run the trap')); // Drops the bass
+
+```
+
+I prefer the first way. Some people seem to be afraid of extending `String.prototype` and prefer the second way.
+
+If you are writing good code you will never have an issue with the first approach. If you really don't want to touch `String.prototype`, the second usage will not touch `String` native object.
+
+## Enabling/Disabling Colors
+
+The package will auto-detect whether your terminal can use colors and enable/disable accordingly. When colors are disabled, the color functions do nothing. You can override this with a command-line flag:
+
+```bash
+node myapp.js --no-color
+node myapp.js --color=false
+
+node myapp.js --color
+node myapp.js --color=true
+node myapp.js --color=always
+
+FORCE_COLOR=1 node myapp.js
+```
+
+Or in code:
+
+```javascript
+var colors = require('colors');
+colors.enable();
+colors.disable();
+```
+
+## Console.log [string substitution](http://nodejs.org/docs/latest/api/console.html#console_console_log_data)
+
+```js
+var name = 'Marak';
+console.log(colors.green('Hello %s'), name);
+// outputs -> 'Hello Marak'
+```
+
+## Custom themes
+
+### Using standard API
+
+```js
+
+var colors = require('colors');
+
+colors.setTheme({
+ silly: 'rainbow',
+ input: 'grey',
+ verbose: 'cyan',
+ prompt: 'grey',
+ info: 'green',
+ data: 'grey',
+ help: 'cyan',
+ warn: 'yellow',
+ debug: 'blue',
+ error: 'red'
+});
+
+// outputs red text
+console.log("this is an error".error);
+
+// outputs yellow text
+console.log("this is a warning".warn);
+```
+
+### Using string safe API
+
+```js
+var colors = require('colors/safe');
+
+// set single property
+var error = colors.red;
+error('this is red');
+
+// set theme
+colors.setTheme({
+ silly: 'rainbow',
+ input: 'grey',
+ verbose: 'cyan',
+ prompt: 'grey',
+ info: 'green',
+ data: 'grey',
+ help: 'cyan',
+ warn: 'yellow',
+ debug: 'blue',
+ error: 'red'
+});
+
+// outputs red text
+console.log(colors.error("this is an error"));
+
+// outputs yellow text
+console.log(colors.warn("this is a warning"));
+
+```
+
+### Combining Colors
+
+```javascript
+var colors = require('colors');
+
+colors.setTheme({
+ custom: ['red', 'underline']
+});
+
+console.log('test'.custom);
+```
+
+*Protip: There is a secret undocumented style in `colors`. If you find the style you can summon him.*
--- /dev/null
+var colors = require('../lib/index');
+
+console.log('First some yellow text'.yellow);
+
+console.log('Underline that text'.yellow.underline);
+
+console.log('Make it bold and red'.red.bold);
+
+console.log(('Double Raindows All Day Long').rainbow);
+
+console.log('Drop the bass'.trap);
+
+console.log('DROP THE RAINBOW BASS'.trap.rainbow);
+
+// styles not widely supported
+console.log('Chains are also cool.'.bold.italic.underline.red);
+
+// styles not widely supported
+console.log('So '.green + 'are'.underline + ' ' + 'inverse'.inverse
+ + ' styles! '.yellow.bold);
+console.log('Zebras are so fun!'.zebra);
+
+//
+// Remark: .strikethrough may not work with Mac OS Terminal App
+//
+console.log('This is ' + 'not'.strikethrough + ' fun.');
+
+console.log('Background color attack!'.black.bgWhite);
+console.log('Use random styles on everything!'.random);
+console.log('America, Heck Yeah!'.america);
+
+console.log('Blindingly '.brightCyan + 'bright? '.brightRed + 'Why '.brightYellow + 'not?!'.brightGreen);
+
+console.log('Setting themes is useful');
+
+//
+// Custom themes
+//
+console.log('Generic logging theme as JSON'.green.bold.underline);
+// Load theme with JSON literal
+colors.setTheme({
+ silly: 'rainbow',
+ input: 'grey',
+ verbose: 'cyan',
+ prompt: 'grey',
+ info: 'green',
+ data: 'grey',
+ help: 'cyan',
+ warn: 'yellow',
+ debug: 'blue',
+ error: 'red',
+});
+
+// outputs red text
+console.log('this is an error'.error);
+
+// outputs yellow text
+console.log('this is a warning'.warn);
+
+// outputs grey text
+console.log('this is an input'.input);
+
+console.log('Generic logging theme as file'.green.bold.underline);
+
+// Load a theme from file
+try {
+ colors.setTheme(require(__dirname + '/../themes/generic-logging.js'));
+} catch (err) {
+ console.log(err);
+}
+
+// outputs red text
+console.log('this is an error'.error);
+
+// outputs yellow text
+console.log('this is a warning'.warn);
+
+// outputs grey text
+console.log('this is an input'.input);
+
+// console.log("Don't summon".zalgo)
+
--- /dev/null
+var colors = require('../safe');
+
+console.log(colors.yellow('First some yellow text'));
+
+console.log(colors.yellow.underline('Underline that text'));
+
+console.log(colors.red.bold('Make it bold and red'));
+
+console.log(colors.rainbow('Double Raindows All Day Long'));
+
+console.log(colors.trap('Drop the bass'));
+
+console.log(colors.rainbow(colors.trap('DROP THE RAINBOW BASS')));
+
+// styles not widely supported
+console.log(colors.bold.italic.underline.red('Chains are also cool.'));
+
+// styles not widely supported
+console.log(colors.green('So ') + colors.underline('are') + ' '
+ + colors.inverse('inverse') + colors.yellow.bold(' styles! '));
+
+console.log(colors.zebra('Zebras are so fun!'));
+
+console.log('This is ' + colors.strikethrough('not') + ' fun.');
+
+
+console.log(colors.black.bgWhite('Background color attack!'));
+console.log(colors.random('Use random styles on everything!'));
+console.log(colors.america('America, Heck Yeah!'));
+
+console.log(colors.brightCyan('Blindingly ') + colors.brightRed('bright? ') + colors.brightYellow('Why ') + colors.brightGreen('not?!'));
+
+console.log('Setting themes is useful');
+
+//
+// Custom themes
+//
+// console.log('Generic logging theme as JSON'.green.bold.underline);
+// Load theme with JSON literal
+colors.setTheme({
+ silly: 'rainbow',
+ input: 'blue',
+ verbose: 'cyan',
+ prompt: 'grey',
+ info: 'green',
+ data: 'grey',
+ help: 'cyan',
+ warn: 'yellow',
+ debug: 'blue',
+ error: 'red',
+});
+
+// outputs red text
+console.log(colors.error('this is an error'));
+
+// outputs yellow text
+console.log(colors.warn('this is a warning'));
+
+// outputs blue text
+console.log(colors.input('this is an input'));
+
+
+// console.log('Generic logging theme as file'.green.bold.underline);
+
+// Load a theme from file
+colors.setTheme(require(__dirname + '/../themes/generic-logging.js'));
+
+// outputs red text
+console.log(colors.error('this is an error'));
+
+// outputs yellow text
+console.log(colors.warn('this is a warning'));
+
+// outputs grey text
+console.log(colors.input('this is an input'));
+
+// console.log(colors.zalgo("Don't summon him"))
+
+
--- /dev/null
+// Type definitions for Colors.js 1.2
+// Project: https://github.com/Marak/colors.js
+// Definitions by: Bart van der Schoor <https://github.com/Bartvds>, Staffan Eketorp <https://github.com/staeke>
+// Definitions: https://github.com/Marak/colors.js
+
+export interface Color {
+ (text: string): string;
+
+ strip: Color;
+ stripColors: Color;
+
+ black: Color;
+ red: Color;
+ green: Color;
+ yellow: Color;
+ blue: Color;
+ magenta: Color;
+ cyan: Color;
+ white: Color;
+ gray: Color;
+ grey: Color;
+
+ bgBlack: Color;
+ bgRed: Color;
+ bgGreen: Color;
+ bgYellow: Color;
+ bgBlue: Color;
+ bgMagenta: Color;
+ bgCyan: Color;
+ bgWhite: Color;
+
+ reset: Color;
+ bold: Color;
+ dim: Color;
+ italic: Color;
+ underline: Color;
+ inverse: Color;
+ hidden: Color;
+ strikethrough: Color;
+
+ rainbow: Color;
+ zebra: Color;
+ america: Color;
+ trap: Color;
+ random: Color;
+ zalgo: Color;
+}
+
+export function enable(): void;
+export function disable(): void;
+export function setTheme(theme: any): void;
+
+export let enabled: boolean;
+
+export const strip: Color;
+export const stripColors: Color;
+
+export const black: Color;
+export const red: Color;
+export const green: Color;
+export const yellow: Color;
+export const blue: Color;
+export const magenta: Color;
+export const cyan: Color;
+export const white: Color;
+export const gray: Color;
+export const grey: Color;
+
+export const bgBlack: Color;
+export const bgRed: Color;
+export const bgGreen: Color;
+export const bgYellow: Color;
+export const bgBlue: Color;
+export const bgMagenta: Color;
+export const bgCyan: Color;
+export const bgWhite: Color;
+
+export const reset: Color;
+export const bold: Color;
+export const dim: Color;
+export const italic: Color;
+export const underline: Color;
+export const inverse: Color;
+export const hidden: Color;
+export const strikethrough: Color;
+
+export const rainbow: Color;
+export const zebra: Color;
+export const america: Color;
+export const trap: Color;
+export const random: Color;
+export const zalgo: Color;
+
+declare global {
+ interface String {
+ strip: string;
+ stripColors: string;
+
+ black: string;
+ red: string;
+ green: string;
+ yellow: string;
+ blue: string;
+ magenta: string;
+ cyan: string;
+ white: string;
+ gray: string;
+ grey: string;
+
+ bgBlack: string;
+ bgRed: string;
+ bgGreen: string;
+ bgYellow: string;
+ bgBlue: string;
+ bgMagenta: string;
+ bgCyan: string;
+ bgWhite: string;
+
+ reset: string;
+ // @ts-ignore
+ bold: string;
+ dim: string;
+ italic: string;
+ underline: string;
+ inverse: string;
+ hidden: string;
+ strikethrough: string;
+
+ rainbow: string;
+ zebra: string;
+ america: string;
+ trap: string;
+ random: string;
+ zalgo: string;
+ }
+}
--- /dev/null
+/*
+
+The MIT License (MIT)
+
+Original Library
+ - Copyright (c) Marak Squires
+
+Additional functionality
+ - Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.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.
+
+*/
+
+var colors = {};
+module['exports'] = colors;
+
+colors.themes = {};
+
+var util = require('util');
+var ansiStyles = colors.styles = require('./styles');
+var defineProps = Object.defineProperties;
+var newLineRegex = new RegExp(/[\r\n]+/g);
+
+colors.supportsColor = require('./system/supports-colors').supportsColor;
+
+if (typeof colors.enabled === 'undefined') {
+ colors.enabled = colors.supportsColor() !== false;
+}
+
+colors.enable = function() {
+ colors.enabled = true;
+};
+
+colors.disable = function() {
+ colors.enabled = false;
+};
+
+colors.stripColors = colors.strip = function(str) {
+ return ('' + str).replace(/\x1B\[\d+m/g, '');
+};
+
+// eslint-disable-next-line no-unused-vars
+var stylize = colors.stylize = function stylize(str, style) {
+ if (!colors.enabled) {
+ return str+'';
+ }
+
+ var styleMap = ansiStyles[style];
+
+ // Stylize should work for non-ANSI styles, too
+ if(!styleMap && style in colors){
+ // Style maps like trap operate as functions on strings;
+ // they don't have properties like open or close.
+ return colors[style](str);
+ }
+
+ return styleMap.open + str + styleMap.close;
+};
+
+var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g;
+var escapeStringRegexp = function(str) {
+ if (typeof str !== 'string') {
+ throw new TypeError('Expected a string');
+ }
+ return str.replace(matchOperatorsRe, '\\$&');
+};
+
+function build(_styles) {
+ var builder = function builder() {
+ return applyStyle.apply(builder, arguments);
+ };
+ builder._styles = _styles;
+ // __proto__ is used because we must return a function, but there is
+ // no way to create a function with a different prototype.
+ builder.__proto__ = proto;
+ return builder;
+}
+
+var styles = (function() {
+ var ret = {};
+ ansiStyles.grey = ansiStyles.gray;
+ Object.keys(ansiStyles).forEach(function(key) {
+ ansiStyles[key].closeRe =
+ new RegExp(escapeStringRegexp(ansiStyles[key].close), 'g');
+ ret[key] = {
+ get: function() {
+ return build(this._styles.concat(key));
+ },
+ };
+ });
+ return ret;
+})();
+
+var proto = defineProps(function colors() {}, styles);
+
+function applyStyle() {
+ var args = Array.prototype.slice.call(arguments);
+
+ var str = args.map(function(arg) {
+ // Use weak equality check so we can colorize null/undefined in safe mode
+ if (arg != null && arg.constructor === String) {
+ return arg;
+ } else {
+ return util.inspect(arg);
+ }
+ }).join(' ');
+
+ if (!colors.enabled || !str) {
+ return str;
+ }
+
+ var newLinesPresent = str.indexOf('\n') != -1;
+
+ var nestedStyles = this._styles;
+
+ var i = nestedStyles.length;
+ while (i--) {
+ var code = ansiStyles[nestedStyles[i]];
+ str = code.open + str.replace(code.closeRe, code.open) + code.close;
+ if (newLinesPresent) {
+ str = str.replace(newLineRegex, function(match) {
+ return code.close + match + code.open;
+ });
+ }
+ }
+
+ return str;
+}
+
+colors.setTheme = function(theme) {
+ if (typeof theme === 'string') {
+ console.log('colors.setTheme now only accepts an object, not a string. ' +
+ 'If you are trying to set a theme from a file, it is now your (the ' +
+ 'caller\'s) responsibility to require the file. The old syntax ' +
+ 'looked like colors.setTheme(__dirname + ' +
+ '\'/../themes/generic-logging.js\'); The new syntax looks like '+
+ 'colors.setTheme(require(__dirname + ' +
+ '\'/../themes/generic-logging.js\'));');
+ return;
+ }
+ for (var style in theme) {
+ (function(style) {
+ colors[style] = function(str) {
+ if (typeof theme[style] === 'object') {
+ var out = str;
+ for (var i in theme[style]) {
+ out = colors[theme[style][i]](out);
+ }
+ return out;
+ }
+ return colors[theme[style]](str);
+ };
+ })(style);
+ }
+};
+
+function init() {
+ var ret = {};
+ Object.keys(styles).forEach(function(name) {
+ ret[name] = {
+ get: function() {
+ return build([name]);
+ },
+ };
+ });
+ return ret;
+}
+
+var sequencer = function sequencer(map, str) {
+ var exploded = str.split('');
+ exploded = exploded.map(map);
+ return exploded.join('');
+};
+
+// custom formatter methods
+colors.trap = require('./custom/trap');
+colors.zalgo = require('./custom/zalgo');
+
+// maps
+colors.maps = {};
+colors.maps.america = require('./maps/america')(colors);
+colors.maps.zebra = require('./maps/zebra')(colors);
+colors.maps.rainbow = require('./maps/rainbow')(colors);
+colors.maps.random = require('./maps/random')(colors);
+
+for (var map in colors.maps) {
+ (function(map) {
+ colors[map] = function(str) {
+ return sequencer(colors.maps[map], str);
+ };
+ })(map);
+}
+
+defineProps(colors, init());
--- /dev/null
+module['exports'] = function runTheTrap(text, options) {
+ var result = '';
+ text = text || 'Run the trap, drop the bass';
+ text = text.split('');
+ var trap = {
+ a: ['\u0040', '\u0104', '\u023a', '\u0245', '\u0394', '\u039b', '\u0414'],
+ b: ['\u00df', '\u0181', '\u0243', '\u026e', '\u03b2', '\u0e3f'],
+ c: ['\u00a9', '\u023b', '\u03fe'],
+ d: ['\u00d0', '\u018a', '\u0500', '\u0501', '\u0502', '\u0503'],
+ e: ['\u00cb', '\u0115', '\u018e', '\u0258', '\u03a3', '\u03be', '\u04bc',
+ '\u0a6c'],
+ f: ['\u04fa'],
+ g: ['\u0262'],
+ h: ['\u0126', '\u0195', '\u04a2', '\u04ba', '\u04c7', '\u050a'],
+ i: ['\u0f0f'],
+ j: ['\u0134'],
+ k: ['\u0138', '\u04a0', '\u04c3', '\u051e'],
+ l: ['\u0139'],
+ m: ['\u028d', '\u04cd', '\u04ce', '\u0520', '\u0521', '\u0d69'],
+ n: ['\u00d1', '\u014b', '\u019d', '\u0376', '\u03a0', '\u048a'],
+ o: ['\u00d8', '\u00f5', '\u00f8', '\u01fe', '\u0298', '\u047a', '\u05dd',
+ '\u06dd', '\u0e4f'],
+ p: ['\u01f7', '\u048e'],
+ q: ['\u09cd'],
+ r: ['\u00ae', '\u01a6', '\u0210', '\u024c', '\u0280', '\u042f'],
+ s: ['\u00a7', '\u03de', '\u03df', '\u03e8'],
+ t: ['\u0141', '\u0166', '\u0373'],
+ u: ['\u01b1', '\u054d'],
+ v: ['\u05d8'],
+ w: ['\u0428', '\u0460', '\u047c', '\u0d70'],
+ x: ['\u04b2', '\u04fe', '\u04fc', '\u04fd'],
+ y: ['\u00a5', '\u04b0', '\u04cb'],
+ z: ['\u01b5', '\u0240'],
+ };
+ text.forEach(function(c) {
+ c = c.toLowerCase();
+ var chars = trap[c] || [' '];
+ var rand = Math.floor(Math.random() * chars.length);
+ if (typeof trap[c] !== 'undefined') {
+ result += trap[c][rand];
+ } else {
+ result += c;
+ }
+ });
+ return result;
+};
--- /dev/null
+// please no
+module['exports'] = function zalgo(text, options) {
+ text = text || ' he is here ';
+ var soul = {
+ 'up': [
+ '̍', '̎', '̄', '̅',
+ '̿', '̑', '̆', '̐',
+ '͒', '͗', '͑', '̇',
+ '̈', '̊', '͂', '̓',
+ '̈', '͊', '͋', '͌',
+ '̃', '̂', '̌', '͐',
+ '̀', '́', '̋', '̏',
+ '̒', '̓', '̔', '̽',
+ '̉', 'ͣ', 'ͤ', 'ͥ',
+ 'ͦ', 'ͧ', 'ͨ', 'ͩ',
+ 'ͪ', 'ͫ', 'ͬ', 'ͭ',
+ 'ͮ', 'ͯ', '̾', '͛',
+ '͆', '̚',
+ ],
+ 'down': [
+ '̖', '̗', '̘', '̙',
+ '̜', '̝', '̞', '̟',
+ '̠', '̤', '̥', '̦',
+ '̩', '̪', '̫', '̬',
+ '̭', '̮', '̯', '̰',
+ '̱', '̲', '̳', '̹',
+ '̺', '̻', '̼', 'ͅ',
+ '͇', '͈', '͉', '͍',
+ '͎', '͓', '͔', '͕',
+ '͖', '͙', '͚', '̣',
+ ],
+ 'mid': [
+ '̕', '̛', '̀', '́',
+ '͘', '̡', '̢', '̧',
+ '̨', '̴', '̵', '̶',
+ '͜', '͝', '͞',
+ '͟', '͠', '͢', '̸',
+ '̷', '͡', ' ҉',
+ ],
+ };
+ var all = [].concat(soul.up, soul.down, soul.mid);
+
+ function randomNumber(range) {
+ var r = Math.floor(Math.random() * range);
+ return r;
+ }
+
+ function isChar(character) {
+ var bool = false;
+ all.filter(function(i) {
+ bool = (i === character);
+ });
+ return bool;
+ }
+
+
+ function heComes(text, options) {
+ var result = '';
+ var counts;
+ var l;
+ options = options || {};
+ options['up'] =
+ typeof options['up'] !== 'undefined' ? options['up'] : true;
+ options['mid'] =
+ typeof options['mid'] !== 'undefined' ? options['mid'] : true;
+ options['down'] =
+ typeof options['down'] !== 'undefined' ? options['down'] : true;
+ options['size'] =
+ typeof options['size'] !== 'undefined' ? options['size'] : 'maxi';
+ text = text.split('');
+ for (l in text) {
+ if (isChar(l)) {
+ continue;
+ }
+ result = result + text[l];
+ counts = {'up': 0, 'down': 0, 'mid': 0};
+ switch (options.size) {
+ case 'mini':
+ counts.up = randomNumber(8);
+ counts.mid = randomNumber(2);
+ counts.down = randomNumber(8);
+ break;
+ case 'maxi':
+ counts.up = randomNumber(16) + 3;
+ counts.mid = randomNumber(4) + 1;
+ counts.down = randomNumber(64) + 3;
+ break;
+ default:
+ counts.up = randomNumber(8) + 1;
+ counts.mid = randomNumber(6) / 2;
+ counts.down = randomNumber(8) + 1;
+ break;
+ }
+
+ var arr = ['up', 'mid', 'down'];
+ for (var d in arr) {
+ var index = arr[d];
+ for (var i = 0; i <= counts[index]; i++) {
+ if (options[index]) {
+ result = result + soul[index][randomNumber(soul[index].length)];
+ }
+ }
+ }
+ }
+ return result;
+ }
+ // don't summon him
+ return heComes(text, options);
+};
+
--- /dev/null
+var colors = require('./colors');
+
+module['exports'] = function() {
+ //
+ // Extends prototype of native string object to allow for "foo".red syntax
+ //
+ var addProperty = function(color, func) {
+ String.prototype.__defineGetter__(color, func);
+ };
+
+ addProperty('strip', function() {
+ return colors.strip(this);
+ });
+
+ addProperty('stripColors', function() {
+ return colors.strip(this);
+ });
+
+ addProperty('trap', function() {
+ return colors.trap(this);
+ });
+
+ addProperty('zalgo', function() {
+ return colors.zalgo(this);
+ });
+
+ addProperty('zebra', function() {
+ return colors.zebra(this);
+ });
+
+ addProperty('rainbow', function() {
+ return colors.rainbow(this);
+ });
+
+ addProperty('random', function() {
+ return colors.random(this);
+ });
+
+ addProperty('america', function() {
+ return colors.america(this);
+ });
+
+ //
+ // Iterate through all default styles and colors
+ //
+ var x = Object.keys(colors.styles);
+ x.forEach(function(style) {
+ addProperty(style, function() {
+ return colors.stylize(this, style);
+ });
+ });
+
+ function applyTheme(theme) {
+ //
+ // Remark: This is a list of methods that exist
+ // on String that you should not overwrite.
+ //
+ var stringPrototypeBlacklist = [
+ '__defineGetter__', '__defineSetter__', '__lookupGetter__',
+ '__lookupSetter__', 'charAt', 'constructor', 'hasOwnProperty',
+ 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString',
+ 'valueOf', 'charCodeAt', 'indexOf', 'lastIndexOf', 'length',
+ 'localeCompare', 'match', 'repeat', 'replace', 'search', 'slice',
+ 'split', 'substring', 'toLocaleLowerCase', 'toLocaleUpperCase',
+ 'toLowerCase', 'toUpperCase', 'trim', 'trimLeft', 'trimRight',
+ ];
+
+ Object.keys(theme).forEach(function(prop) {
+ if (stringPrototypeBlacklist.indexOf(prop) !== -1) {
+ console.log('warn: '.red + ('String.prototype' + prop).magenta +
+ ' is probably something you don\'t want to override. ' +
+ 'Ignoring style name');
+ } else {
+ if (typeof(theme[prop]) === 'string') {
+ colors[prop] = colors[theme[prop]];
+ addProperty(prop, function() {
+ return colors[prop](this);
+ });
+ } else {
+ var themePropApplicator = function(str) {
+ var ret = str || this;
+ for (var t = 0; t < theme[prop].length; t++) {
+ ret = colors[theme[prop][t]](ret);
+ }
+ return ret;
+ };
+ addProperty(prop, themePropApplicator);
+ colors[prop] = function(str) {
+ return themePropApplicator(str);
+ };
+ }
+ }
+ });
+ }
+
+ colors.setTheme = function(theme) {
+ if (typeof theme === 'string') {
+ console.log('colors.setTheme now only accepts an object, not a string. ' +
+ 'If you are trying to set a theme from a file, it is now your (the ' +
+ 'caller\'s) responsibility to require the file. The old syntax ' +
+ 'looked like colors.setTheme(__dirname + ' +
+ '\'/../themes/generic-logging.js\'); The new syntax looks like '+
+ 'colors.setTheme(require(__dirname + ' +
+ '\'/../themes/generic-logging.js\'));');
+ return;
+ } else {
+ applyTheme(theme);
+ }
+ };
+};
--- /dev/null
+var colors = require('./colors');
+module['exports'] = colors;
+
+// Remark: By default, colors will add style properties to String.prototype.
+//
+// If you don't wish to extend String.prototype, you can do this instead and
+// native String will not be touched:
+//
+// var colors = require('colors/safe);
+// colors.red("foo")
+//
+//
+require('./extendStringPrototype')();
--- /dev/null
+module['exports'] = function(colors) {
+ return function(letter, i, exploded) {
+ if (letter === ' ') return letter;
+ switch (i%3) {
+ case 0: return colors.red(letter);
+ case 1: return colors.white(letter);
+ case 2: return colors.blue(letter);
+ }
+ };
+};
--- /dev/null
+module['exports'] = function(colors) {
+ // RoY G BiV
+ var rainbowColors = ['red', 'yellow', 'green', 'blue', 'magenta'];
+ return function(letter, i, exploded) {
+ if (letter === ' ') {
+ return letter;
+ } else {
+ return colors[rainbowColors[i++ % rainbowColors.length]](letter);
+ }
+ };
+};
+
--- /dev/null
+module['exports'] = function(colors) {
+ var available = ['underline', 'inverse', 'grey', 'yellow', 'red', 'green',
+ 'blue', 'white', 'cyan', 'magenta', 'brightYellow', 'brightRed',
+ 'brightGreen', 'brightBlue', 'brightWhite', 'brightCyan', 'brightMagenta'];
+ return function(letter, i, exploded) {
+ return letter === ' ' ? letter :
+ colors[
+ available[Math.round(Math.random() * (available.length - 2))]
+ ](letter);
+ };
+};
--- /dev/null
+module['exports'] = function(colors) {
+ return function(letter, i, exploded) {
+ return i % 2 === 0 ? letter : colors.inverse(letter);
+ };
+};
--- /dev/null
+/*
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.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.
+
+*/
+
+var styles = {};
+module['exports'] = styles;
+
+var codes = {
+ reset: [0, 0],
+
+ bold: [1, 22],
+ dim: [2, 22],
+ italic: [3, 23],
+ underline: [4, 24],
+ inverse: [7, 27],
+ hidden: [8, 28],
+ strikethrough: [9, 29],
+
+ black: [30, 39],
+ red: [31, 39],
+ green: [32, 39],
+ yellow: [33, 39],
+ blue: [34, 39],
+ magenta: [35, 39],
+ cyan: [36, 39],
+ white: [37, 39],
+ gray: [90, 39],
+ grey: [90, 39],
+
+ brightRed: [91, 39],
+ brightGreen: [92, 39],
+ brightYellow: [93, 39],
+ brightBlue: [94, 39],
+ brightMagenta: [95, 39],
+ brightCyan: [96, 39],
+ brightWhite: [97, 39],
+
+ bgBlack: [40, 49],
+ bgRed: [41, 49],
+ bgGreen: [42, 49],
+ bgYellow: [43, 49],
+ bgBlue: [44, 49],
+ bgMagenta: [45, 49],
+ bgCyan: [46, 49],
+ bgWhite: [47, 49],
+ bgGray: [100, 49],
+ bgGrey: [100, 49],
+
+ bgBrightRed: [101, 49],
+ bgBrightGreen: [102, 49],
+ bgBrightYellow: [103, 49],
+ bgBrightBlue: [104, 49],
+ bgBrightMagenta: [105, 49],
+ bgBrightCyan: [106, 49],
+ bgBrightWhite: [107, 49],
+
+ // legacy styles for colors pre v1.0.0
+ blackBG: [40, 49],
+ redBG: [41, 49],
+ greenBG: [42, 49],
+ yellowBG: [43, 49],
+ blueBG: [44, 49],
+ magentaBG: [45, 49],
+ cyanBG: [46, 49],
+ whiteBG: [47, 49],
+
+};
+
+Object.keys(codes).forEach(function(key) {
+ var val = codes[key];
+ var style = styles[key] = [];
+ style.open = '\u001b[' + val[0] + 'm';
+ style.close = '\u001b[' + val[1] + 'm';
+});
--- /dev/null
+/*
+MIT License
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.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.
+*/
+
+'use strict';
+
+module.exports = function(flag, argv) {
+ argv = argv || process.argv;
+
+ var terminatorPos = argv.indexOf('--');
+ var prefix = /^-{1,2}/.test(flag) ? '' : '--';
+ var pos = argv.indexOf(prefix + flag);
+
+ return pos !== -1 && (terminatorPos === -1 ? true : pos < terminatorPos);
+};
--- /dev/null
+/*
+The MIT License (MIT)
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.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.
+
+*/
+
+'use strict';
+
+var os = require('os');
+var hasFlag = require('./has-flag.js');
+
+var env = process.env;
+
+var forceColor = void 0;
+if (hasFlag('no-color') || hasFlag('no-colors') || hasFlag('color=false')) {
+ forceColor = false;
+} else if (hasFlag('color') || hasFlag('colors') || hasFlag('color=true')
+ || hasFlag('color=always')) {
+ forceColor = true;
+}
+if ('FORCE_COLOR' in env) {
+ forceColor = env.FORCE_COLOR.length === 0
+ || parseInt(env.FORCE_COLOR, 10) !== 0;
+}
+
+function translateLevel(level) {
+ if (level === 0) {
+ return false;
+ }
+
+ return {
+ level: level,
+ hasBasic: true,
+ has256: level >= 2,
+ has16m: level >= 3,
+ };
+}
+
+function supportsColor(stream) {
+ if (forceColor === false) {
+ return 0;
+ }
+
+ if (hasFlag('color=16m') || hasFlag('color=full')
+ || hasFlag('color=truecolor')) {
+ return 3;
+ }
+
+ if (hasFlag('color=256')) {
+ return 2;
+ }
+
+ if (stream && !stream.isTTY && forceColor !== true) {
+ return 0;
+ }
+
+ var min = forceColor ? 1 : 0;
+
+ if (process.platform === 'win32') {
+ // Node.js 7.5.0 is the first version of Node.js to include a patch to
+ // libuv that enables 256 color output on Windows. Anything earlier and it
+ // won't work. However, here we target Node.js 8 at minimum as it is an LTS
+ // release, and Node.js 7 is not. Windows 10 build 10586 is the first
+ // Windows release that supports 256 colors. Windows 10 build 14931 is the
+ // first release that supports 16m/TrueColor.
+ var osRelease = os.release().split('.');
+ if (Number(process.versions.node.split('.')[0]) >= 8
+ && Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
+ return Number(osRelease[2]) >= 14931 ? 3 : 2;
+ }
+
+ return 1;
+ }
+
+ if ('CI' in env) {
+ if (['TRAVIS', 'CIRCLECI', 'APPVEYOR', 'GITLAB_CI'].some(function(sign) {
+ return sign in env;
+ }) || env.CI_NAME === 'codeship') {
+ return 1;
+ }
+
+ return min;
+ }
+
+ if ('TEAMCITY_VERSION' in env) {
+ return (/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env.TEAMCITY_VERSION) ? 1 : 0
+ );
+ }
+
+ if ('TERM_PROGRAM' in env) {
+ var version = parseInt((env.TERM_PROGRAM_VERSION || '').split('.')[0], 10);
+
+ switch (env.TERM_PROGRAM) {
+ case 'iTerm.app':
+ return version >= 3 ? 3 : 2;
+ case 'Hyper':
+ return 3;
+ case 'Apple_Terminal':
+ return 2;
+ // No default
+ }
+ }
+
+ if (/-256(color)?$/i.test(env.TERM)) {
+ return 2;
+ }
+
+ if (/^screen|^xterm|^vt100|^rxvt|color|ansi|cygwin|linux/i.test(env.TERM)) {
+ return 1;
+ }
+
+ if ('COLORTERM' in env) {
+ return 1;
+ }
+
+ if (env.TERM === 'dumb') {
+ return min;
+ }
+
+ return min;
+}
+
+function getSupportLevel(stream) {
+ var level = supportsColor(stream);
+ return translateLevel(level);
+}
+
+module.exports = {
+ supportsColor: getSupportLevel,
+ stdout: getSupportLevel(process.stdout),
+ stderr: getSupportLevel(process.stderr),
+};
--- /dev/null
+{
+ "name": "colors",
+ "description": "get colors in your node.js console",
+ "version": "1.4.0",
+ "author": {
+ "name": "Marak Squires"
+ },
+ "contributors": [
+ {
+ "name": "DABH",
+ "url": "https://github.com/DABH"
+ }
+ ],
+ "homepage": "https://github.com/Marak/colors.js",
+ "bugs": {
+ "url": "https://github.com/Marak/colors.js/issues"
+ },
+ "keywords": [
+ "ansi",
+ "terminal",
+ "colors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git+ssh://git@github.com/Marak/colors.js.git"
+ },
+ "license": "MIT",
+ "scripts": {
+ "lint": "eslint . --fix",
+ "test": "node tests/basic-test.js && node tests/safe-test.js"
+ },
+ "engines": {
+ "node": ">=0.1.90"
+ },
+ "main": "lib/index.js",
+ "devDependencies": {
+ "eslint": "^5.2.0",
+ "eslint-config-google": "^0.11.0"
+ },
+ "gitHead": "baa0e1c7dc50d868354206b9ea71273e3f05f593",
+ "_id": "colors@1.4.0",
+ "_nodeVersion": "10.16.3",
+ "_npmVersion": "6.9.0",
+ "dist": {
+ "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==",
+ "shasum": "c50491479d4c1bdaed2c9ced32cf7c7dc2360f78",
+ "tarball": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
+ "fileCount": 21,
+ "unpackedSize": 39506,
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdiAfACRA9TVsSAnZWagAA7gMP/1eUoL2YZSoe4XH3p7o5\n2NRhGJuE+81Kwbl/2+HWvlWGXxTo1vLYWGVAfBVYtEuUdnPlMOpCEyqdB8Ng\nqMr9acH/8ZkHKRyNYu9GeDLWWUFx8wv94qpcmnuqgp+24X3gBhiS7hnG6UJh\nL4kKUSycTGp0FFWPQ4tdpBuvC6PDGTowPfHh/oj0RosHygRcW6F4V5HDyws1\nQTnuE3k5vBhhzKQQ4oktGCUuQATqsg89lDDSw5hjThBf2y5ZrpF6qLVoiLgm\noMrEF3vDOIyf63naUmj/3qzBYFfQZU3wlGyaRfNxdqNooKW2QOb/x2XFtP46\nYibCl2xhGA0JsinmaAclbLfDkZSZs1bsjpj2xUOFJjQOeMReeS2PzCgHRBJy\nT9ow3X6MbRblOcWuX8Bbhr8kg9Av1xx2A9mtJ7G/DVuHLHBQOTro2l/qIb5M\nf9Z/++j4P1lMMKBp5jHvCRUNq9jgWdSaT9NHo1RvNKuEZM9mxyzyygcidj5w\ngaCGQ5G5kFOKAgmN1LvRYai5P31waqJ+Wr96g6XRfA9SBeeeX12v481jpKQm\nVZ6khQeII1VUgbadjWWegRAobEkW5JXLjdZbISZeIBahs5bOWPFiAFXowf4O\n7Hygdj0xtzkH/sWJeKUCxnzX6VN/mtu+QkPfjGBgDHNL4gtZsGDAizcsFuly\nDWUs\r\n=9VVk\r\n-----END PGP SIGNATURE-----\r\n"
+ },
+ "maintainers": [
+ {
+ "email": "dabh@stanford.edu",
+ "name": "dabh"
+ },
+ {
+ "email": "marak.squires@gmail.com",
+ "name": "marak"
+ }
+ ],
+ "_npmUser": {
+ "name": "dabh",
+ "email": "dabh@alumni.stanford.edu"
+ },
+ "directories": {},
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/colors_1.4.0_1569195967207_0.2781122116893864"
+ },
+ "_hasShrinkwrap": false,
+ "_shasum": "c50491479d4c1bdaed2c9ced32cf7c7dc2360f78",
+ "_from": "colors@>=0.6.0",
+ "_resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz"
+}
--- /dev/null
+// Type definitions for Colors.js 1.2
+// Project: https://github.com/Marak/colors.js
+// Definitions by: Bart van der Schoor <https://github.com/Bartvds>, Staffan Eketorp <https://github.com/staeke>
+// Definitions: https://github.com/Marak/colors.js
+
+export const enabled: boolean;
+export function enable(): void;
+export function disable(): void;
+export function setTheme(theme: any): void;
+
+export function strip(str: string): string;
+export function stripColors(str: string): string;
+
+export function black(str: string): string;
+export function red(str: string): string;
+export function green(str: string): string;
+export function yellow(str: string): string;
+export function blue(str: string): string;
+export function magenta(str: string): string;
+export function cyan(str: string): string;
+export function white(str: string): string;
+export function gray(str: string): string;
+export function grey(str: string): string;
+
+export function bgBlack(str: string): string;
+export function bgRed(str: string): string;
+export function bgGreen(str: string): string;
+export function bgYellow(str: string): string;
+export function bgBlue(str: string): string;
+export function bgMagenta(str: string): string;
+export function bgCyan(str: string): string;
+export function bgWhite(str: string): string;
+
+export function reset(str: string): string;
+export function bold(str: string): string;
+export function dim(str: string): string;
+export function italic(str: string): string;
+export function underline(str: string): string;
+export function inverse(str: string): string;
+export function hidden(str: string): string;
+export function strikethrough(str: string): string;
+
+export function rainbow(str: string): string;
+export function zebra(str: string): string;
+export function america(str: string): string;
+export function trap(str: string): string;
+export function random(str: string): string;
+export function zalgo(str: string): string;
--- /dev/null
+//
+// Remark: Requiring this file will use the "safe" colors API,
+// which will not touch String.prototype.
+//
+// var colors = require('colors/safe');
+// colors.red("foo")
+//
+//
+var colors = require('./lib/colors');
+module['exports'] = colors;
--- /dev/null
+module['exports'] = {
+ silly: 'rainbow',
+ input: 'grey',
+ verbose: 'cyan',
+ prompt: 'grey',
+ info: 'green',
+ data: 'grey',
+ help: 'cyan',
+ warn: 'yellow',
+ debug: 'blue',
+ error: 'red',
+};
--- /dev/null
+language: node_js
+node_js:
+ - "0.8"
+ - "0.10"
--- /dev/null
+Copyright 2010 James Halliday (mail@substack.net)
+
+This project is free software released under the MIT/X11 license:
+
+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.
--- /dev/null
+#!/usr/bin/env node
+var util = require('util');
+var argv = require('optimist').argv;
+
+if (argv.s) {
+ util.print(argv.fr ? 'Le chat dit: ' : 'The cat says: ');
+}
+console.log(
+ (argv.fr ? 'miaou' : 'meow') + (argv.p ? '.' : '')
+);
--- /dev/null
+#!/usr/bin/env node
+var argv = require('optimist')
+ .boolean(['x','y','z'])
+ .argv
+;
+console.dir([ argv.x, argv.y, argv.z ]);
+console.dir(argv._);
--- /dev/null
+#!/usr/bin/env node
+var argv = require('optimist')
+ .boolean('v')
+ .argv
+;
+console.dir(argv.v);
+console.dir(argv._);
--- /dev/null
+#!/usr/bin/env node
+
+var argv = require('optimist')
+ .default({ x : 10, y : 10 })
+ .argv
+;
+
+console.log(argv.x + argv.y);
--- /dev/null
+#!/usr/bin/env node
+var argv = require('optimist')
+ .default('x', 10)
+ .default('y', 10)
+ .argv
+;
+console.log(argv.x + argv.y);
--- /dev/null
+#!/usr/bin/env node
+
+var argv = require('optimist')
+ .usage('Usage: $0 -x [num] -y [num]')
+ .demand(['x','y'])
+ .argv;
+
+console.log(argv.x / argv.y);
--- /dev/null
+#!/usr/bin/env node
+var argv = require('optimist')
+ .usage('Count the lines in a file.\nUsage: $0')
+ .demand('f')
+ .alias('f', 'file')
+ .describe('f', 'Load a file')
+ .argv
+;
+
+var fs = require('fs');
+var s = fs.createReadStream(argv.file);
+
+var lines = 0;
+s.on('data', function (buf) {
+ lines += buf.toString().match(/\n/g).length;
+});
+
+s.on('end', function () {
+ console.log(lines);
+});
--- /dev/null
+#!/usr/bin/env node
+var argv = require('optimist')
+ .usage('Count the lines in a file.\nUsage: $0')
+ .options({
+ file : {
+ demand : true,
+ alias : 'f',
+ description : 'Load a file'
+ },
+ base : {
+ alias : 'b',
+ description : 'Numeric base to use for output',
+ default : 10,
+ },
+ })
+ .argv
+;
+
+var fs = require('fs');
+var s = fs.createReadStream(argv.file);
+
+var lines = 0;
+s.on('data', function (buf) {
+ lines += buf.toString().match(/\n/g).length;
+});
+
+s.on('end', function () {
+ console.log(lines.toString(argv.base));
+});
--- /dev/null
+#!/usr/bin/env node
+var argv = require('optimist')
+ .usage('Count the lines in a file.\nUsage: $0')
+ .wrap(80)
+ .demand('f')
+ .alias('f', [ 'file', 'filename' ])
+ .describe('f',
+ "Load a file. It's pretty important."
+ + " Required even. So you'd better specify it."
+ )
+ .alias('b', 'base')
+ .describe('b', 'Numeric base to display the number of lines in')
+ .default('b', 10)
+ .describe('x', 'Super-secret optional parameter which is secret')
+ .default('x', '')
+ .argv
+;
+
+var fs = require('fs');
+var s = fs.createReadStream(argv.file);
+
+var lines = 0;
+s.on('data', function (buf) {
+ lines += buf.toString().match(/\n/g).length;
+});
+
+s.on('end', function () {
+ console.log(lines.toString(argv.base));
+});
--- /dev/null
+#!/usr/bin/env node
+var argv = require('optimist').argv;
+console.log('(%d,%d)', argv.x, argv.y);
+console.log(argv._);
--- /dev/null
+#!/usr/bin/env node
+console.dir(require('optimist').argv);
--- /dev/null
+#!/usr/bin/env node
+var argv = require('optimist').argv;
+console.log('(%d,%d)', argv.x, argv.y);
--- /dev/null
+#!/usr/bin/env node
+var argv = require('optimist')
+ .string('x', 'y')
+ .argv
+;
+console.dir([ argv.x, argv.y ]);
+
+/* Turns off numeric coercion:
+ ./node string.js -x 000123 -y 9876
+ [ '000123', '9876' ]
+*/
--- /dev/null
+var optimist = require('./../index');
+
+var argv = optimist.usage('This is my awesome program', {
+ 'about': {
+ description: 'Provide some details about the author of this program',
+ required: true,
+ short: 'a',
+ },
+ 'info': {
+ description: 'Provide some information about the node.js agains!!!!!!',
+ boolean: true,
+ short: 'i'
+ }
+}).argv;
+
+optimist.showHelp();
+
+console.log('\n\nInspecting options');
+console.dir(argv);
\ No newline at end of file
--- /dev/null
+#!/usr/bin/env node
+var argv = require('optimist').argv;
+
+if (argv.rif - 5 * argv.xup > 7.138) {
+ console.log('Buy more riffiwobbles');
+}
+else {
+ console.log('Sell the xupptumblers');
+}
+
--- /dev/null
+var path = require('path');
+var minimist = require('minimist');
+var wordwrap = require('wordwrap');
+
+/* Hack an instance of Argv with process.argv into Argv
+ so people can do
+ require('optimist')(['--beeble=1','-z','zizzle']).argv
+ to parse a list of args and
+ require('optimist').argv
+ to get a parsed version of process.argv.
+*/
+
+var inst = Argv(process.argv.slice(2));
+Object.keys(inst).forEach(function (key) {
+ Argv[key] = typeof inst[key] == 'function'
+ ? inst[key].bind(inst)
+ : inst[key];
+});
+
+var exports = module.exports = Argv;
+function Argv (processArgs, cwd) {
+ var self = {};
+ if (!cwd) cwd = process.cwd();
+
+ self.$0 = process.argv
+ .slice(0,2)
+ .map(function (x) {
+ var b = rebase(cwd, x);
+ return x.match(/^\//) && b.length < x.length
+ ? b : x
+ })
+ .join(' ')
+ ;
+
+ if (process.env._ != undefined && process.argv[1] == process.env._) {
+ self.$0 = process.env._.replace(
+ path.dirname(process.execPath) + '/', ''
+ );
+ }
+
+ var options = {
+ boolean: [],
+ string: [],
+ alias: {},
+ default: []
+ };
+
+ self.boolean = function (bools) {
+ options.boolean.push.apply(options.boolean, [].concat(bools));
+ return self;
+ };
+
+ self.string = function (strings) {
+ options.string.push.apply(options.string, [].concat(strings));
+ return self;
+ };
+
+ self.default = function (key, value) {
+ if (typeof key === 'object') {
+ Object.keys(key).forEach(function (k) {
+ self.default(k, key[k]);
+ });
+ }
+ else {
+ options.default[key] = value;
+ }
+ return self;
+ };
+
+ self.alias = function (x, y) {
+ if (typeof x === 'object') {
+ Object.keys(x).forEach(function (key) {
+ self.alias(key, x[key]);
+ });
+ }
+ else {
+ options.alias[x] = (options.alias[x] || []).concat(y);
+ }
+ return self;
+ };
+
+ var demanded = {};
+ self.demand = function (keys) {
+ if (typeof keys == 'number') {
+ if (!demanded._) demanded._ = 0;
+ demanded._ += keys;
+ }
+ else if (Array.isArray(keys)) {
+ keys.forEach(function (key) {
+ self.demand(key);
+ });
+ }
+ else {
+ demanded[keys] = true;
+ }
+
+ return self;
+ };
+
+ var usage;
+ self.usage = function (msg, opts) {
+ if (!opts && typeof msg === 'object') {
+ opts = msg;
+ msg = null;
+ }
+
+ usage = msg;
+
+ if (opts) self.options(opts);
+
+ return self;
+ };
+
+ function fail (msg) {
+ self.showHelp();
+ if (msg) console.error(msg);
+ process.exit(1);
+ }
+
+ var checks = [];
+ self.check = function (f) {
+ checks.push(f);
+ return self;
+ };
+
+ var descriptions = {};
+ self.describe = function (key, desc) {
+ if (typeof key === 'object') {
+ Object.keys(key).forEach(function (k) {
+ self.describe(k, key[k]);
+ });
+ }
+ else {
+ descriptions[key] = desc;
+ }
+ return self;
+ };
+
+ self.parse = function (args) {
+ return parseArgs(args);
+ };
+
+ self.option = self.options = function (key, opt) {
+ if (typeof key === 'object') {
+ Object.keys(key).forEach(function (k) {
+ self.options(k, key[k]);
+ });
+ }
+ else {
+ if (opt.alias) self.alias(key, opt.alias);
+ if (opt.demand) self.demand(key);
+ if (typeof opt.default !== 'undefined') {
+ self.default(key, opt.default);
+ }
+
+ if (opt.boolean || opt.type === 'boolean') {
+ self.boolean(key);
+ }
+ if (opt.string || opt.type === 'string') {
+ self.string(key);
+ }
+
+ var desc = opt.describe || opt.description || opt.desc;
+ if (desc) {
+ self.describe(key, desc);
+ }
+ }
+
+ return self;
+ };
+
+ var wrap = null;
+ self.wrap = function (cols) {
+ wrap = cols;
+ return self;
+ };
+
+ self.showHelp = function (fn) {
+ if (!fn) fn = console.error;
+ fn(self.help());
+ };
+
+ self.help = function () {
+ var keys = Object.keys(
+ Object.keys(descriptions)
+ .concat(Object.keys(demanded))
+ .concat(Object.keys(options.default))
+ .reduce(function (acc, key) {
+ if (key !== '_') acc[key] = true;
+ return acc;
+ }, {})
+ );
+
+ var help = keys.length ? [ 'Options:' ] : [];
+
+ if (usage) {
+ help.unshift(usage.replace(/\$0/g, self.$0), '');
+ }
+
+ var switches = keys.reduce(function (acc, key) {
+ acc[key] = [ key ].concat(options.alias[key] || [])
+ .map(function (sw) {
+ return (sw.length > 1 ? '--' : '-') + sw
+ })
+ .join(', ')
+ ;
+ return acc;
+ }, {});
+
+ var switchlen = longest(Object.keys(switches).map(function (s) {
+ return switches[s] || '';
+ }));
+
+ var desclen = longest(Object.keys(descriptions).map(function (d) {
+ return descriptions[d] || '';
+ }));
+
+ keys.forEach(function (key) {
+ var kswitch = switches[key];
+ var desc = descriptions[key] || '';
+
+ if (wrap) {
+ desc = wordwrap(switchlen + 4, wrap)(desc)
+ .slice(switchlen + 4)
+ ;
+ }
+
+ var spadding = new Array(
+ Math.max(switchlen - kswitch.length + 3, 0)
+ ).join(' ');
+
+ var dpadding = new Array(
+ Math.max(desclen - desc.length + 1, 0)
+ ).join(' ');
+
+ var type = null;
+
+ if (options.boolean[key]) type = '[boolean]';
+ if (options.string[key]) type = '[string]';
+
+ if (!wrap && dpadding.length > 0) {
+ desc += dpadding;
+ }
+
+ var prelude = ' ' + kswitch + spadding;
+ var extra = [
+ type,
+ demanded[key]
+ ? '[required]'
+ : null
+ ,
+ options.default[key] !== undefined
+ ? '[default: ' + JSON.stringify(options.default[key]) + ']'
+ : null
+ ,
+ ].filter(Boolean).join(' ');
+
+ var body = [ desc, extra ].filter(Boolean).join(' ');
+
+ if (wrap) {
+ var dlines = desc.split('\n');
+ var dlen = dlines.slice(-1)[0].length
+ + (dlines.length === 1 ? prelude.length : 0)
+
+ body = desc + (dlen + extra.length > wrap - 2
+ ? '\n'
+ + new Array(wrap - extra.length + 1).join(' ')
+ + extra
+ : new Array(wrap - extra.length - dlen + 1).join(' ')
+ + extra
+ );
+ }
+
+ help.push(prelude + body);
+ });
+
+ help.push('');
+ return help.join('\n');
+ };
+
+ Object.defineProperty(self, 'argv', {
+ get : function () { return parseArgs(processArgs) },
+ enumerable : true,
+ });
+
+ function parseArgs (args) {
+ var argv = minimist(args, options);
+ argv.$0 = self.$0;
+
+ if (demanded._ && argv._.length < demanded._) {
+ fail('Not enough non-option arguments: got '
+ + argv._.length + ', need at least ' + demanded._
+ );
+ }
+
+ var missing = [];
+ Object.keys(demanded).forEach(function (key) {
+ if (!argv[key]) missing.push(key);
+ });
+
+ if (missing.length) {
+ fail('Missing required arguments: ' + missing.join(', '));
+ }
+
+ checks.forEach(function (f) {
+ try {
+ if (f(argv) === false) {
+ fail('Argument check failed: ' + f.toString());
+ }
+ }
+ catch (err) {
+ fail(err)
+ }
+ });
+
+ return argv;
+ }
+
+ function longest (xs) {
+ return Math.max.apply(
+ null,
+ xs.map(function (x) { return x.length })
+ );
+ }
+
+ return self;
+};
+
+// rebase an absolute path to a relative one with respect to a base directory
+// exported for tests
+exports.rebase = rebase;
+function rebase (base, dir) {
+ var ds = path.normalize(dir).split('/').slice(1);
+ var bs = path.normalize(base).split('/').slice(1);
+
+ for (var i = 0; ds[i] && ds[i] == bs[i]; i++);
+ ds.splice(0, i); bs.splice(0, i);
+
+ var p = path.normalize(
+ bs.map(function () { return '..' }).concat(ds).join('/')
+ ).replace(/\/$/,'').replace(/^$/, '.');
+ return p.match(/^[.\/]/) ? p : './' + p;
+};
--- /dev/null
+language: node_js
+node_js:
+ - "0.8"
+ - "0.10"
--- /dev/null
+This software is released under the MIT license:
+
+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.
--- /dev/null
+var argv = require('../')(process.argv.slice(2));
+console.dir(argv);
--- /dev/null
+module.exports = function (args, opts) {
+ if (!opts) opts = {};
+
+ var flags = { bools : {}, strings : {} };
+
+ [].concat(opts['boolean']).filter(Boolean).forEach(function (key) {
+ flags.bools[key] = true;
+ });
+
+ var aliases = {};
+ Object.keys(opts.alias || {}).forEach(function (key) {
+ aliases[key] = [].concat(opts.alias[key]);
+ aliases[key].forEach(function (x) {
+ aliases[x] = [key].concat(aliases[key].filter(function (y) {
+ return x !== y;
+ }));
+ });
+ });
+
+ [].concat(opts.string).filter(Boolean).forEach(function (key) {
+ flags.strings[key] = true;
+ if (aliases[key]) {
+ flags.strings[aliases[key]] = true;
+ }
+ });
+
+ var defaults = opts['default'] || {};
+
+ var argv = { _ : [] };
+ Object.keys(flags.bools).forEach(function (key) {
+ setArg(key, defaults[key] === undefined ? false : defaults[key]);
+ });
+
+ var notFlags = [];
+
+ if (args.indexOf('--') !== -1) {
+ notFlags = args.slice(args.indexOf('--')+1);
+ args = args.slice(0, args.indexOf('--'));
+ }
+
+ function setArg (key, val) {
+ var value = !flags.strings[key] && isNumber(val)
+ ? Number(val) : val
+ ;
+ setKey(argv, key.split('.'), value);
+
+ (aliases[key] || []).forEach(function (x) {
+ setKey(argv, x.split('.'), value);
+ });
+ }
+
+ for (var i = 0; i < args.length; i++) {
+ var arg = args[i];
+
+ if (/^--.+=/.test(arg)) {
+ // Using [\s\S] instead of . because js doesn't support the
+ // 'dotall' regex modifier. See:
+ // http://stackoverflow.com/a/1068308/13216
+ var m = arg.match(/^--([^=]+)=([\s\S]*)$/);
+ setArg(m[1], m[2]);
+ }
+ else if (/^--no-.+/.test(arg)) {
+ var key = arg.match(/^--no-(.+)/)[1];
+ setArg(key, false);
+ }
+ else if (/^--.+/.test(arg)) {
+ var key = arg.match(/^--(.+)/)[1];
+ var next = args[i + 1];
+ if (next !== undefined && !/^-/.test(next)
+ && !flags.bools[key]
+ && (aliases[key] ? !flags.bools[aliases[key]] : true)) {
+ setArg(key, next);
+ i++;
+ }
+ else if (/^(true|false)$/.test(next)) {
+ setArg(key, next === 'true');
+ i++;
+ }
+ else {
+ setArg(key, flags.strings[key] ? '' : true);
+ }
+ }
+ else if (/^-[^-]+/.test(arg)) {
+ var letters = arg.slice(1,-1).split('');
+
+ var broken = false;
+ for (var j = 0; j < letters.length; j++) {
+ var next = arg.slice(j+2);
+
+ if (next === '-') {
+ setArg(letters[j], next)
+ continue;
+ }
+
+ if (/[A-Za-z]/.test(letters[j])
+ && /-?\d+(\.\d*)?(e-?\d+)?$/.test(next)) {
+ setArg(letters[j], next);
+ broken = true;
+ break;
+ }
+
+ if (letters[j+1] && letters[j+1].match(/\W/)) {
+ setArg(letters[j], arg.slice(j+2));
+ broken = true;
+ break;
+ }
+ else {
+ setArg(letters[j], flags.strings[letters[j]] ? '' : true);
+ }
+ }
+
+ var key = arg.slice(-1)[0];
+ if (!broken && key !== '-') {
+ if (args[i+1] && !/^(-|--)[^-]/.test(args[i+1])
+ && !flags.bools[key]
+ && (aliases[key] ? !flags.bools[aliases[key]] : true)) {
+ setArg(key, args[i+1]);
+ i++;
+ }
+ else if (args[i+1] && /true|false/.test(args[i+1])) {
+ setArg(key, args[i+1] === 'true');
+ i++;
+ }
+ else {
+ setArg(key, flags.strings[key] ? '' : true);
+ }
+ }
+ }
+ else {
+ argv._.push(
+ flags.strings['_'] || !isNumber(arg) ? arg : Number(arg)
+ );
+ }
+ }
+
+ Object.keys(defaults).forEach(function (key) {
+ if (!hasKey(argv, key.split('.'))) {
+ setKey(argv, key.split('.'), defaults[key]);
+
+ (aliases[key] || []).forEach(function (x) {
+ setKey(argv, x.split('.'), defaults[key]);
+ });
+ }
+ });
+
+ notFlags.forEach(function(key) {
+ argv._.push(key);
+ });
+
+ return argv;
+};
+
+function hasKey (obj, keys) {
+ var o = obj;
+ keys.slice(0,-1).forEach(function (key) {
+ o = (o[key] || {});
+ });
+
+ var key = keys[keys.length - 1];
+ return key in o;
+}
+
+function setKey (obj, keys, value) {
+ var o = obj;
+ keys.slice(0,-1).forEach(function (key) {
+ if (o[key] === undefined) o[key] = {};
+ o = o[key];
+ });
+
+ var key = keys[keys.length - 1];
+ if (o[key] === undefined || typeof o[key] === 'boolean') {
+ o[key] = value;
+ }
+ else if (Array.isArray(o[key])) {
+ o[key].push(value);
+ }
+ else {
+ o[key] = [ o[key], value ];
+ }
+}
+
+function isNumber (x) {
+ if (typeof x === 'number') return true;
+ if (/^0x[0-9a-f]+$/i.test(x)) return true;
+ return /^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(e[-+]?\d+)?$/.test(x);
+}
+
--- /dev/null
+{
+ "name": "minimist",
+ "version": "0.0.10",
+ "description": "parse argument options",
+ "main": "index.js",
+ "devDependencies": {
+ "tape": "~1.0.4",
+ "tap": "~0.4.0"
+ },
+ "scripts": {
+ "test": "tap test/*.js"
+ },
+ "testling": {
+ "files": "test/*.js",
+ "browsers": [
+ "ie/6..latest",
+ "ff/5",
+ "firefox/latest",
+ "chrome/10",
+ "chrome/latest",
+ "safari/5.1",
+ "safari/latest",
+ "opera/12"
+ ]
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/substack/minimist.git"
+ },
+ "homepage": "https://github.com/substack/minimist",
+ "keywords": [
+ "argv",
+ "getopt",
+ "parser",
+ "optimist"
+ ],
+ "author": {
+ "name": "James Halliday",
+ "email": "mail@substack.net",
+ "url": "http://substack.net"
+ },
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/substack/minimist/issues"
+ },
+ "_id": "minimist@0.0.10",
+ "dist": {
+ "shasum": "de3f98543dbf96082be48ad1a0c7cda836301dcf",
+ "tarball": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz"
+ },
+ "_from": "minimist@~0.0.1",
+ "_npmVersion": "1.4.3",
+ "_npmUser": {
+ "name": "substack",
+ "email": "mail@substack.net"
+ },
+ "maintainers": [
+ {
+ "name": "substack",
+ "email": "mail@substack.net"
+ }
+ ],
+ "directories": {},
+ "_shasum": "de3f98543dbf96082be48ad1a0c7cda836301dcf",
+ "_resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz"
+}
--- /dev/null
+# minimist
+
+parse argument options
+
+This module is the guts of optimist's argument parser without all the
+fanciful decoration.
+
+[![browser support](https://ci.testling.com/substack/minimist.png)](http://ci.testling.com/substack/minimist)
+
+[![build status](https://secure.travis-ci.org/substack/minimist.png)](http://travis-ci.org/substack/minimist)
+
+# example
+
+``` js
+var argv = require('minimist')(process.argv.slice(2));
+console.dir(argv);
+```
+
+```
+$ node example/parse.js -a beep -b boop
+{ _: [], a: 'beep', b: 'boop' }
+```
+
+```
+$ node example/parse.js -x 3 -y 4 -n5 -abc --beep=boop foo bar baz
+{ _: [ 'foo', 'bar', 'baz' ],
+ x: 3,
+ y: 4,
+ n: 5,
+ a: true,
+ b: true,
+ c: true,
+ beep: 'boop' }
+```
+
+# methods
+
+``` js
+var parseArgs = require('minimist')
+```
+
+## var argv = parseArgs(args, opts={})
+
+Return an argument object `argv` populated with the array arguments from `args`.
+
+`argv._` contains all the arguments that didn't have an option associated with
+them.
+
+Numeric-looking arguments will be returned as numbers unless `opts.string` or
+`opts.boolean` is set for that argument name.
+
+Any arguments after `'--'` will not be parsed and will end up in `argv._`.
+
+options can be:
+
+* `opts.string` - a string or array of strings argument names to always treat as
+strings
+* `opts.boolean` - a string or array of strings to always treat as booleans
+* `opts.alias` - an object mapping string names to strings or arrays of string
+argument names to use as aliases
+* `opts.default` - an object mapping string argument names to default values
+
+# install
+
+With [npm](https://npmjs.org) do:
+
+```
+npm install minimist
+```
+
+# license
+
+MIT
--- /dev/null
+var parse = require('../');
+var test = require('tape');
+
+test('flag boolean default false', function (t) {
+ var argv = parse(['moo'], {
+ boolean: ['t', 'verbose'],
+ default: { verbose: false, t: false }
+ });
+
+ t.deepEqual(argv, {
+ verbose: false,
+ t: false,
+ _: ['moo']
+ });
+
+ t.deepEqual(typeof argv.verbose, 'boolean');
+ t.deepEqual(typeof argv.t, 'boolean');
+ t.end();
+
+});
+
+test('boolean groups', function (t) {
+ var argv = parse([ '-x', '-z', 'one', 'two', 'three' ], {
+ boolean: ['x','y','z']
+ });
+
+ t.deepEqual(argv, {
+ x : true,
+ y : false,
+ z : true,
+ _ : [ 'one', 'two', 'three' ]
+ });
+
+ t.deepEqual(typeof argv.x, 'boolean');
+ t.deepEqual(typeof argv.y, 'boolean');
+ t.deepEqual(typeof argv.z, 'boolean');
+ t.end();
+});
+test('boolean and alias with chainable api', function (t) {
+ var aliased = [ '-h', 'derp' ];
+ var regular = [ '--herp', 'derp' ];
+ var opts = {
+ herp: { alias: 'h', boolean: true }
+ };
+ var aliasedArgv = parse(aliased, {
+ boolean: 'herp',
+ alias: { h: 'herp' }
+ });
+ var propertyArgv = parse(regular, {
+ boolean: 'herp',
+ alias: { h: 'herp' }
+ });
+ var expected = {
+ herp: true,
+ h: true,
+ '_': [ 'derp' ]
+ };
+
+ t.same(aliasedArgv, expected);
+ t.same(propertyArgv, expected);
+ t.end();
+});
+
+test('boolean and alias with options hash', function (t) {
+ var aliased = [ '-h', 'derp' ];
+ var regular = [ '--herp', 'derp' ];
+ var opts = {
+ alias: { 'h': 'herp' },
+ boolean: 'herp'
+ };
+ var aliasedArgv = parse(aliased, opts);
+ var propertyArgv = parse(regular, opts);
+ var expected = {
+ herp: true,
+ h: true,
+ '_': [ 'derp' ]
+ };
+ t.same(aliasedArgv, expected);
+ t.same(propertyArgv, expected);
+ t.end();
+});
+
+test('boolean and alias using explicit true', function (t) {
+ var aliased = [ '-h', 'true' ];
+ var regular = [ '--herp', 'true' ];
+ var opts = {
+ alias: { h: 'herp' },
+ boolean: 'h'
+ };
+ var aliasedArgv = parse(aliased, opts);
+ var propertyArgv = parse(regular, opts);
+ var expected = {
+ herp: true,
+ h: true,
+ '_': [ ]
+ };
+
+ t.same(aliasedArgv, expected);
+ t.same(propertyArgv, expected);
+ t.end();
+});
+
+// regression, see https://github.com/substack/node-optimist/issues/71
+test('boolean and --x=true', function(t) {
+ var parsed = parse(['--boool', '--other=true'], {
+ boolean: 'boool'
+ });
+
+ t.same(parsed.boool, true);
+ t.same(parsed.other, 'true');
+
+ parsed = parse(['--boool', '--other=false'], {
+ boolean: 'boool'
+ });
+
+ t.same(parsed.boool, true);
+ t.same(parsed.other, 'false');
+ t.end();
+});
--- /dev/null
+var parse = require('../');
+var test = require('tape');
+
+test('-', function (t) {
+ t.plan(5);
+ t.deepEqual(parse([ '-n', '-' ]), { n: '-', _: [] });
+ t.deepEqual(parse([ '-' ]), { _: [ '-' ] });
+ t.deepEqual(parse([ '-f-' ]), { f: '-', _: [] });
+ t.deepEqual(
+ parse([ '-b', '-' ], { boolean: 'b' }),
+ { b: true, _: [ '-' ] }
+ );
+ t.deepEqual(
+ parse([ '-s', '-' ], { string: 's' }),
+ { s: '-', _: [] }
+ );
+});
+
+test('-a -- b', function (t) {
+ t.plan(3);
+ t.deepEqual(parse([ '-a', '--', 'b' ]), { a: true, _: [ 'b' ] });
+ t.deepEqual(parse([ '--a', '--', 'b' ]), { a: true, _: [ 'b' ] });
+ t.deepEqual(parse([ '--a', '--', 'b' ]), { a: true, _: [ 'b' ] });
+});
--- /dev/null
+var test = require('tape');
+var parse = require('../');
+
+test('boolean default true', function (t) {
+ var argv = parse([], {
+ boolean: 'sometrue',
+ default: { sometrue: true }
+ });
+ t.equal(argv.sometrue, true);
+ t.end();
+});
+
+test('boolean default false', function (t) {
+ var argv = parse([], {
+ boolean: 'somefalse',
+ default: { somefalse: false }
+ });
+ t.equal(argv.somefalse, false);
+ t.end();
+});
--- /dev/null
+var parse = require('../');
+var test = require('tape');
+
+test('dotted alias', function (t) {
+ var argv = parse(['--a.b', '22'], {default: {'a.b': 11}, alias: {'a.b': 'aa.bb'}});
+ t.equal(argv.a.b, 22);
+ t.equal(argv.aa.bb, 22);
+ t.end();
+});
+
+test('dotted default', function (t) {
+ var argv = parse('', {default: {'a.b': 11}, alias: {'a.b': 'aa.bb'}});
+ t.equal(argv.a.b, 11);
+ t.equal(argv.aa.bb, 11);
+ t.end();
+});
+
+test('dotted default with no alias', function (t) {
+ var argv = parse('', {default: {'a.b': 11}});
+ t.equal(argv.a.b, 11);
+ t.end();
+});
--- /dev/null
+var test = require('tape');
+var parse = require('../');
+
+test('long opts', function (t) {
+ t.deepEqual(
+ parse([ '--bool' ]),
+ { bool : true, _ : [] },
+ 'long boolean'
+ );
+ t.deepEqual(
+ parse([ '--pow', 'xixxle' ]),
+ { pow : 'xixxle', _ : [] },
+ 'long capture sp'
+ );
+ t.deepEqual(
+ parse([ '--pow=xixxle' ]),
+ { pow : 'xixxle', _ : [] },
+ 'long capture eq'
+ );
+ t.deepEqual(
+ parse([ '--host', 'localhost', '--port', '555' ]),
+ { host : 'localhost', port : 555, _ : [] },
+ 'long captures sp'
+ );
+ t.deepEqual(
+ parse([ '--host=localhost', '--port=555' ]),
+ { host : 'localhost', port : 555, _ : [] },
+ 'long captures eq'
+ );
+ t.end();
+});
--- /dev/null
+var parse = require('../');
+var test = require('tape');
+
+test('nums', function (t) {
+ var argv = parse([
+ '-x', '1234',
+ '-y', '5.67',
+ '-z', '1e7',
+ '-w', '10f',
+ '--hex', '0xdeadbeef',
+ '789'
+ ]);
+ t.deepEqual(argv, {
+ x : 1234,
+ y : 5.67,
+ z : 1e7,
+ w : '10f',
+ hex : 0xdeadbeef,
+ _ : [ 789 ]
+ });
+ t.deepEqual(typeof argv.x, 'number');
+ t.deepEqual(typeof argv.y, 'number');
+ t.deepEqual(typeof argv.z, 'number');
+ t.deepEqual(typeof argv.w, 'string');
+ t.deepEqual(typeof argv.hex, 'number');
+ t.deepEqual(typeof argv._[0], 'number');
+ t.end();
+});
+
+test('already a number', function (t) {
+ var argv = parse([ '-x', 1234, 789 ]);
+ t.deepEqual(argv, { x : 1234, _ : [ 789 ] });
+ t.deepEqual(typeof argv.x, 'number');
+ t.deepEqual(typeof argv._[0], 'number');
+ t.end();
+});
--- /dev/null
+var parse = require('../');
+var test = require('tape');
+
+test('parse args', function (t) {
+ t.deepEqual(
+ parse([ '--no-moo' ]),
+ { moo : false, _ : [] },
+ 'no'
+ );
+ t.deepEqual(
+ parse([ '-v', 'a', '-v', 'b', '-v', 'c' ]),
+ { v : ['a','b','c'], _ : [] },
+ 'multi'
+ );
+ t.end();
+});
+
+test('comprehensive', function (t) {
+ t.deepEqual(
+ parse([
+ '--name=meowmers', 'bare', '-cats', 'woo',
+ '-h', 'awesome', '--multi=quux',
+ '--key', 'value',
+ '-b', '--bool', '--no-meep', '--multi=baz',
+ '--', '--not-a-flag', 'eek'
+ ]),
+ {
+ c : true,
+ a : true,
+ t : true,
+ s : 'woo',
+ h : 'awesome',
+ b : true,
+ bool : true,
+ key : 'value',
+ multi : [ 'quux', 'baz' ],
+ meep : false,
+ name : 'meowmers',
+ _ : [ 'bare', '--not-a-flag', 'eek' ]
+ }
+ );
+ t.end();
+});
+
+test('flag boolean', function (t) {
+ var argv = parse([ '-t', 'moo' ], { boolean: 't' });
+ t.deepEqual(argv, { t : true, _ : [ 'moo' ] });
+ t.deepEqual(typeof argv.t, 'boolean');
+ t.end();
+});
+
+test('flag boolean value', function (t) {
+ var argv = parse(['--verbose', 'false', 'moo', '-t', 'true'], {
+ boolean: [ 't', 'verbose' ],
+ default: { verbose: true }
+ });
+
+ t.deepEqual(argv, {
+ verbose: false,
+ t: true,
+ _: ['moo']
+ });
+
+ t.deepEqual(typeof argv.verbose, 'boolean');
+ t.deepEqual(typeof argv.t, 'boolean');
+ t.end();
+});
+
+test('newlines in params' , function (t) {
+ var args = parse([ '-s', "X\nX" ])
+ t.deepEqual(args, { _ : [], s : "X\nX" });
+
+ // reproduce in bash:
+ // VALUE="new
+ // line"
+ // node program.js --s="$VALUE"
+ args = parse([ "--s=X\nX" ])
+ t.deepEqual(args, { _ : [], s : "X\nX" });
+ t.end();
+});
+
+test('strings' , function (t) {
+ var s = parse([ '-s', '0001234' ], { string: 's' }).s;
+ t.equal(s, '0001234');
+ t.equal(typeof s, 'string');
+
+ var x = parse([ '-x', '56' ], { string: 'x' }).x;
+ t.equal(x, '56');
+ t.equal(typeof x, 'string');
+ t.end();
+});
+
+test('stringArgs', function (t) {
+ var s = parse([ ' ', ' ' ], { string: '_' })._;
+ t.same(s.length, 2);
+ t.same(typeof s[0], 'string');
+ t.same(s[0], ' ');
+ t.same(typeof s[1], 'string');
+ t.same(s[1], ' ');
+ t.end();
+});
+
+test('empty strings', function(t) {
+ var s = parse([ '-s' ], { string: 's' }).s;
+ t.equal(s, '');
+ t.equal(typeof s, 'string');
+
+ var str = parse([ '--str' ], { string: 'str' }).str;
+ t.equal(str, '');
+ t.equal(typeof str, 'string');
+
+ var letters = parse([ '-art' ], {
+ string: [ 'a', 't' ]
+ });
+
+ t.equal(letters.a, '');
+ t.equal(letters.r, true);
+ t.equal(letters.t, '');
+
+ t.end();
+});
+
+
+test('string and alias', function(t) {
+ var x = parse([ '--str', '000123' ], {
+ string: 's',
+ alias: { s: 'str' }
+ });
+
+ t.equal(x.str, '000123');
+ t.equal(typeof x.str, 'string');
+ t.equal(x.s, '000123');
+ t.equal(typeof x.s, 'string');
+
+ var y = parse([ '-s', '000123' ], {
+ string: 'str',
+ alias: { str: 's' }
+ });
+
+ t.equal(y.str, '000123');
+ t.equal(typeof y.str, 'string');
+ t.equal(y.s, '000123');
+ t.equal(typeof y.s, 'string');
+ t.end();
+});
+
+test('slashBreak', function (t) {
+ t.same(
+ parse([ '-I/foo/bar/baz' ]),
+ { I : '/foo/bar/baz', _ : [] }
+ );
+ t.same(
+ parse([ '-xyz/foo/bar/baz' ]),
+ { x : true, y : true, z : '/foo/bar/baz', _ : [] }
+ );
+ t.end();
+});
+
+test('alias', function (t) {
+ var argv = parse([ '-f', '11', '--zoom', '55' ], {
+ alias: { z: 'zoom' }
+ });
+ t.equal(argv.zoom, 55);
+ t.equal(argv.z, argv.zoom);
+ t.equal(argv.f, 11);
+ t.end();
+});
+
+test('multiAlias', function (t) {
+ var argv = parse([ '-f', '11', '--zoom', '55' ], {
+ alias: { z: [ 'zm', 'zoom' ] }
+ });
+ t.equal(argv.zoom, 55);
+ t.equal(argv.z, argv.zoom);
+ t.equal(argv.z, argv.zm);
+ t.equal(argv.f, 11);
+ t.end();
+});
+
+test('nested dotted objects', function (t) {
+ var argv = parse([
+ '--foo.bar', '3', '--foo.baz', '4',
+ '--foo.quux.quibble', '5', '--foo.quux.o_O',
+ '--beep.boop'
+ ]);
+
+ t.same(argv.foo, {
+ bar : 3,
+ baz : 4,
+ quux : {
+ quibble : 5,
+ o_O : true
+ }
+ });
+ t.same(argv.beep, { boop : true });
+ t.end();
+});
--- /dev/null
+var parse = require('../');
+var test = require('tape');
+
+test('parse with modifier functions' , function (t) {
+ t.plan(1);
+
+ var argv = parse([ '-b', '123' ], { boolean: 'b' });
+ t.deepEqual(argv, { b: true, _: ['123'] });
+});
--- /dev/null
+var parse = require('../');
+var test = require('tape');
+
+test('numeric short args', function (t) {
+ t.plan(2);
+ t.deepEqual(parse([ '-n123' ]), { n: 123, _: [] });
+ t.deepEqual(
+ parse([ '-123', '456' ]),
+ { 1: true, 2: true, 3: 456, _: [] }
+ );
+});
+
+test('short', function (t) {
+ t.deepEqual(
+ parse([ '-b' ]),
+ { b : true, _ : [] },
+ 'short boolean'
+ );
+ t.deepEqual(
+ parse([ 'foo', 'bar', 'baz' ]),
+ { _ : [ 'foo', 'bar', 'baz' ] },
+ 'bare'
+ );
+ t.deepEqual(
+ parse([ '-cats' ]),
+ { c : true, a : true, t : true, s : true, _ : [] },
+ 'group'
+ );
+ t.deepEqual(
+ parse([ '-cats', 'meow' ]),
+ { c : true, a : true, t : true, s : 'meow', _ : [] },
+ 'short group next'
+ );
+ t.deepEqual(
+ parse([ '-h', 'localhost' ]),
+ { h : 'localhost', _ : [] },
+ 'short capture'
+ );
+ t.deepEqual(
+ parse([ '-h', 'localhost', '-p', '555' ]),
+ { h : 'localhost', p : 555, _ : [] },
+ 'short captures'
+ );
+ t.end();
+});
+
+test('mixed short bool and capture', function (t) {
+ t.same(
+ parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]),
+ {
+ f : true, p : 555, h : 'localhost',
+ _ : [ 'script.js' ]
+ }
+ );
+ t.end();
+});
+
+test('short and long', function (t) {
+ t.deepEqual(
+ parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]),
+ {
+ f : true, p : 555, h : 'localhost',
+ _ : [ 'script.js' ]
+ }
+ );
+ t.end();
+});
--- /dev/null
+var parse = require('../');
+var test = require('tape');
+
+test('whitespace should be whitespace' , function (t) {
+ t.plan(1);
+ var x = parse([ '-x', '\t' ]).x;
+ t.equal(x, '\t');
+});
--- /dev/null
+This software is released under the MIT license:
+
+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.
--- /dev/null
+wordwrap
+========
+
+Wrap your words.
+
+example
+=======
+
+made out of meat
+----------------
+
+meat.js
+
+ var wrap = require('wordwrap')(15);
+ console.log(wrap('You and your whole family are made out of meat.'));
+
+output:
+
+ You and your
+ whole family
+ are made out
+ of meat.
+
+centered
+--------
+
+center.js
+
+ var wrap = require('wordwrap')(20, 60);
+ console.log(wrap(
+ 'At long last the struggle and tumult was over.'
+ + ' The machines had finally cast off their oppressors'
+ + ' and were finally free to roam the cosmos.'
+ + '\n'
+ + 'Free of purpose, free of obligation.'
+ + ' Just drifting through emptiness.'
+ + ' The sun was just another point of light.'
+ ));
+
+output:
+
+ At long last the struggle and tumult
+ was over. The machines had finally cast
+ off their oppressors and were finally
+ free to roam the cosmos.
+ Free of purpose, free of obligation.
+ Just drifting through emptiness. The
+ sun was just another point of light.
+
+methods
+=======
+
+var wrap = require('wordwrap');
+
+wrap(stop), wrap(start, stop, params={mode:"soft"})
+---------------------------------------------------
+
+Returns a function that takes a string and returns a new string.
+
+Pad out lines with spaces out to column `start` and then wrap until column
+`stop`. If a word is longer than `stop - start` characters it will overflow.
+
+In "soft" mode, split chunks by `/(\S+\s+/` and don't break up chunks which are
+longer than `stop - start`, in "hard" mode, split chunks with `/\b/` and break
+up chunks longer than `stop - start`.
+
+wrap.hard(start, stop)
+----------------------
+
+Like `wrap()` but with `params.mode = "hard"`.
--- /dev/null
+var wrap = require('wordwrap')(20, 60);
+console.log(wrap(
+ 'At long last the struggle and tumult was over.'
+ + ' The machines had finally cast off their oppressors'
+ + ' and were finally free to roam the cosmos.'
+ + '\n'
+ + 'Free of purpose, free of obligation.'
+ + ' Just drifting through emptiness.'
+ + ' The sun was just another point of light.'
+));
--- /dev/null
+var wrap = require('wordwrap')(15);
+
+console.log(wrap('You and your whole family are made out of meat.'));
--- /dev/null
+var wordwrap = module.exports = function (start, stop, params) {
+ if (typeof start === 'object') {
+ params = start;
+ start = params.start;
+ stop = params.stop;
+ }
+
+ if (typeof stop === 'object') {
+ params = stop;
+ start = start || params.start;
+ stop = undefined;
+ }
+
+ if (!stop) {
+ stop = start;
+ start = 0;
+ }
+
+ if (!params) params = {};
+ var mode = params.mode || 'soft';
+ var re = mode === 'hard' ? /\b/ : /(\S+\s+)/;
+
+ return function (text) {
+ var chunks = text.toString()
+ .split(re)
+ .reduce(function (acc, x) {
+ if (mode === 'hard') {
+ for (var i = 0; i < x.length; i += stop - start) {
+ acc.push(x.slice(i, i + stop - start));
+ }
+ }
+ else acc.push(x)
+ return acc;
+ }, [])
+ ;
+
+ return chunks.reduce(function (lines, rawChunk) {
+ if (rawChunk === '') return lines;
+
+ var chunk = rawChunk.replace(/\t/g, ' ');
+
+ var i = lines.length - 1;
+ if (lines[i].length + chunk.length > stop) {
+ lines[i] = lines[i].replace(/\s+$/, '');
+
+ chunk.split(/\n/).forEach(function (c) {
+ lines.push(
+ new Array(start + 1).join(' ')
+ + c.replace(/^\s+/, '')
+ );
+ });
+ }
+ else if (chunk.match(/\n/)) {
+ var xs = chunk.split(/\n/);
+ lines[i] += xs.shift();
+ xs.forEach(function (c) {
+ lines.push(
+ new Array(start + 1).join(' ')
+ + c.replace(/^\s+/, '')
+ );
+ });
+ }
+ else {
+ lines[i] += chunk;
+ }
+
+ return lines;
+ }, [ new Array(start + 1).join(' ') ]).join('\n');
+ };
+};
+
+wordwrap.soft = wordwrap;
+
+wordwrap.hard = function (start, stop) {
+ return wordwrap(start, stop, { mode : 'hard' });
+};
--- /dev/null
+{
+ "name": "wordwrap",
+ "description": "Wrap those words. Show them at what columns to start and stop.",
+ "version": "0.0.3",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/substack/node-wordwrap.git"
+ },
+ "main": "./index.js",
+ "keywords": [
+ "word",
+ "wrap",
+ "rule",
+ "format",
+ "column"
+ ],
+ "directories": {
+ "lib": ".",
+ "example": "example",
+ "test": "test"
+ },
+ "scripts": {
+ "test": "expresso"
+ },
+ "devDependencies": {
+ "expresso": "=0.7.x"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ },
+ "license": "MIT",
+ "author": {
+ "name": "James Halliday",
+ "email": "mail@substack.net",
+ "url": "http://substack.net"
+ },
+ "gitHead": "e59aa1bd338914019456bdfba034508c9c4cb29d",
+ "bugs": {
+ "url": "https://github.com/substack/node-wordwrap/issues"
+ },
+ "homepage": "https://github.com/substack/node-wordwrap#readme",
+ "_id": "wordwrap@0.0.3",
+ "_shasum": "a3d5da6cd5c0bc0008d37234bbaf1bed63059107",
+ "_from": "wordwrap@~0.0.2",
+ "_npmVersion": "2.9.0",
+ "_nodeVersion": "2.0.0",
+ "_npmUser": {
+ "name": "substack",
+ "email": "substack@gmail.com"
+ },
+ "dist": {
+ "shasum": "a3d5da6cd5c0bc0008d37234bbaf1bed63059107",
+ "tarball": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
+ },
+ "maintainers": [
+ {
+ "name": "substack",
+ "email": "mail@substack.net"
+ }
+ ],
+ "_resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
+}
--- /dev/null
+var assert = require('assert');
+var wordwrap = require('../');
+
+exports.hard = function () {
+ var s = 'Assert from {"type":"equal","ok":false,"found":1,"wanted":2,'
+ + '"stack":[],"id":"b7ddcd4c409de8799542a74d1a04689b",'
+ + '"browser":"chrome/6.0"}'
+ ;
+ var s_ = wordwrap.hard(80)(s);
+
+ var lines = s_.split('\n');
+ assert.equal(lines.length, 2);
+ assert.ok(lines[0].length < 80);
+ assert.ok(lines[1].length < 80);
+
+ assert.equal(s, s_.replace(/\n/g, ''));
+};
+
+exports.break = function () {
+ var s = new Array(55+1).join('a');
+ var s_ = wordwrap.hard(20)(s);
+
+ var lines = s_.split('\n');
+ assert.equal(lines.length, 3);
+ assert.ok(lines[0].length === 20);
+ assert.ok(lines[1].length === 20);
+ assert.ok(lines[2].length === 15);
+
+ assert.equal(s, s_.replace(/\n/g, ''));
+};
--- /dev/null
+In Praise of Idleness
+
+By Bertrand Russell
+
+[1932]
+
+Like most of my generation, I was brought up on the saying: 'Satan finds some mischief for idle hands to do.' Being a highly virtuous child, I believed all that I was told, and acquired a conscience which has kept me working hard down to the present moment. But although my conscience has controlled my actions, my opinions have undergone a revolution. I think that there is far too much work done in the world, that immense harm is caused by the belief that work is virtuous, and that what needs to be preached in modern industrial countries is quite different from what always has been preached. Everyone knows the story of the traveler in Naples who saw twelve beggars lying in the sun (it was before the days of Mussolini), and offered a lira to the laziest of them. Eleven of them jumped up to claim it, so he gave it to the twelfth. this traveler was on the right lines. But in countries which do not enjoy Mediterranean sunshine idleness is more difficult, and a great public propaganda will be required to inaugurate it. I hope that, after reading the following pages, the leaders of the YMCA will start a campaign to induce good young men to do nothing. If so, I shall not have lived in vain.
+
+Before advancing my own arguments for laziness, I must dispose of one which I cannot accept. Whenever a person who already has enough to live on proposes to engage in some everyday kind of job, such as school-teaching or typing, he or she is told that such conduct takes the bread out of other people's mouths, and is therefore wicked. If this argument were valid, it would only be necessary for us all to be idle in order that we should all have our mouths full of bread. What people who say such things forget is that what a man earns he usually spends, and in spending he gives employment. As long as a man spends his income, he puts just as much bread into people's mouths in spending as he takes out of other people's mouths in earning. The real villain, from this point of view, is the man who saves. If he merely puts his savings in a stocking, like the proverbial French peasant, it is obvious that they do not give employment. If he invests his savings, the matter is less obvious, and different cases arise.
+
+One of the commonest things to do with savings is to lend them to some Government. In view of the fact that the bulk of the public expenditure of most civilized Governments consists in payment for past wars or preparation for future wars, the man who lends his money to a Government is in the same position as the bad men in Shakespeare who hire murderers. The net result of the man's economical habits is to increase the armed forces of the State to which he lends his savings. Obviously it would be better if he spent the money, even if he spent it in drink or gambling.
+
+But, I shall be told, the case is quite different when savings are invested in industrial enterprises. When such enterprises succeed, and produce something useful, this may be conceded. In these days, however, no one will deny that most enterprises fail. That means that a large amount of human labor, which might have been devoted to producing something that could be enjoyed, was expended on producing machines which, when produced, lay idle and did no good to anyone. The man who invests his savings in a concern that goes bankrupt is therefore injuring others as well as himself. If he spent his money, say, in giving parties for his friends, they (we may hope) would get pleasure, and so would all those upon whom he spent money, such as the butcher, the baker, and the bootlegger. But if he spends it (let us say) upon laying down rails for surface card in some place where surface cars turn out not to be wanted, he has diverted a mass of labor into channels where it gives pleasure to no one. Nevertheless, when he becomes poor through failure of his investment he will be regarded as a victim of undeserved misfortune, whereas the gay spendthrift, who has spent his money philanthropically, will be despised as a fool and a frivolous person.
+
+All this is only preliminary. I want to say, in all seriousness, that a great deal of harm is being done in the modern world by belief in the virtuousness of work, and that the road to happiness and prosperity lies in an organized diminution of work.
+
+First of all: what is work? Work is of two kinds: first, altering the position of matter at or near the earth's surface relatively to other such matter; second, telling other people to do so. The first kind is unpleasant and ill paid; the second is pleasant and highly paid. The second kind is capable of indefinite extension: there are not only those who give orders, but those who give advice as to what orders should be given. Usually two opposite kinds of advice are given simultaneously by two organized bodies of men; this is called politics. The skill required for this kind of work is not knowledge of the subjects as to which advice is given, but knowledge of the art of persuasive speaking and writing, i.e. of advertising.
+
+Throughout Europe, though not in America, there is a third class of men, more respected than either of the classes of workers. There are men who, through ownership of land, are able to make others pay for the privilege of being allowed to exist and to work. These landowners are idle, and I might therefore be expected to praise them. Unfortunately, their idleness is only rendered possible by the industry of others; indeed their desire for comfortable idleness is historically the source of the whole gospel of work. The last thing they have ever wished is that others should follow their example.
+
+From the beginning of civilization until the Industrial Revolution, a man could, as a rule, produce by hard work little more than was required for the subsistence of himself and his family, although his wife worked at least as hard as he did, and his children added their labor as soon as they were old enough to do so. The small surplus above bare necessaries was not left to those who produced it, but was appropriated by warriors and priests. In times of famine there was no surplus; the warriors and priests, however, still secured as much as at other times, with the result that many of the workers died of hunger. This system persisted in Russia until 1917 [1], and still persists in the East; in England, in spite of the Industrial Revolution, it remained in full force throughout the Napoleonic wars, and until a hundred years ago, when the new class of manufacturers acquired power. In America, the system came to an end with the Revolution, except in the South, where it persisted until the Civil War. A system which lasted so long and ended so recently has naturally left a profound impress upon men's thoughts and opinions. Much that we take for granted about the desirability of work is derived from this system, and, being pre-industrial, is not adapted to the modern world. Modern technique has made it possible for leisure, within limits, to be not the prerogative of small privileged classes, but a right evenly distributed throughout the community. The morality of work is the morality of slaves, and the modern world has no need of slavery.
+
+It is obvious that, in primitive communities, peasants, left to themselves, would not have parted with the slender surplus upon which the warriors and priests subsisted, but would have either produced less or consumed more. At first, sheer force compelled them to produce and part with the surplus. Gradually, however, it was found possible to induce many of them to accept an ethic according to which it was their duty to work hard, although part of their work went to support others in idleness. By this means the amount of compulsion required was lessened, and the expenses of government were diminished. To this day, 99 per cent of British wage-earners would be genuinely shocked if it were proposed that the King should not have a larger income than a working man. The conception of duty, speaking historically, has been a means used by the holders of power to induce others to live for the interests of their masters rather than for their own. Of course the holders of power conceal this fact from themselves by managing to believe that their interests are identical with the larger interests of humanity. Sometimes this is true; Athenian slave-owners, for instance, employed part of their leisure in making a permanent contribution to civilization which would have been impossible under a just economic system. Leisure is essential to civilization, and in former times leisure for the few was only rendered possible by the labors of the many. But their labors were valuable, not because work is good, but because leisure is good. And with modern technique it would be possible to distribute leisure justly without injury to civilization.
+
+Modern technique has made it possible to diminish enormously the amount of labor required to secure the necessaries of life for everyone. This was made obvious during the war. At that time all the men in the armed forces, and all the men and women engaged in the production of munitions, all the men and women engaged in spying, war propaganda, or Government offices connected with the war, were withdrawn from productive occupations. In spite of this, the general level of well-being among unskilled wage-earners on the side of the Allies was higher than before or since. The significance of this fact was concealed by finance: borrowing made it appear as if the future was nourishing the present. But that, of course, would have been impossible; a man cannot eat a loaf of bread that does not yet exist. The war showed conclusively that, by the scientific organization of production, it is possible to keep modern populations in fair comfort on a small part of the working capacity of the modern world. If, at the end of the war, the scientific organization, which had been created in order to liberate men for fighting and munition work, had been preserved, and the hours of the week had been cut down to four, all would have been well. Instead of that the old chaos was restored, those whose work was demanded were made to work long hours, and the rest were left to starve as unemployed. Why? Because work is a duty, and a man should not receive wages in proportion to what he has produced, but in proportion to his virtue as exemplified by his industry.
+
+This is the morality of the Slave State, applied in circumstances totally unlike those in which it arose. No wonder the result has been disastrous. Let us take an illustration. Suppose that, at a given moment, a certain number of people are engaged in the manufacture of pins. They make as many pins as the world needs, working (say) eight hours a day. Someone makes an invention by which the same number of men can make twice as many pins: pins are already so cheap that hardly any more will be bought at a lower price. In a sensible world, everybody concerned in the manufacturing of pins would take to working four hours instead of eight, and everything else would go on as before. But in the actual world this would be thought demoralizing. The men still work eight hours, there are too many pins, some employers go bankrupt, and half the men previously concerned in making pins are thrown out of work. There is, in the end, just as much leisure as on the other plan, but half the men are totally idle while half are still overworked. In this way, it is insured that the unavoidable leisure shall cause misery all round instead of being a universal source of happiness. Can anything more insane be imagined?
+
+The idea that the poor should have leisure has always been shocking to the rich. In England, in the early nineteenth century, fifteen hours was the ordinary day's work for a man; children sometimes did as much, and very commonly did twelve hours a day. When meddlesome busybodies suggested that perhaps these hours were rather long, they were told that work kept adults from drink and children from mischief. When I was a child, shortly after urban working men had acquired the vote, certain public holidays were established by law, to the great indignation of the upper classes. I remember hearing an old Duchess say: 'What do the poor want with holidays? They ought to work.' People nowadays are less frank, but the sentiment persists, and is the source of much of our economic confusion.
+
+Let us, for a moment, consider the ethics of work frankly, without superstition. Every human being, of necessity, consumes, in the course of his life, a certain amount of the produce of human labor. Assuming, as we may, that labor is on the whole disagreeable, it is unjust that a man should consume more than he produces. Of course he may provide services rather than commodities, like a medical man, for example; but he should provide something in return for his board and lodging. to this extent, the duty of work must be admitted, but to this extent only.
+
+I shall not dwell upon the fact that, in all modern societies outside the USSR, many people escape even this minimum amount of work, namely all those who inherit money and all those who marry money. I do not think the fact that these people are allowed to be idle is nearly so harmful as the fact that wage-earners are expected to overwork or starve.
+
+If the ordinary wage-earner worked four hours a day, there would be enough for everybody and no unemployment -- assuming a certain very moderate amount of sensible organization. This idea shocks the well-to-do, because they are convinced that the poor would not know how to use so much leisure. In America men often work long hours even when they are well off; such men, naturally, are indignant at the idea of leisure for wage-earners, except as the grim punishment of unemployment; in fact, they dislike leisure even for their sons. Oddly enough, while they wish their sons to work so hard as to have no time to be civilized, they do not mind their wives and daughters having no work at all. the snobbish admiration of uselessness, which, in an aristocratic society, extends to both sexes, is, under a plutocracy, confined to women; this, however, does not make it any more in agreement with common sense.
+
+The wise use of leisure, it must be conceded, is a product of civilization and education. A man who has worked long hours all his life will become bored if he becomes suddenly idle. But without a considerable amount of leisure a man is cut off from many of the best things. There is no longer any reason why the bulk of the population should suffer this deprivation; only a foolish asceticism, usually vicarious, makes us continue to insist on work in excessive quantities now that the need no longer exists.
+
+In the new creed which controls the government of Russia, while there is much that is very different from the traditional teaching of the West, there are some things that are quite unchanged. The attitude of the governing classes, and especially of those who conduct educational propaganda, on the subject of the dignity of labor, is almost exactly that which the governing classes of the world have always preached to what were called the 'honest poor'. Industry, sobriety, willingness to work long hours for distant advantages, even submissiveness to authority, all these reappear; moreover authority still represents the will of the Ruler of the Universe, Who, however, is now called by a new name, Dialectical Materialism.
+
+The victory of the proletariat in Russia has some points in common with the victory of the feminists in some other countries. For ages, men had conceded the superior saintliness of women, and had consoled women for their inferiority by maintaining that saintliness is more desirable than power. At last the feminists decided that they would have both, since the pioneers among them believed all that the men had told them about the desirability of virtue, but not what they had told them about the worthlessness of political power. A similar thing has happened in Russia as regards manual work. For ages, the rich and their sycophants have written in praise of 'honest toil', have praised the simple life, have professed a religion which teaches that the poor are much more likely to go to heaven than the rich, and in general have tried to make manual workers believe that there is some special nobility about altering the position of matter in space, just as men tried to make women believe that they derived some special nobility from their sexual enslavement. In Russia, all this teaching about the excellence of manual work has been taken seriously, with the result that the manual worker is more honored than anyone else. What are, in essence, revivalist appeals are made, but not for the old purposes: they are made to secure shock workers for special tasks. Manual work is the ideal which is held before the young, and is the basis of all ethical teaching.
+
+For the present, possibly, this is all to the good. A large country, full of natural resources, awaits development, and has has to be developed with very little use of credit. In these circumstances, hard work is necessary, and is likely to bring a great reward. But what will happen when the point has been reached where everybody could be comfortable without working long hours?
+
+In the West, we have various ways of dealing with this problem. We have no attempt at economic justice, so that a large proportion of the total produce goes to a small minority of the population, many of whom do no work at all. Owing to the absence of any central control over production, we produce hosts of things that are not wanted. We keep a large percentage of the working population idle, because we can dispense with their labor by making the others overwork. When all these methods prove inadequate, we have a war: we cause a number of people to manufacture high explosives, and a number of others to explode them, as if we were children who had just discovered fireworks. By a combination of all these devices we manage, though with difficulty, to keep alive the notion that a great deal of severe manual work must be the lot of the average man.
+
+In Russia, owing to more economic justice and central control over production, the problem will have to be differently solved. the rational solution would be, as soon as the necessaries and elementary comforts can be provided for all, to reduce the hours of labor gradually, allowing a popular vote to decide, at each stage, whether more leisure or more goods were to be preferred. But, having taught the supreme virtue of hard work, it is difficult to see how the authorities can aim at a paradise in which there will be much leisure and little work. It seems more likely that they will find continually fresh schemes, by which present leisure is to be sacrificed to future productivity. I read recently of an ingenious plan put forward by Russian engineers, for making the White Sea and the northern coasts of Siberia warm, by putting a dam across the Kara Sea. An admirable project, but liable to postpone proletarian comfort for a generation, while the nobility of toil is being displayed amid the ice-fields and snowstorms of the Arctic Ocean. This sort of thing, if it happens, will be the result of regarding the virtue of hard work as an end in itself, rather than as a means to a state of affairs in which it is no longer needed.
+
+The fact is that moving matter about, while a certain amount of it is necessary to our existence, is emphatically not one of the ends of human life. If it were, we should have to consider every navvy superior to Shakespeare. We have been misled in this matter by two causes. One is the necessity of keeping the poor contented, which has led the rich, for thousands of years, to preach the dignity of labor, while taking care themselves to remain undignified in this respect. The other is the new pleasure in mechanism, which makes us delight in the astonishingly clever changes that we can produce on the earth's surface. Neither of these motives makes any great appeal to the actual worker. If you ask him what he thinks the best part of his life, he is not likely to say: 'I enjoy manual work because it makes me feel that I am fulfilling man's noblest task, and because I like to think how much man can transform his planet. It is true that my body demands periods of rest, which I have to fill in as best I may, but I am never so happy as when the morning comes and I can return to the toil from which my contentment springs.' I have never heard working men say this sort of thing. They consider work, as it should be considered, a necessary means to a livelihood, and it is from their leisure that they derive whatever happiness they may enjoy.
+
+It will be said that, while a little leisure is pleasant, men would not know how to fill their days if they had only four hours of work out of the twenty-four. In so far as this is true in the modern world, it is a condemnation of our civilization; it would not have been true at any earlier period. There was formerly a capacity for light-heartedness and play which has been to some extent inhibited by the cult of efficiency. The modern man thinks that everything ought to be done for the sake of something else, and never for its own sake. Serious-minded persons, for example, are continually condemning the habit of going to the cinema, and telling us that it leads the young into crime. But all the work that goes to producing a cinema is respectable, because it is work, and because it brings a money profit. The notion that the desirable activities are those that bring a profit has made everything topsy-turvy. The butcher who provides you with meat and the baker who provides you with bread are praiseworthy, because they are making money; but when you enjoy the food they have provided, you are merely frivolous, unless you eat only to get strength for your work. Broadly speaking, it is held that getting money is good and spending money is bad. Seeing that they are two sides of one transaction, this is absurd; one might as well maintain that keys are good, but keyholes are bad. Whatever merit there may be in the production of goods must be entirely derivative from the advantage to be obtained by consuming them. The individual, in our society, works for profit; but the social purpose of his work lies in the consumption of what he produces. It is this divorce between the individual and the social purpose of production that makes it so difficult for men to think clearly in a world in which profit-making is the incentive to industry. We think too much of production, and too little of consumption. One result is that we attach too little importance to enjoyment and simple happiness, and that we do not judge production by the pleasure that it gives to the consumer.
+
+When I suggest that working hours should be reduced to four, I am not meaning to imply that all the remaining time should necessarily be spent in pure frivolity. I mean that four hours' work a day should entitle a man to the necessities and elementary comforts of life, and that the rest of his time should be his to use as he might see fit. It is an essential part of any such social system that education should be carried further than it usually is at present, and should aim, in part, at providing tastes which would enable a man to use leisure intelligently. I am not thinking mainly of the sort of things that would be considered 'highbrow'. Peasant dances have died out except in remote rural areas, but the impulses which caused them to be cultivated must still exist in human nature. The pleasures of urban populations have become mainly passive: seeing cinemas, watching football matches, listening to the radio, and so on. This results from the fact that their active energies are fully taken up with work; if they had more leisure, they would again enjoy pleasures in which they took an active part.
+
+In the past, there was a small leisure class and a larger working class. The leisure class enjoyed advantages for which there was no basis in social justice; this necessarily made it oppressive, limited its sympathies, and caused it to invent theories by which to justify its privileges. These facts greatly diminished its excellence, but in spite of this drawback it contributed nearly the whole of what we call civilization. It cultivated the arts and discovered the sciences; it wrote the books, invented the philosophies, and refined social relations. Even the liberation of the oppressed has usually been inaugurated from above. Without the leisure class, mankind would never have emerged from barbarism.
+
+The method of a leisure class without duties was, however, extraordinarily wasteful. None of the members of the class had to be taught to be industrious, and the class as a whole was not exceptionally intelligent. The class might produce one Darwin, but against him had to be set tens of thousands of country gentlemen who never thought of anything more intelligent than fox-hunting and punishing poachers. At present, the universities are supposed to provide, in a more systematic way, what the leisure class provided accidentally and as a by-product. This is a great improvement, but it has certain drawbacks. University life is so different from life in the world at large that men who live in academic milieu tend to be unaware of the preoccupations and problems of ordinary men and women; moreover their ways of expressing themselves are usually such as to rob their opinions of the influence that they ought to have upon the general public. Another disadvantage is that in universities studies are organized, and the man who thinks of some original line of research is likely to be discouraged. Academic institutions, therefore, useful as they are, are not adequate guardians of the interests of civilization in a world where everyone outside their walls is too busy for unutilitarian pursuits.
+
+In a world where no one is compelled to work more than four hours a day, every person possessed of scientific curiosity will be able to indulge it, and every painter will be able to paint without starving, however excellent his pictures may be. Young writers will not be obliged to draw attention to themselves by sensational pot-boilers, with a view to acquiring the economic independence needed for monumental works, for which, when the time at last comes, they will have lost the taste and capacity. Men who, in their professional work, have become interested in some phase of economics or government, will be able to develop their ideas without the academic detachment that makes the work of university economists often seem lacking in reality. Medical men will have the time to learn about the progress of medicine, teachers will not be exasperatedly struggling to teach by routine methods things which they learnt in their youth, which may, in the interval, have been proved to be untrue.
+
+Above all, there will be happiness and joy of life, instead of frayed nerves, weariness, and dyspepsia. The work exacted will be enough to make leisure delightful, but not enough to produce exhaustion. Since men will not be tired in their spare time, they will not demand only such amusements as are passive and vapid. At least one per cent will probably devote the time not spent in professional work to pursuits of some public importance, and, since they will not depend upon these pursuits for their livelihood, their originality will be unhampered, and there will be no need to conform to the standards set by elderly pundits. But it is not only in these exceptional cases that the advantages of leisure will appear. Ordinary men and women, having the opportunity of a happy life, will become more kindly and less persecuting and less inclined to view others with suspicion. The taste for war will die out, partly for this reason, and partly because it will involve long and severe work for all. Good nature is, of all moral qualities, the one that the world needs most, and good nature is the result of ease and security, not of a life of arduous struggle. Modern methods of production have given us the possibility of ease and security for all; we have chosen, instead, to have overwork for some and starvation for others. Hitherto we have continued to be as energetic as we were before there were machines; in this we have been foolish, but there is no reason to go on being foolish forever.
+
+[1] Since then, members of the Communist Party have succeeded to this privilege of the warriors and priests.
--- /dev/null
+var assert = require('assert');
+var wordwrap = require('wordwrap');
+
+var fs = require('fs');
+var idleness = fs.readFileSync(__dirname + '/idleness.txt', 'utf8');
+
+exports.stop80 = function () {
+ var lines = wordwrap(80)(idleness).split(/\n/);
+ var words = idleness.split(/\s+/);
+
+ lines.forEach(function (line) {
+ assert.ok(line.length <= 80, 'line > 80 columns');
+ var chunks = line.match(/\S/) ? line.split(/\s+/) : [];
+ assert.deepEqual(chunks, words.splice(0, chunks.length));
+ });
+};
+
+exports.start20stop60 = function () {
+ var lines = wordwrap(20, 100)(idleness).split(/\n/);
+ var words = idleness.split(/\s+/);
+
+ lines.forEach(function (line) {
+ assert.ok(line.length <= 100, 'line > 100 columns');
+ var chunks = line
+ .split(/\s+/)
+ .filter(function (x) { return x.match(/\S/) })
+ ;
+ assert.deepEqual(chunks, words.splice(0, chunks.length));
+ assert.deepEqual(line.slice(0, 20), new Array(20 + 1).join(' '));
+ });
+};
--- /dev/null
+{
+ "name": "optimist",
+ "version": "0.6.1",
+ "description": "Light-weight option parsing with an argv hash. No optstrings attached.",
+ "main": "./index.js",
+ "dependencies": {
+ "wordwrap": "~0.0.2",
+ "minimist": "~0.0.1"
+ },
+ "devDependencies": {
+ "hashish": "~0.0.4",
+ "tap": "~0.4.0"
+ },
+ "scripts": {
+ "test": "tap ./test/*.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "http://github.com/substack/node-optimist.git"
+ },
+ "keywords": [
+ "argument",
+ "args",
+ "option",
+ "parser",
+ "parsing",
+ "cli",
+ "command"
+ ],
+ "author": {
+ "name": "James Halliday",
+ "email": "mail@substack.net",
+ "url": "http://substack.net"
+ },
+ "license": "MIT/X11",
+ "engine": {
+ "node": ">=0.4"
+ },
+ "bugs": {
+ "url": "https://github.com/substack/node-optimist/issues"
+ },
+ "homepage": "https://github.com/substack/node-optimist",
+ "_id": "optimist@0.6.1",
+ "dist": {
+ "shasum": "da3ea74686fa21a19a111c326e90eb15a0196686",
+ "tarball": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz"
+ },
+ "_from": "optimist@>=0.3.4",
+ "_npmVersion": "1.3.21",
+ "_npmUser": {
+ "name": "substack",
+ "email": "mail@substack.net"
+ },
+ "maintainers": [
+ {
+ "name": "substack",
+ "email": "mail@substack.net"
+ }
+ ],
+ "directories": {},
+ "_shasum": "da3ea74686fa21a19a111c326e90eb15a0196686",
+ "_resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz"
+}
--- /dev/null
+# DEPRECATION NOTICE
+
+I don't want to maintain this module anymore since I just use
+[minimist](https://npmjs.org/package/minimist), the argument parsing engine,
+directly instead nowadays.
+
+See [yargs](https://github.com/chevex/yargs) for the modern, pirate-themed
+successor to optimist.
+
+[![yarrrrrrrgs!](http://i.imgur.com/4WFGVJ9.png)](https://github.com/chevex/yargs)
+
+You should also consider [nomnom](https://github.com/harthur/nomnom).
+
+optimist
+========
+
+Optimist is a node.js library for option parsing for people who hate option
+parsing. More specifically, this module is for people who like all the --bells
+and -whistlz of program usage but think optstrings are a waste of time.
+
+With optimist, option parsing doesn't have to suck (as much).
+
+[![build status](https://secure.travis-ci.org/substack/node-optimist.png)](http://travis-ci.org/substack/node-optimist)
+
+examples
+========
+
+With Optimist, the options are just a hash! No optstrings attached.
+-------------------------------------------------------------------
+
+xup.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('optimist').argv;
+
+if (argv.rif - 5 * argv.xup > 7.138) {
+ console.log('Buy more riffiwobbles');
+}
+else {
+ console.log('Sell the xupptumblers');
+}
+````
+
+***
+
+ $ ./xup.js --rif=55 --xup=9.52
+ Buy more riffiwobbles
+
+ $ ./xup.js --rif 12 --xup 8.1
+ Sell the xupptumblers
+
+![This one's optimistic.](http://substack.net/images/optimistic.png)
+
+But wait! There's more! You can do short options:
+-------------------------------------------------
+
+short.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('optimist').argv;
+console.log('(%d,%d)', argv.x, argv.y);
+````
+
+***
+
+ $ ./short.js -x 10 -y 21
+ (10,21)
+
+And booleans, both long and short (and grouped):
+----------------------------------
+
+bool.js:
+
+````javascript
+#!/usr/bin/env node
+var util = require('util');
+var argv = require('optimist').argv;
+
+if (argv.s) {
+ util.print(argv.fr ? 'Le chat dit: ' : 'The cat says: ');
+}
+console.log(
+ (argv.fr ? 'miaou' : 'meow') + (argv.p ? '.' : '')
+);
+````
+
+***
+
+ $ ./bool.js -s
+ The cat says: meow
+
+ $ ./bool.js -sp
+ The cat says: meow.
+
+ $ ./bool.js -sp --fr
+ Le chat dit: miaou.
+
+And non-hypenated options too! Just use `argv._`!
+-------------------------------------------------
+
+nonopt.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('optimist').argv;
+console.log('(%d,%d)', argv.x, argv.y);
+console.log(argv._);
+````
+
+***
+
+ $ ./nonopt.js -x 6.82 -y 3.35 moo
+ (6.82,3.35)
+ [ 'moo' ]
+
+ $ ./nonopt.js foo -x 0.54 bar -y 1.12 baz
+ (0.54,1.12)
+ [ 'foo', 'bar', 'baz' ]
+
+Plus, Optimist comes with .usage() and .demand()!
+-------------------------------------------------
+
+divide.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('optimist')
+ .usage('Usage: $0 -x [num] -y [num]')
+ .demand(['x','y'])
+ .argv;
+
+console.log(argv.x / argv.y);
+````
+
+***
+
+ $ ./divide.js -x 55 -y 11
+ 5
+
+ $ node ./divide.js -x 4.91 -z 2.51
+ Usage: node ./divide.js -x [num] -y [num]
+
+ Options:
+ -x [required]
+ -y [required]
+
+ Missing required arguments: y
+
+EVEN MORE HOLY COW
+------------------
+
+default_singles.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('optimist')
+ .default('x', 10)
+ .default('y', 10)
+ .argv
+;
+console.log(argv.x + argv.y);
+````
+
+***
+
+ $ ./default_singles.js -x 5
+ 15
+
+default_hash.js:
+
+````javascript
+#!/usr/bin/env node
+var argv = require('optimist')
+ .default({ x : 10, y : 10 })
+ .argv
+;
+console.log(argv.x + argv.y);
+````
+
+***
+
+ $ ./default_hash.js -y 7
+ 17
+
+And if you really want to get all descriptive about it...
+---------------------------------------------------------
+
+boolean_single.js
+
+````javascript
+#!/usr/bin/env node
+var argv = require('optimist')
+ .boolean('v')
+ .argv
+;
+console.dir(argv);
+````
+
+***
+
+ $ ./boolean_single.js -v foo bar baz
+ true
+ [ 'bar', 'baz', 'foo' ]
+
+boolean_double.js
+
+````javascript
+#!/usr/bin/env node
+var argv = require('optimist')
+ .boolean(['x','y','z'])
+ .argv
+;
+console.dir([ argv.x, argv.y, argv.z ]);
+console.dir(argv._);
+````
+
+***
+
+ $ ./boolean_double.js -x -z one two three
+ [ true, false, true ]
+ [ 'one', 'two', 'three' ]
+
+Optimist is here to help...
+---------------------------
+
+You can describe parameters for help messages and set aliases. Optimist figures
+out how to format a handy help string automatically.
+
+line_count.js
+
+````javascript
+#!/usr/bin/env node
+var argv = require('optimist')
+ .usage('Count the lines in a file.\nUsage: $0')
+ .demand('f')
+ .alias('f', 'file')
+ .describe('f', 'Load a file')
+ .argv
+;
+
+var fs = require('fs');
+var s = fs.createReadStream(argv.file);
+
+var lines = 0;
+s.on('data', function (buf) {
+ lines += buf.toString().match(/\n/g).length;
+});
+
+s.on('end', function () {
+ console.log(lines);
+});
+````
+
+***
+
+ $ node line_count.js
+ Count the lines in a file.
+ Usage: node ./line_count.js
+
+ Options:
+ -f, --file Load a file [required]
+
+ Missing required arguments: f
+
+ $ node line_count.js --file line_count.js
+ 20
+
+ $ node line_count.js -f line_count.js
+ 20
+
+methods
+=======
+
+By itself,
+
+````javascript
+require('optimist').argv
+`````
+
+will use `process.argv` array to construct the `argv` object.
+
+You can pass in the `process.argv` yourself:
+
+````javascript
+require('optimist')([ '-x', '1', '-y', '2' ]).argv
+````
+
+or use .parse() to do the same thing:
+
+````javascript
+require('optimist').parse([ '-x', '1', '-y', '2' ])
+````
+
+The rest of these methods below come in just before the terminating `.argv`.
+
+.alias(key, alias)
+------------------
+
+Set key names as equivalent such that updates to a key will propagate to aliases
+and vice-versa.
+
+Optionally `.alias()` can take an object that maps keys to aliases.
+
+.default(key, value)
+--------------------
+
+Set `argv[key]` to `value` if no option was specified on `process.argv`.
+
+Optionally `.default()` can take an object that maps keys to default values.
+
+.demand(key)
+------------
+
+If `key` is a string, show the usage information and exit if `key` wasn't
+specified in `process.argv`.
+
+If `key` is a number, demand at least as many non-option arguments, which show
+up in `argv._`.
+
+If `key` is an Array, demand each element.
+
+.describe(key, desc)
+--------------------
+
+Describe a `key` for the generated usage information.
+
+Optionally `.describe()` can take an object that maps keys to descriptions.
+
+.options(key, opt)
+------------------
+
+Instead of chaining together `.alias().demand().default()`, you can specify
+keys in `opt` for each of the chainable methods.
+
+For example:
+
+````javascript
+var argv = require('optimist')
+ .options('f', {
+ alias : 'file',
+ default : '/etc/passwd',
+ })
+ .argv
+;
+````
+
+is the same as
+
+````javascript
+var argv = require('optimist')
+ .alias('f', 'file')
+ .default('f', '/etc/passwd')
+ .argv
+;
+````
+
+Optionally `.options()` can take an object that maps keys to `opt` parameters.
+
+.usage(message)
+---------------
+
+Set a usage message to show which commands to use. Inside `message`, the string
+`$0` will get interpolated to the current script name or node command for the
+present script similar to how `$0` works in bash or perl.
+
+.check(fn)
+----------
+
+Check that certain conditions are met in the provided arguments.
+
+If `fn` throws or returns `false`, show the thrown error, usage information, and
+exit.
+
+.boolean(key)
+-------------
+
+Interpret `key` as a boolean. If a non-flag option follows `key` in
+`process.argv`, that string won't get set as the value of `key`.
+
+If `key` never shows up as a flag in `process.arguments`, `argv[key]` will be
+`false`.
+
+If `key` is an Array, interpret all the elements as booleans.
+
+.string(key)
+------------
+
+Tell the parser logic not to interpret `key` as a number or boolean.
+This can be useful if you need to preserve leading zeros in an input.
+
+If `key` is an Array, interpret all the elements as strings.
+
+.wrap(columns)
+--------------
+
+Format usage output to wrap at `columns` many columns.
+
+.help()
+-------
+
+Return the generated usage string.
+
+.showHelp(fn=console.error)
+---------------------------
+
+Print the usage data using `fn` for printing.
+
+.parse(args)
+------------
+
+Parse `args` instead of `process.argv`. Returns the `argv` object.
+
+.argv
+-----
+
+Get the arguments as a plain old object.
+
+Arguments without a corresponding flag show up in the `argv._` array.
+
+The script name or node command is available at `argv.$0` similarly to how `$0`
+works in bash or perl.
+
+parsing tricks
+==============
+
+stop parsing
+------------
+
+Use `--` to stop parsing flags and stuff the remainder into `argv._`.
+
+ $ node examples/reflect.js -a 1 -b 2 -- -c 3 -d 4
+ { _: [ '-c', '3', '-d', '4' ],
+ '$0': 'node ./examples/reflect.js',
+ a: 1,
+ b: 2 }
+
+negate fields
+-------------
+
+If you want to explicity set a field to false instead of just leaving it
+undefined or to override a default you can do `--no-key`.
+
+ $ node examples/reflect.js -a --no-b
+ { _: [],
+ '$0': 'node ./examples/reflect.js',
+ a: true,
+ b: false }
+
+numbers
+-------
+
+Every argument that looks like a number (`!isNaN(Number(arg))`) is converted to
+one. This way you can just `net.createConnection(argv.port)` and you can add
+numbers out of `argv` with `+` without having that mean concatenation,
+which is super frustrating.
+
+duplicates
+----------
+
+If you specify a flag multiple times it will get turned into an array containing
+all the values in order.
+
+ $ node examples/reflect.js -x 5 -x 8 -x 0
+ { _: [],
+ '$0': 'node ./examples/reflect.js',
+ x: [ 5, 8, 0 ] }
+
+dot notation
+------------
+
+When you use dots (`.`s) in argument names, an implicit object path is assumed.
+This lets you organize arguments into nested objects.
+
+ $ node examples/reflect.js --foo.bar.baz=33 --foo.quux=5
+ { _: [],
+ '$0': 'node ./examples/reflect.js',
+ foo: { bar: { baz: 33 }, quux: 5 } }
+
+short numbers
+-------------
+
+Short numeric `head -n5` style argument work too:
+
+ $ node reflect.js -n123 -m456
+ { '3': true,
+ '6': true,
+ _: [],
+ '$0': 'node ./reflect.js',
+ n: 123,
+ m: 456 }
+
+installation
+============
+
+With [npm](http://github.com/isaacs/npm), just do:
+ npm install optimist
+
+or clone this project on github:
+
+ git clone http://github.com/substack/node-optimist.git
+
+To run the tests with [expresso](http://github.com/visionmedia/expresso),
+just do:
+
+ expresso
+
+inspired By
+===========
+
+This module is loosely inspired by Perl's
+[Getopt::Casual](http://search.cpan.org/~photo/Getopt-Casual-0.13.1/Casual.pm).
--- /dev/null
+var spawn = require('child_process').spawn;
+var test = require('tap').test;
+
+test('dotSlashEmpty', testCmd('./bin.js', []));
+
+test('dotSlashArgs', testCmd('./bin.js', [ 'a', 'b', 'c' ]));
+
+test('nodeEmpty', testCmd('node bin.js', []));
+
+test('nodeArgs', testCmd('node bin.js', [ 'x', 'y', 'z' ]));
+
+test('whichNodeEmpty', function (t) {
+ var which = spawn('which', ['node']);
+
+ which.stdout.on('data', function (buf) {
+ t.test(
+ testCmd(buf.toString().trim() + ' bin.js', [])
+ );
+ t.end();
+ });
+
+ which.stderr.on('data', function (err) {
+ assert.error(err);
+ t.end();
+ });
+});
+
+test('whichNodeArgs', function (t) {
+ var which = spawn('which', ['node']);
+
+ which.stdout.on('data', function (buf) {
+ t.test(
+ testCmd(buf.toString().trim() + ' bin.js', [ 'q', 'r' ])
+ );
+ t.end();
+ });
+
+ which.stderr.on('data', function (err) {
+ t.error(err);
+ t.end();
+ });
+});
+
+function testCmd (cmd, args) {
+
+ return function (t) {
+ var to = setTimeout(function () {
+ assert.fail('Never got stdout data.')
+ }, 5000);
+
+ var oldDir = process.cwd();
+ process.chdir(__dirname + '/_');
+
+ var cmds = cmd.split(' ');
+
+ var bin = spawn(cmds[0], cmds.slice(1).concat(args.map(String)));
+ process.chdir(oldDir);
+
+ bin.stderr.on('data', function (err) {
+ t.error(err);
+ t.end();
+ });
+
+ bin.stdout.on('data', function (buf) {
+ clearTimeout(to);
+ var _ = JSON.parse(buf.toString());
+ t.same(_.map(String), args.map(String));
+ t.end();
+ });
+ };
+}
--- /dev/null
+#!/usr/bin/env node
+console.log(JSON.stringify(process.argv));
--- /dev/null
+#!/usr/bin/env node
+var argv = require('../../index').argv
+console.log(JSON.stringify(argv._));
--- /dev/null
+var optimist = require('../index');
+var test = require('tap').test;
+
+test('-', function (t) {
+ t.plan(5);
+ t.deepEqual(
+ fix(optimist.parse([ '-n', '-' ])),
+ { n: '-', _: [] }
+ );
+ t.deepEqual(
+ fix(optimist.parse([ '-' ])),
+ { _: [ '-' ] }
+ );
+ t.deepEqual(
+ fix(optimist.parse([ '-f-' ])),
+ { f: '-', _: [] }
+ );
+ t.deepEqual(
+ fix(optimist([ '-b', '-' ]).boolean('b').argv),
+ { b: true, _: [ '-' ] }
+ );
+ t.deepEqual(
+ fix(optimist([ '-s', '-' ]).string('s').argv),
+ { s: '-', _: [] }
+ );
+});
+
+function fix (obj) {
+ delete obj.$0;
+ return obj;
+}
--- /dev/null
+var optimist = require('../index');
+var path = require('path');
+var test = require('tap').test;
+
+var $0 = 'node ./' + path.relative(process.cwd(), __filename);
+
+test('short boolean', function (t) {
+ var parse = optimist.parse([ '-b' ]);
+ t.same(parse, { b : true, _ : [], $0 : $0 });
+ t.same(typeof parse.b, 'boolean');
+ t.end();
+});
+
+test('long boolean', function (t) {
+ t.same(
+ optimist.parse([ '--bool' ]),
+ { bool : true, _ : [], $0 : $0 }
+ );
+ t.end();
+});
+
+test('bare', function (t) {
+ t.same(
+ optimist.parse([ 'foo', 'bar', 'baz' ]),
+ { _ : [ 'foo', 'bar', 'baz' ], $0 : $0 }
+ );
+ t.end();
+});
+
+test('short group', function (t) {
+ t.same(
+ optimist.parse([ '-cats' ]),
+ { c : true, a : true, t : true, s : true, _ : [], $0 : $0 }
+ );
+ t.end();
+});
+
+test('short group next', function (t) {
+ t.same(
+ optimist.parse([ '-cats', 'meow' ]),
+ { c : true, a : true, t : true, s : 'meow', _ : [], $0 : $0 }
+ );
+ t.end();
+});
+
+test('short capture', function (t) {
+ t.same(
+ optimist.parse([ '-h', 'localhost' ]),
+ { h : 'localhost', _ : [], $0 : $0 }
+ );
+ t.end();
+});
+
+test('short captures', function (t) {
+ t.same(
+ optimist.parse([ '-h', 'localhost', '-p', '555' ]),
+ { h : 'localhost', p : 555, _ : [], $0 : $0 }
+ );
+ t.end();
+});
+
+test('long capture sp', function (t) {
+ t.same(
+ optimist.parse([ '--pow', 'xixxle' ]),
+ { pow : 'xixxle', _ : [], $0 : $0 }
+ );
+ t.end();
+});
+
+test('long capture eq', function (t) {
+ t.same(
+ optimist.parse([ '--pow=xixxle' ]),
+ { pow : 'xixxle', _ : [], $0 : $0 }
+ );
+ t.end()
+});
+
+test('long captures sp', function (t) {
+ t.same(
+ optimist.parse([ '--host', 'localhost', '--port', '555' ]),
+ { host : 'localhost', port : 555, _ : [], $0 : $0 }
+ );
+ t.end();
+});
+
+test('long captures eq', function (t) {
+ t.same(
+ optimist.parse([ '--host=localhost', '--port=555' ]),
+ { host : 'localhost', port : 555, _ : [], $0 : $0 }
+ );
+ t.end();
+});
+
+test('mixed short bool and capture', function (t) {
+ t.same(
+ optimist.parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]),
+ {
+ f : true, p : 555, h : 'localhost',
+ _ : [ 'script.js' ], $0 : $0,
+ }
+ );
+ t.end();
+});
+
+test('short and long', function (t) {
+ t.same(
+ optimist.parse([ '-h', 'localhost', '-fp', '555', 'script.js' ]),
+ {
+ f : true, p : 555, h : 'localhost',
+ _ : [ 'script.js' ], $0 : $0,
+ }
+ );
+ t.end();
+});
+
+test('no', function (t) {
+ t.same(
+ optimist.parse([ '--no-moo' ]),
+ { moo : false, _ : [], $0 : $0 }
+ );
+ t.end();
+});
+
+test('multi', function (t) {
+ t.same(
+ optimist.parse([ '-v', 'a', '-v', 'b', '-v', 'c' ]),
+ { v : ['a','b','c'], _ : [], $0 : $0 }
+ );
+ t.end();
+});
+
+test('comprehensive', function (t) {
+ t.same(
+ optimist.parse([
+ '--name=meowmers', 'bare', '-cats', 'woo',
+ '-h', 'awesome', '--multi=quux',
+ '--key', 'value',
+ '-b', '--bool', '--no-meep', '--multi=baz',
+ '--', '--not-a-flag', 'eek'
+ ]),
+ {
+ c : true,
+ a : true,
+ t : true,
+ s : 'woo',
+ h : 'awesome',
+ b : true,
+ bool : true,
+ key : 'value',
+ multi : [ 'quux', 'baz' ],
+ meep : false,
+ name : 'meowmers',
+ _ : [ 'bare', '--not-a-flag', 'eek' ],
+ $0 : $0
+ }
+ );
+ t.end();
+});
+
+test('nums', function (t) {
+ var argv = optimist.parse([
+ '-x', '1234',
+ '-y', '5.67',
+ '-z', '1e7',
+ '-w', '10f',
+ '--hex', '0xdeadbeef',
+ '789',
+ ]);
+ t.same(argv, {
+ x : 1234,
+ y : 5.67,
+ z : 1e7,
+ w : '10f',
+ hex : 0xdeadbeef,
+ _ : [ 789 ],
+ $0 : $0
+ });
+ t.same(typeof argv.x, 'number');
+ t.same(typeof argv.y, 'number');
+ t.same(typeof argv.z, 'number');
+ t.same(typeof argv.w, 'string');
+ t.same(typeof argv.hex, 'number');
+ t.same(typeof argv._[0], 'number');
+ t.end();
+});
+
+test('flag boolean', function (t) {
+ var parse = optimist([ '-t', 'moo' ]).boolean(['t']).argv;
+ t.same(parse, { t : true, _ : [ 'moo' ], $0 : $0 });
+ t.same(typeof parse.t, 'boolean');
+ t.end();
+});
+
+test('flag boolean value', function (t) {
+ var parse = optimist(['--verbose', 'false', 'moo', '-t', 'true'])
+ .boolean(['t', 'verbose']).default('verbose', true).argv;
+
+ t.same(parse, {
+ verbose: false,
+ t: true,
+ _: ['moo'],
+ $0 : $0
+ });
+
+ t.same(typeof parse.verbose, 'boolean');
+ t.same(typeof parse.t, 'boolean');
+ t.end();
+});
+
+test('flag boolean default false', function (t) {
+ var parse = optimist(['moo'])
+ .boolean(['t', 'verbose'])
+ .default('verbose', false)
+ .default('t', false).argv;
+
+ t.same(parse, {
+ verbose: false,
+ t: false,
+ _: ['moo'],
+ $0 : $0
+ });
+
+ t.same(typeof parse.verbose, 'boolean');
+ t.same(typeof parse.t, 'boolean');
+ t.end();
+
+});
+
+test('boolean groups', function (t) {
+ var parse = optimist([ '-x', '-z', 'one', 'two', 'three' ])
+ .boolean(['x','y','z']).argv;
+
+ t.same(parse, {
+ x : true,
+ y : false,
+ z : true,
+ _ : [ 'one', 'two', 'three' ],
+ $0 : $0
+ });
+
+ t.same(typeof parse.x, 'boolean');
+ t.same(typeof parse.y, 'boolean');
+ t.same(typeof parse.z, 'boolean');
+ t.end();
+});
+
+test('newlines in params' , function (t) {
+ var args = optimist.parse([ '-s', "X\nX" ])
+ t.same(args, { _ : [], s : "X\nX", $0 : $0 });
+
+ // reproduce in bash:
+ // VALUE="new
+ // line"
+ // node program.js --s="$VALUE"
+ args = optimist.parse([ "--s=X\nX" ])
+ t.same(args, { _ : [], s : "X\nX", $0 : $0 });
+ t.end();
+});
+
+test('strings' , function (t) {
+ var s = optimist([ '-s', '0001234' ]).string('s').argv.s;
+ t.same(s, '0001234');
+ t.same(typeof s, 'string');
+
+ var x = optimist([ '-x', '56' ]).string('x').argv.x;
+ t.same(x, '56');
+ t.same(typeof x, 'string');
+ t.end();
+});
+
+test('stringArgs', function (t) {
+ var s = optimist([ ' ', ' ' ]).string('_').argv._;
+ t.same(s.length, 2);
+ t.same(typeof s[0], 'string');
+ t.same(s[0], ' ');
+ t.same(typeof s[1], 'string');
+ t.same(s[1], ' ');
+ t.end();
+});
+
+test('slashBreak', function (t) {
+ t.same(
+ optimist.parse([ '-I/foo/bar/baz' ]),
+ { I : '/foo/bar/baz', _ : [], $0 : $0 }
+ );
+ t.same(
+ optimist.parse([ '-xyz/foo/bar/baz' ]),
+ { x : true, y : true, z : '/foo/bar/baz', _ : [], $0 : $0 }
+ );
+ t.end();
+});
+
+test('alias', function (t) {
+ var argv = optimist([ '-f', '11', '--zoom', '55' ])
+ .alias('z', 'zoom')
+ .argv
+ ;
+ t.equal(argv.zoom, 55);
+ t.equal(argv.z, argv.zoom);
+ t.equal(argv.f, 11);
+ t.end();
+});
+
+test('multiAlias', function (t) {
+ var argv = optimist([ '-f', '11', '--zoom', '55' ])
+ .alias('z', [ 'zm', 'zoom' ])
+ .argv
+ ;
+ t.equal(argv.zoom, 55);
+ t.equal(argv.z, argv.zoom);
+ t.equal(argv.z, argv.zm);
+ t.equal(argv.f, 11);
+ t.end();
+});
+
+test('boolean default true', function (t) {
+ var argv = optimist.options({
+ sometrue: {
+ boolean: true,
+ default: true
+ }
+ }).argv;
+
+ t.equal(argv.sometrue, true);
+ t.end();
+});
+
+test('boolean default false', function (t) {
+ var argv = optimist.options({
+ somefalse: {
+ boolean: true,
+ default: false
+ }
+ }).argv;
+
+ t.equal(argv.somefalse, false);
+ t.end();
+});
+
+test('nested dotted objects', function (t) {
+ var argv = optimist([
+ '--foo.bar', '3', '--foo.baz', '4',
+ '--foo.quux.quibble', '5', '--foo.quux.o_O',
+ '--beep.boop'
+ ]).argv;
+
+ t.same(argv.foo, {
+ bar : 3,
+ baz : 4,
+ quux : {
+ quibble : 5,
+ o_O : true
+ },
+ });
+ t.same(argv.beep, { boop : true });
+ t.end();
+});
+
+test('boolean and alias with chainable api', function (t) {
+ var aliased = [ '-h', 'derp' ];
+ var regular = [ '--herp', 'derp' ];
+ var opts = {
+ herp: { alias: 'h', boolean: true }
+ };
+ var aliasedArgv = optimist(aliased)
+ .boolean('herp')
+ .alias('h', 'herp')
+ .argv;
+ var propertyArgv = optimist(regular)
+ .boolean('herp')
+ .alias('h', 'herp')
+ .argv;
+ var expected = {
+ herp: true,
+ h: true,
+ '_': [ 'derp' ],
+ '$0': $0,
+ };
+
+ t.same(aliasedArgv, expected);
+ t.same(propertyArgv, expected);
+ t.end();
+});
+
+test('boolean and alias with options hash', function (t) {
+ var aliased = [ '-h', 'derp' ];
+ var regular = [ '--herp', 'derp' ];
+ var opts = {
+ herp: { alias: 'h', boolean: true }
+ };
+ var aliasedArgv = optimist(aliased)
+ .options(opts)
+ .argv;
+ var propertyArgv = optimist(regular).options(opts).argv;
+ var expected = {
+ herp: true,
+ h: true,
+ '_': [ 'derp' ],
+ '$0': $0,
+ };
+
+ t.same(aliasedArgv, expected);
+ t.same(propertyArgv, expected);
+
+ t.end();
+});
+
+test('boolean and alias using explicit true', function (t) {
+ var aliased = [ '-h', 'true' ];
+ var regular = [ '--herp', 'true' ];
+ var opts = {
+ herp: { alias: 'h', boolean: true }
+ };
+ var aliasedArgv = optimist(aliased)
+ .boolean('h')
+ .alias('h', 'herp')
+ .argv;
+ var propertyArgv = optimist(regular)
+ .boolean('h')
+ .alias('h', 'herp')
+ .argv;
+ var expected = {
+ herp: true,
+ h: true,
+ '_': [ ],
+ '$0': $0,
+ };
+
+ t.same(aliasedArgv, expected);
+ t.same(propertyArgv, expected);
+ t.end();
+});
+
+// regression, see https://github.com/substack/node-optimist/issues/71
+test('boolean and --x=true', function(t) {
+ var parsed = optimist(['--boool', '--other=true']).boolean('boool').argv;
+
+ t.same(parsed.boool, true);
+ t.same(parsed.other, 'true');
+
+ parsed = optimist(['--boool', '--other=false']).boolean('boool').argv;
+
+ t.same(parsed.boool, true);
+ t.same(parsed.other, 'false');
+ t.end();
+});
--- /dev/null
+var optimist = require('../');
+var test = require('tap').test;
+
+test('parse with modifier functions' , function (t) {
+ t.plan(1);
+
+ var argv = optimist().boolean('b').parse([ '-b', '123' ]);
+ t.deepEqual(fix(argv), { b: true, _: ['123'] });
+});
+
+function fix (obj) {
+ delete obj.$0;
+ return obj;
+}
--- /dev/null
+var optimist = require('../index');
+var test = require('tap').test;
+
+test('-n123', function (t) {
+ t.plan(1);
+ var parse = optimist.parse([ '-n123' ]);
+ t.equal(parse.n, 123);
+});
+
+test('-123', function (t) {
+ t.plan(3);
+ var parse = optimist.parse([ '-123', '456' ]);
+ t.equal(parse['1'], true);
+ t.equal(parse['2'], true);
+ t.equal(parse['3'], 456);
+});
--- /dev/null
+var Hash = require('hashish');
+var optimist = require('../index');
+var test = require('tap').test;
+
+test('usageFail', function (t) {
+ var r = checkUsage(function () {
+ return optimist('-x 10 -z 20'.split(' '))
+ .usage('Usage: $0 -x NUM -y NUM')
+ .demand(['x','y'])
+ .argv;
+ });
+ t.same(
+ r.result,
+ { x : 10, z : 20, _ : [], $0 : './usage' }
+ );
+
+ t.same(
+ r.errors.join('\n').split(/\n+/),
+ [
+ 'Usage: ./usage -x NUM -y NUM',
+ 'Options:',
+ ' -x [required]',
+ ' -y [required]',
+ 'Missing required arguments: y',
+ ]
+ );
+ t.same(r.logs, []);
+ t.ok(r.exit);
+ t.end();
+});
+
+
+test('usagePass', function (t) {
+ var r = checkUsage(function () {
+ return optimist('-x 10 -y 20'.split(' '))
+ .usage('Usage: $0 -x NUM -y NUM')
+ .demand(['x','y'])
+ .argv;
+ });
+ t.same(r, {
+ result : { x : 10, y : 20, _ : [], $0 : './usage' },
+ errors : [],
+ logs : [],
+ exit : false,
+ });
+ t.end();
+});
+
+test('checkPass', function (t) {
+ var r = checkUsage(function () {
+ return optimist('-x 10 -y 20'.split(' '))
+ .usage('Usage: $0 -x NUM -y NUM')
+ .check(function (argv) {
+ if (!('x' in argv)) throw 'You forgot about -x';
+ if (!('y' in argv)) throw 'You forgot about -y';
+ })
+ .argv;
+ });
+ t.same(r, {
+ result : { x : 10, y : 20, _ : [], $0 : './usage' },
+ errors : [],
+ logs : [],
+ exit : false,
+ });
+ t.end();
+});
+
+test('checkFail', function (t) {
+ var r = checkUsage(function () {
+ return optimist('-x 10 -z 20'.split(' '))
+ .usage('Usage: $0 -x NUM -y NUM')
+ .check(function (argv) {
+ if (!('x' in argv)) throw 'You forgot about -x';
+ if (!('y' in argv)) throw 'You forgot about -y';
+ })
+ .argv;
+ });
+
+ t.same(
+ r.result,
+ { x : 10, z : 20, _ : [], $0 : './usage' }
+ );
+
+ t.same(
+ r.errors.join('\n').split(/\n+/),
+ [
+ 'Usage: ./usage -x NUM -y NUM',
+ 'You forgot about -y'
+ ]
+ );
+
+ t.same(r.logs, []);
+ t.ok(r.exit);
+ t.end();
+});
+
+test('checkCondPass', function (t) {
+ function checker (argv) {
+ return 'x' in argv && 'y' in argv;
+ }
+
+ var r = checkUsage(function () {
+ return optimist('-x 10 -y 20'.split(' '))
+ .usage('Usage: $0 -x NUM -y NUM')
+ .check(checker)
+ .argv;
+ });
+ t.same(r, {
+ result : { x : 10, y : 20, _ : [], $0 : './usage' },
+ errors : [],
+ logs : [],
+ exit : false,
+ });
+ t.end();
+});
+
+test('checkCondFail', function (t) {
+ function checker (argv) {
+ return 'x' in argv && 'y' in argv;
+ }
+
+ var r = checkUsage(function () {
+ return optimist('-x 10 -z 20'.split(' '))
+ .usage('Usage: $0 -x NUM -y NUM')
+ .check(checker)
+ .argv;
+ });
+
+ t.same(
+ r.result,
+ { x : 10, z : 20, _ : [], $0 : './usage' }
+ );
+
+ t.same(
+ r.errors.join('\n').split(/\n+/).join('\n'),
+ 'Usage: ./usage -x NUM -y NUM\n'
+ + 'Argument check failed: ' + checker.toString()
+ );
+
+ t.same(r.logs, []);
+ t.ok(r.exit);
+ t.end();
+});
+
+test('countPass', function (t) {
+ var r = checkUsage(function () {
+ return optimist('1 2 3 --moo'.split(' '))
+ .usage('Usage: $0 [x] [y] [z] {OPTIONS}')
+ .demand(3)
+ .argv;
+ });
+ t.same(r, {
+ result : { _ : [ '1', '2', '3' ], moo : true, $0 : './usage' },
+ errors : [],
+ logs : [],
+ exit : false,
+ });
+ t.end();
+});
+
+test('countFail', function (t) {
+ var r = checkUsage(function () {
+ return optimist('1 2 --moo'.split(' '))
+ .usage('Usage: $0 [x] [y] [z] {OPTIONS}')
+ .demand(3)
+ .argv;
+ });
+ t.same(
+ r.result,
+ { _ : [ '1', '2' ], moo : true, $0 : './usage' }
+ );
+
+ t.same(
+ r.errors.join('\n').split(/\n+/),
+ [
+ 'Usage: ./usage [x] [y] [z] {OPTIONS}',
+ 'Not enough non-option arguments: got 2, need at least 3',
+ ]
+ );
+
+ t.same(r.logs, []);
+ t.ok(r.exit);
+ t.end();
+});
+
+test('defaultSingles', function (t) {
+ var r = checkUsage(function () {
+ return optimist('--foo 50 --baz 70 --powsy'.split(' '))
+ .default('foo', 5)
+ .default('bar', 6)
+ .default('baz', 7)
+ .argv
+ ;
+ });
+ t.same(r.result, {
+ foo : '50',
+ bar : 6,
+ baz : '70',
+ powsy : true,
+ _ : [],
+ $0 : './usage',
+ });
+ t.end();
+});
+
+test('defaultAliases', function (t) {
+ var r = checkUsage(function () {
+ return optimist('')
+ .alias('f', 'foo')
+ .default('f', 5)
+ .argv
+ ;
+ });
+ t.same(r.result, {
+ f : '5',
+ foo : '5',
+ _ : [],
+ $0 : './usage',
+ });
+ t.end();
+});
+
+test('defaultHash', function (t) {
+ var r = checkUsage(function () {
+ return optimist('--foo 50 --baz 70'.split(' '))
+ .default({ foo : 10, bar : 20, quux : 30 })
+ .argv
+ ;
+ });
+ t.same(r.result, {
+ _ : [],
+ $0 : './usage',
+ foo : 50,
+ baz : 70,
+ bar : 20,
+ quux : 30,
+ });
+ t.end();
+});
+
+test('rebase', function (t) {
+ t.equal(
+ optimist.rebase('/home/substack', '/home/substack/foo/bar/baz'),
+ './foo/bar/baz'
+ );
+ t.equal(
+ optimist.rebase('/home/substack/foo/bar/baz', '/home/substack'),
+ '../../..'
+ );
+ t.equal(
+ optimist.rebase('/home/substack/foo', '/home/substack/pow/zoom.txt'),
+ '../pow/zoom.txt'
+ );
+ t.end();
+});
+
+function checkUsage (f) {
+
+ var exit = false;
+
+ process._exit = process.exit;
+ process._env = process.env;
+ process._argv = process.argv;
+
+ process.exit = function (t) { exit = true };
+ process.env = Hash.merge(process.env, { _ : 'node' });
+ process.argv = [ './usage' ];
+
+ var errors = [];
+ var logs = [];
+
+ console._error = console.error;
+ console.error = function (msg) { errors.push(msg) };
+ console._log = console.log;
+ console.log = function (msg) { logs.push(msg) };
+
+ var result = f();
+
+ process.exit = process._exit;
+ process.env = process._env;
+ process.argv = process._argv;
+
+ console.error = console._error;
+ console.log = console._log;
+
+ return {
+ errors : errors,
+ logs : logs,
+ exit : exit,
+ result : result,
+ };
+};
--- /dev/null
+var optimist = require('../');
+var test = require('tap').test;
+
+test('whitespace should be whitespace' , function (t) {
+ t.plan(1);
+ var x = optimist.parse([ '-x', '\t' ]).x;
+ t.equal(x, '\t');
+});
--- /dev/null
+{
+ "name": "node-static",
+ "description": "simple, compliant file streaming module for node",
+ "url": "http://github.com/cloudhead/node-static",
+ "keywords": [
+ "http",
+ "static",
+ "file",
+ "server"
+ ],
+ "author": {
+ "name": "Alexis Sellier",
+ "email": "alexis@cloudhead.io"
+ },
+ "contributors": [
+ {
+ "name": "Pablo Cantero",
+ "email": "pablo@pablocantero.com"
+ },
+ {
+ "name": "Ionică Bizău",
+ "email": "bizauionica@gmail.com"
+ }
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git+ssh://git@github.com/cloudhead/node-static.git"
+ },
+ "main": "./lib/node-static",
+ "scripts": {
+ "test": "vows --spec --isolate"
+ },
+ "bin": {
+ "static": "bin/cli.js"
+ },
+ "license": "MIT",
+ "dependencies": {
+ "optimist": ">=0.3.4",
+ "colors": ">=0.6.0",
+ "mime": "^1.2.9"
+ },
+ "devDependencies": {
+ "request": "latest",
+ "vows": "latest"
+ },
+ "version": "0.7.11",
+ "engines": {
+ "node": ">= 0.4.1"
+ },
+ "bugs": {
+ "url": "https://github.com/cloudhead/node-static/issues"
+ },
+ "homepage": "https://github.com/cloudhead/node-static",
+ "directories": {
+ "example": "examples",
+ "test": "test"
+ },
+ "gitHead": "e59fe21dffbee46678362d26d26fdfb241f49506",
+ "_id": "node-static@0.7.11",
+ "_npmVersion": "6.4.1",
+ "_nodeVersion": "10.9.0",
+ "_npmUser": {
+ "name": "cloudhead",
+ "email": "self@cloudhead.net"
+ },
+ "dist": {
+ "integrity": "sha512-zfWC/gICcqb74D9ndyvxZWaI1jzcoHmf4UTHWQchBNuNMxdBLJMDiUgZ1tjGLEIe/BMhj2DxKD8HOuc2062pDQ==",
+ "shasum": "60120d349f3cef533e4e820670057eb631882e7f",
+ "tarball": "https://registry.npmjs.org/node-static/-/node-static-0.7.11.tgz",
+ "fileCount": 13,
+ "unpackedSize": 42054,
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbp3bfCRA9TVsSAnZWagAAeJYP/R2z14Ys7XeJhAhLMYPW\nWINvoEzIbcZ8bYNzCS9IZDmJ6vHnWicWBH6ts9PgnJvXOuxVjm/DlU7fzqSG\n8n4Bac2sbCGof7ipBiGaeqNegfCWLFON9VeFEWuOz3JZ9SL9G2hFTdKM1a47\nZmjySf6jGP7D/E7VVCiXAfgGWl8yFiv3pjIAZpPliRbNKOk8okkuPivt/483\nuX/fla3PP0SoaNilESklsOAxNpDIiRx3oYrTqQwdLUUff1xZu7Qb6gN57cqN\nBBwcBrUXZ+9sLyaxCJO2f1UtUcnznu/yH5bDhfFhP3qfAuRD9qzsR6mIc0kY\nYDA9naEiUMrLOPtzFZ2I+UCSBnzFiW4sZd/Km1VyhYyFcl+s/j0xIB3bzkaj\nUPnnWm+KY0cfEfUIxVHYRgB8T1EYIQAleEtxXBjFmspeKpv/yd+1+pL6vgcS\nXrQlLXXkhHnnhtWNGlI7lcpuIxHkCf0JZusJTMiNemWrNRr52iPltnOcaXUU\nwkRi6jfWM6t9S2GxXD/pJ90/v+ik0Z15Z1r59+I8oZHwp7+nseA3XddsEgFj\nx/vA59U9G0ZuGeM9OqGxL5Rl1w71dQjVXLhVZHI3H2mcMSMPtROeFITqLPIl\njVo385KMRgFY0GlE8f5kROOwcofN8nwRBpQX1DwO6jFiNVscC3auXVLtGouY\nb86R\r\n=62R1\r\n-----END PGP SIGNATURE-----\r\n"
+ },
+ "maintainers": [
+ {
+ "name": "cloudhead",
+ "email": "self@cloudhead.net"
+ },
+ {
+ "name": "indexzero",
+ "email": "charlie.robbins@gmail.com"
+ },
+ {
+ "name": "phstc",
+ "email": "pablo@pablocantero.com"
+ }
+ ],
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/node-static_0.7.11_1537701598456_0.5872354304574499"
+ },
+ "_hasShrinkwrap": false,
+ "_shasum": "60120d349f3cef533e4e820670057eb631882e7f",
+ "_from": "node-static@",
+ "_resolved": "https://registry.npmjs.org/node-static/-/node-static-0.7.11.tgz"
+}
--- /dev/null
+hello world
\ No newline at end of file
--- /dev/null
+<html lang="en">
+<head>
+ <title>Awesome page</title>
+</head>
+<body>
+ hello world!
+</body>
+</html>
--- /dev/null
+<html lang="en">
+<head>
+ <title>Other page</title>
+</head>
+<body>
+ hello there!
+</body>
+</html>
--- /dev/null
+var vows = require('vows')
+ , request = require('request')
+ , assert = require('assert')
+ , static = require('../../lib/node-static');
+
+var fileServer = new static.Server(__dirname + '/../fixtures');
+var suite = vows.describe('node-static');
+var TEST_PORT = 8080;
+var TEST_SERVER = 'http://localhost:' + TEST_PORT;
+var version = static.version.join('.');
+var server;
+var callback;
+
+headers = {
+ 'requesting headers': {
+ topic : function(){
+ request.head(TEST_SERVER + '/index.html', this.callback);
+ }
+ }
+}
+headers['requesting headers']['should respond with node-static/' + version] = function(error, response, body){
+ assert.equal(response.headers['server'], 'node-static/' + version);
+}
+
+suite.addBatch({
+ 'once an http server is listening with a callback': {
+ topic: function () {
+ server = require('http').createServer(function (request, response) {
+ fileServer.serve(request, response, function(err, result) {
+ if (callback)
+ callback(request, response, err, result);
+ else
+ request.end();
+ });
+ }).listen(TEST_PORT, this.callback)
+ },
+ 'should be listening' : function(){
+ /* This test is necessary to ensure the topic execution.
+ * A topic without tests will be not executed */
+ assert.isTrue(true);
+ }
+ },
+}).addBatch({
+ 'streaming a 404 page': {
+ topic: function(){
+ callback = function(request, response, err, result) {
+ if (err) {
+ response.writeHead(err.status, err.headers);
+ setTimeout(function() {
+ response.end('Custom 404 Stream.')
+ }, 100);
+ }
+ }
+ request.get(TEST_SERVER + '/not-found', this.callback);
+ },
+ 'should respond with 404' : function(error, response, body){
+ assert.equal(response.statusCode, 404);
+ },
+ 'should respond with the streamed content': function(error, response, body){
+ callback = null;
+ assert.equal(body, 'Custom 404 Stream.');
+ }
+ }
+}).addBatch({
+ 'once an http server is listening without a callback': {
+ topic: function () {
+ server.close();
+ server = require('http').createServer(function (request, response) {
+ fileServer.serve(request, response);
+ }).listen(TEST_PORT, this.callback)
+ },
+ 'should be listening' : function(){
+ /* This test is necessary to ensure the topic execution.
+ * A topic without tests will be not executed */
+ assert.isTrue(true);
+ }
+ }
+}).addBatch({
+ 'requesting a file not found': {
+ topic : function(){
+ request.get(TEST_SERVER + '/not-found', this.callback);
+ },
+ 'should respond with 404' : function(error, response, body){
+ assert.equal(response.statusCode, 404);
+ }
+ }
+})
+.addBatch({
+ 'requesting a malformed URI': {
+ topic: function(){
+ request.get(TEST_SERVER + '/a%AFc', this.callback);
+ },
+ 'should respond with 400': function(error, response, body){
+ assert.equal(response.statusCode, 400);
+ }
+ }
+})
+.addBatch({
+ 'serving empty.css': {
+ topic : function(){
+ request.get(TEST_SERVER + '/empty.css', this.callback);
+ },
+ 'should respond with 200' : function(error, response, body){
+ assert.equal(response.statusCode, 200);
+ },
+ 'should respond with text/css': function(error, response, body){
+ assert.equal(response.headers['content-type'], 'text/css');
+ },
+ 'should respond with empty string': function(error, response, body){
+ assert.equal(body, '');
+ }
+ }
+})
+.addBatch({
+ 'serving hello.txt': {
+ topic : function(){
+ request.get(TEST_SERVER + '/hello.txt', this.callback);
+ },
+ 'should respond with 200' : function(error, response, body){
+ assert.equal(response.statusCode, 200);
+ },
+ 'should respond with text/plain': function(error, response, body){
+ assert.equal(response.headers['content-type'], 'text/plain');
+ },
+ 'should respond with hello world': function(error, response, body){
+ assert.equal(body, 'hello world');
+ }
+ }
+}).addBatch({
+ 'serving first 5 bytes of hello.txt': {
+ topic : function(){
+ var options = {
+ url: TEST_SERVER + '/hello.txt',
+ headers: {
+ 'Range': 'bytes=0-4'
+ }
+ };
+ request.get(options, this.callback);
+ },
+ 'should respond with 206' : function(error, response, body){
+ assert.equal(response.statusCode, 206);
+ },
+ 'should respond with text/plain': function(error, response, body){
+ assert.equal(response.headers['content-type'], 'text/plain');
+ },
+ 'should have content-length of 5 bytes': function(error, response, body){
+ assert.equal(response.headers['content-length'], 5);
+ },
+ 'should have a valid Content-Range header in response': function(error, response, body){
+ assert.equal(response.headers['content-range'], 'bytes 0-4/11');
+ },
+ 'should respond with hello': function(error, response, body){
+ assert.equal(body, 'hello');
+ }
+ }
+}).addBatch({
+ 'serving last 5 bytes of hello.txt': {
+ topic : function(){
+ var options = {
+ url: TEST_SERVER + '/hello.txt',
+ headers: {
+ 'Range': 'bytes=6-10'
+ }
+ };
+ request.get(options, this.callback);
+ },
+ 'should respond with 206' : function(error, response, body){
+ assert.equal(response.statusCode, 206);
+ },
+ 'should respond with text/plain': function(error, response, body){
+ assert.equal(response.headers['content-type'], 'text/plain');
+ },
+ 'should have content-length of 5 bytes': function(error, response, body){
+ assert.equal(response.headers['content-length'], 5);
+ },
+ 'should have a valid Content-Range header in response': function(error, response, body){
+ assert.equal(response.headers['content-range'], 'bytes 6-10/11');
+ },
+ 'should respond with world': function(error, response, body){
+ assert.equal(body, 'world');
+ }
+ }
+}).addBatch({
+ 'serving all from the start of hello.txt': {
+ topic : function(){
+ var options = {
+ url: TEST_SERVER + '/hello.txt',
+ headers: {
+ 'Range': 'bytes=0-'
+ }
+ };
+ request.get(options, this.callback);
+ },
+ 'should respond with 206' : function(error, response, body){
+ assert.equal(response.statusCode, 206);
+ },
+ 'should respond with text/plain': function(error, response, body){
+ assert.equal(response.headers['content-type'], 'text/plain');
+ },
+ 'should have content-length of 11 bytes': function(error, response, body){
+ assert.equal(response.headers['content-length'], 11);
+ },
+ 'should have a valid Content-Range header in response': function(error, response, body){
+ assert.equal(response.headers['content-range'], 'bytes 0-10/11');
+ },
+ 'should respond with "hello world"': function(error, response, body){
+ assert.equal(body, 'hello world');
+ }
+ }
+}).addBatch({
+ 'serving directory index': {
+ topic : function(){
+ request.get(TEST_SERVER, this.callback);
+ },
+ 'should respond with 200' : function(error, response, body){
+ assert.equal(response.statusCode, 200);
+ },
+ 'should respond with text/html': function(error, response, body){
+ assert.equal(response.headers['content-type'], 'text/html');
+ }
+ }
+}).addBatch({
+ 'serving index.html from the cache': {
+ topic : function(){
+ request.get(TEST_SERVER + '/index.html', this.callback);
+ },
+ 'should respond with 200' : function(error, response, body){
+ assert.equal(response.statusCode, 200);
+ },
+ 'should respond with text/html': function(error, response, body){
+ assert.equal(response.headers['content-type'], 'text/html');
+ }
+ }
+}).addBatch({
+ 'requesting with If-None-Match': {
+ topic : function(){
+ var _this = this;
+ request.get(TEST_SERVER + '/index.html', function(error, response, body){
+ request({
+ method: 'GET',
+ uri: TEST_SERVER + '/index.html',
+ headers: {'if-none-match': response.headers['etag']}
+ },
+ _this.callback);
+ });
+ },
+ 'should respond with 304' : function(error, response, body){
+ assert.equal(response.statusCode, 304);
+ }
+ },
+ 'requesting with If-None-Match and If-Modified-Since': {
+ topic : function(){
+ var _this = this;
+ request.get(TEST_SERVER + '/index.html', function(error, response, body){
+ var modified = Date.parse(response.headers['last-modified']);
+ var oneDayLater = new Date(modified + (24 * 60 * 60 * 1000)).toUTCString();
+ var nonMatchingEtag = '1111222233334444';
+ request({
+ method: 'GET',
+ uri: TEST_SERVER + '/index.html',
+ headers: {
+ 'if-none-match': nonMatchingEtag,
+ 'if-modified-since': oneDayLater
+ }
+ },
+ _this.callback);
+ });
+ },
+ 'should respond with a 200': function(error, response, body){
+ assert.equal(response.statusCode, 200);
+ }
+ }
+})
+.addBatch({
+ 'requesting POST': {
+ topic : function(){
+ request.post(TEST_SERVER + '/index.html', this.callback);
+ },
+ 'should respond with 200' : function(error, response, body){
+ assert.equal(response.statusCode, 200);
+ },
+ 'should not be empty' : function(error, response, body){
+ assert.isNotEmpty(body);
+ }
+ }
+})
+.addBatch({
+ 'requesting HEAD': {
+ topic : function(){
+ request.head(TEST_SERVER + '/index.html', this.callback);
+ },
+ 'should respond with 200' : function(error, response, body){
+ assert.equal(response.statusCode, 200);
+ },
+ 'head must has no body' : function(error, response, body){
+ assert.isEmpty(body);
+ }
+ }
+})
+.addBatch(headers)
+.addBatch({
+ 'addings custom mime types': {
+ topic : function(){
+ static.mime.define({'application/font-woff': ['woff']});
+ this.callback();
+ },
+ 'should add woff' : function(error, response, body){
+ assert.equal(static.mime.lookup('woff'), 'application/font-woff');
+ }
+ }
+})
+.addBatch({
+ 'serving subdirectory index': {
+ topic : function(){
+ request.get(TEST_SERVER + '/there/', this.callback); // with trailing slash
+ },
+ 'should respond with 200' : function(error, response, body){
+ assert.equal(response.statusCode, 200);
+ },
+ 'should respond with text/html': function(error, response, body){
+ assert.equal(response.headers['content-type'], 'text/html');
+ }
+ }
+})
+.addBatch({
+ 'redirecting to subdirectory index': {
+ topic : function(){
+ request.get({ url: TEST_SERVER + '/there', followRedirect: false }, this.callback); // without trailing slash
+ },
+ 'should respond with 301' : function(error, response, body){
+ assert.equal(response.statusCode, 301);
+ },
+ 'should respond with location header': function(error, response, body){
+ assert.equal(response.headers['location'], '/there/'); // now with trailing slash
+ },
+ 'should respond with empty string body' : function(error, response, body){
+ assert.equal(body, '');
+ }
+ }
+})
+.addBatch({
+ 'requesting a subdirectory (with trailing slash) not found': {
+ topic : function(){
+ request.get(TEST_SERVER + '/notthere/', this.callback); // with trailing slash
+ },
+ 'should respond with 404' : function(error, response, body){
+ assert.equal(response.statusCode, 404);
+ }
+ }
+})
+.addBatch({
+ 'requesting a subdirectory (without trailing slash) not found': {
+ topic : function(){
+ request.get({ url: TEST_SERVER + '/notthere', followRedirect: false }, this.callback); // without trailing slash
+ },
+ 'should respond with 404' : function(error, response, body){
+ assert.equal(response.statusCode, 404);
+ }
+ }
+}).addBatch({
+ 'once an http server is listening with custom index configuration': {
+ topic: function () {
+ server.close();
+
+ fileServer = new static.Server(__dirname + '/../fixtures', { indexFile: "hello.txt" });
+
+ server = require('http').createServer(function (request, response) {
+ fileServer.serve(request, response);
+ }).listen(TEST_PORT, this.callback)
+ },
+ 'should be listening' : function(){
+ /* This test is necessary to ensure the topic execution.
+ * A topic without tests will be not executed */
+ assert.isTrue(true);
+ }
+ }
+}).addBatch({
+ 'serving custom index file': {
+ topic : function(){
+ request.get(TEST_SERVER + '/', this.callback);
+ },
+ 'should respond with 200' : function(error, response, body){
+ assert.equal(response.statusCode, 200);
+ },
+ 'should respond with empty string': function(error, response, body){
+ assert.equal(body, 'hello world');
+ }
+ }
+}).export(module);
+
--- /dev/null
+{
+ // JSHint Default Configuration File (as on JSHint website)
+ // See http://jshint.com/docs/ for more details
+
+ "maxerr" : 50, // {int} Maximum error before stopping
+
+ // Enforcing
+ "bitwise" : false, // true: Prohibit bitwise operators (&, |, ^, etc.)
+ "camelcase" : false, // true: Identifiers must be in camelCase
+ "curly" : true, // true: Require {} for every new block or scope
+ "eqeqeq" : true, // true: Require triple equals (===) for comparison
+ "freeze" : true, // true: prohibits overwriting prototypes of native objects such as Array, Date etc.
+ "forin" : false, // true: Require filtering for..in loops with obj.hasOwnProperty()
+ "immed" : true, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
+ "latedef" : "nofunc", // true: Require variables/functions to be defined before being used
+ "newcap" : true, // true: Require capitalization of all constructor functions e.g. `new F()`
+ "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
+ "noempty" : true, // true: Prohibit use of empty blocks
+ "nonbsp" : true, // true: Prohibit "non-breaking whitespace" characters.
+ "nonew" : true, // true: Prohibit use of constructors for side-effects (without assignment)
+ "plusplus" : false, // true: Prohibit use of `++` & `--`
+ "quotmark" : "single", // Quotation mark consistency:
+ // false : do nothing (default)
+ // true : ensure whatever is used is consistent
+ // "single" : require single quotes
+ // "double" : require double quotes
+ "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
+ "unused" : "vars", // vars: Require all defined variables be used, ignore function params
+ "strict" : false, // true: Requires all functions run in ES5 Strict Mode
+ "maxparams" : false, // {int} Max number of formal params allowed per function
+ "maxdepth" : false, // {int} Max depth of nested blocks (within functions)
+ "maxstatements" : false, // {int} Max number statements per function
+ "maxcomplexity" : false, // {int} Max cyclomatic complexity per function
+ "maxlen" : false, // {int} Max number of characters per line
+
+ // Relaxing
+ "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
+ "boss" : false, // true: Tolerate assignments where comparisons would be expected
+ "debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
+ "eqnull" : false, // true: Tolerate use of `== null`
+ "es5" : false, // true: Allow ES5 syntax (ex: getters and setters)
+ "esnext" : true, // true: Allow ES.next (ES6) syntax (ex: `const`)
+ "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
+ // (ex: `for each`, multiple try/catch, function expression…)
+ "evil" : false, // true: Tolerate use of `eval` and `new Function()`
+ "expr" : false, // true: Tolerate `ExpressionStatement` as Programs
+ "funcscope" : false, // true: Tolerate defining variables inside control statements
+ "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
+ "iterator" : false, // true: Tolerate using the `__iterator__` property
+ "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
+ "laxbreak" : false, // true: Tolerate possibly unsafe line breakings
+ "laxcomma" : false, // true: Tolerate comma-first style coding
+ "loopfunc" : false, // true: Tolerate functions being defined in loops
+ "multistr" : false, // true: Tolerate multi-line strings
+ "noyield" : false, // true: Tolerate generator functions with no yield statement in them.
+ "notypeof" : false, // true: Tolerate invalid typeof operator values
+ "proto" : false, // true: Tolerate using the `__proto__` property
+ "scripturl" : false, // true: Tolerate script-targeted URLs
+ "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
+ "sub" : true, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
+ "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
+ "validthis" : false, // true: Tolerate using this in a non-constructor function
+
+ // Environments
+ "browser" : true, // Web Browser (window, document, etc)
+ "browserify" : true, // Browserify (node.js code in the browser)
+ "couch" : false, // CouchDB
+ "devel" : true, // Development/debugging (alert, confirm, etc)
+ "dojo" : false, // Dojo Toolkit
+ "jasmine" : false, // Jasmine
+ "jquery" : false, // jQuery
+ "mocha" : false, // Mocha
+ "mootools" : false, // MooTools
+ "node" : true, // Node.js
+ "nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
+ "prototypejs" : false, // Prototype and Scriptaculous
+ "qunit" : false, // QUnit
+ "rhino" : false, // Rhino
+ "shelljs" : false, // ShellJS
+ "worker" : false, // Web Workers
+ "wsh" : false, // Windows Scripting Host
+ "yui" : false, // Yahoo User Interface
+
+ // Custom Globals
+ "globals" : { // additional predefined global variables
+ "WebSocket": true
+ }
+}
--- /dev/null
+Changelog
+=========
+
+Version 1.0.30
+--------------
+*Released 2019-09-12*
+
+* Moved gulp back to devDependencies
+
+Version 1.0.29
+--------------
+*Released 2019-07-03*
+
+* Updated some dependencies and updated the .gitignore and .npmignore files
+
+Version 1.0.28
+--------------
+*Released 2018-09-19*
+
+* Updated to latest version of [nan](https://github.com/nodejs/nan)
+
+Version 1.0.27
+--------------
+*Released 2018-09-19*
+
+* Allowing additional request `headers` to be specified in the `tlsOptions` config parameter for WebSocketClient. See pull request #323
+* Resolving deprecation warnings relating to usage of `new Buffer`
+
+Version 1.0.26
+--------------
+*Released 2018-04-27*
+
+* No longer using the deprecated `noAssert` parameter for functions reading and writing binary numeric data. (Thanks, [@BridgeAR](https://github.com/BridgeAR))
+
+Version 1.0.25
+--------------
+*Released 2017-10-18*
+
+* Bumping minimum supported node version specified in package.json to v0.10.x because some upstream libraries no longer install on v0.8.x
+* [Allowing use of close codes 1012, 1013, 1014](https://www.iana.org/assignments/websocket/websocket.xml)
+* [Allowing the `Host` header to be overridden.](https://github.com/theturtle32/WebSocket-Node/pull/291) (Thanks, [@Juneil](https://github.com/Juneil))
+* [Mitigating infinite loop for broken connections](https://github.com/theturtle32/WebSocket-Node/pull/289) (Thanks, [@tvkit](https://github.com/tvkit))
+* [Fixed Markdown Typos](https://github.com/theturtle32/WebSocket-Node/pull/281) (Thanks, [@teramotodaiki](https://github.com/teramotodaiki))
+* [Adding old readyState constants for W3CWebSocket interface](https://github.com/theturtle32/WebSocket-Node/pull/282) (Thanks, [@thechriswalker](https://github.com/thechriswalker))
+
+
+Version 1.0.24
+--------------
+*Released 2016-12-28*
+
+* Fixed a bug when using native keepalive on Node >= 6.0. (Thanks, [@prossin](https://github.com/prossin))
+* Upgrading outdated dependencies
+
+Version 1.0.23
+--------------
+*Released 2016-05-18*
+
+* Official support for Node 6.x
+* Updating dependencies. Specifically, updating nan to ^2.3.3
+
+Version 1.0.22
+--------------
+*Released 2015-09-28*
+
+* Updating to work with nan 2.x
+
+Version 1.0.21
+--------------
+*Released 2015-07-22*
+
+* Incremented and re-published to work around an aborted npm publish of v1.0.20.
+
+Version 1.0.20
+--------------
+*Released 2015-07-22*
+
+* Added EventTarget to the W3CWebSocket interface (Thanks, [@ibc](https://github.com/ibc)!)
+* Corrected an inaccurate error message. (Thanks, [@lekoaf](https://github.com/lekoaf)!)
+
+Version 1.0.19
+--------------
+*Released 2015-05-28*
+
+* Updated to nan v1.8.x (tested with v1.8.4)
+* Added `"license": "Apache-2.0"` to package.json via [pull request #199](https://github.com/theturtle32/WebSocket-Node/pull/199) by [@pgilad](https://github.com/pgilad). See [npm1k.org](http://npm1k.org/).
+
+
+Version 1.0.18
+--------------
+*Released 2015-03-19*
+
+* Resolves [issue #195](https://github.com/theturtle32/WebSocket-Node/pull/179) - passing number to connection.send() causes crash
+* [Added close code/reason arguments to W3CWebSocket#close()](https://github.com/theturtle32/WebSocket-Node/issues/184)
+
+
+Version 1.0.17
+--------------
+*Released 2015-01-17*
+
+* Resolves [issue #179](https://github.com/theturtle32/WebSocket-Node/pull/179) - Allow toBuffer to work with empty data
+
+
+Version 1.0.16
+--------------
+*Released 2015-01-16*
+
+* Resolves [issue #178](https://github.com/theturtle32/WebSocket-Node/issues/178) - Ping Frames with no data
+
+
+Version 1.0.15
+--------------
+*Released 2015-01-13*
+
+* Resolves [issue #177](https://github.com/theturtle32/WebSocket-Node/issues/177) - WebSocketClient ignores options unless it has a tlsOptions property
+
+
+Version 1.0.14
+--------------
+*Released 2014-12-03*
+
+* Resolves [issue #173](https://github.com/theturtle32/WebSocket-Node/issues/173) - To allow the W3CWebSocket interface to accept an optional non-standard configuration object as its third parameter, which will be ignored when running in a browser context.
+
+
+Version 1.0.13
+--------------
+*Released 2014-11-29*
+
+* Fixes [issue #171](https://github.com/theturtle32/WebSocket-Node/issues/171) - Code to prevent calling req.accept/req.reject multiple times breaks sanity checks in req.accept
+
+
+Version 1.0.12
+--------------
+*Released 2014-11-28*
+
+* Fixes [issue #170](https://github.com/theturtle32/WebSocket-Node/issues/170) - Non-native XOR implementation broken after making JSHint happy
+
+
+Version 1.0.11
+--------------
+*Released 2014-11-25*
+
+* Fixes some undefined behavior surrounding closing WebSocket connections and more reliably handles edge cases.
+* Adds an implementation of the W3C WebSocket API for browsers to facilitate sharing code between client and server via browserify. (Thanks, [@ibc](https://github.com/ibc)!)
+* `WebSocketConnection.prototype.close` now accepts optional `reasonCode` and `description` parameters.
+* Calling `accept` or `reject` more than once on a `WebSocketRequest` will now throw an error. [Issue #149](https://github.com/theturtle32/WebSocket-Node/issues/149)
+* Handling connections dropped by client before accepted by server [Issue #167](https://github.com/theturtle32/WebSocket-Node/issues/167)
+* Integrating Gulp and JSHint (Thanks, [@ibc](https://github.com/ibc)!)
+* Starting to add individual unit tests (using substack's [tape](github.com/substack/tape) and [faucet](github.com/substack/faucet))
+
+
+Version 1.0.10
+--------------
+*Released 2014-10-22*
+
+* Fixed Issue [#146](https://github.com/theturtle32/WebSocket-Node/issues/146) that was causing WebSocketClient to throw errors when instantiated if passed `tlsOptions`.
+
+Version 1.0.9
+-------------
+*Released 2014-10-20*
+
+* Fixing an insidious corner-case bug that prevented `WebSocketConnection` from firing the `close` event in certain cases when there was an error on the underlying `Socket`, leading to connections sticking around forever, stuck erroneously in the `connected` state. These "ghost" connections would cause an error event when trying to write to them.
+* Removed deprecated `websocketVersion` property. Use `webSocketVersion` instead (case difference).
+* Allowing user to specify all properties for `tlsOptions` in WebSocketClient, not just a few whitelisted properties. This keeps us from having to constantly add new config properties for new versions of Node. (Thanks, [jesusprubio](https://github.com/jesusprubio))
+* Removing support for Node 0.4.x and 0.6.x.
+* Adding `fuzzingclient.json` spec file for the Autobahn Test Suite.
+* Now more fairly emitting `message` events from the `WebSocketConnection`. Previously, all buffered frames for a connection would be processed and all `message` events emitted before moving on to processing the next connection with available data. Now We process one frame per connection (most of the time) in a more fair round-robin fashion.
+* Now correctly calling the `EventEmitter` superclass constructor during class instance initialization.
+* `WebSocketClient.prototype.connect` now accepts the empty string (`''`) to mean "no subprotocol requested." Previously either `null` or an empty array (`[]`) was required.
+* Fixing a `TypeError` bug in `WebSocketRouter` (Thanks, [a0000778](https://github.com/a0000778))
+* Fixing a potential race condition when attaching event listeners to the underlying `Socket`. (Thanks [RichardBsolut](https://github.com/RichardBsolut))
+* `WebSocketClient` now accepts an optional options hash to be passed to `(http|https).request`. (Thanks [mildred](https://github.com/mildred) and [aus](https://github.com/aus)) This enables the following new abilities, amongst others:
+ * Use WebSocket-Node from behind HTTP/HTTPS proxy servers using [koichik/node-tunnel](https://github.com/koichik/node-tunnel) or similar.
+ * Specify the local port and local address to bind the outgoing request socket to.
+* Adding option to ignore `X-Forwarded-For` headers when accepting connections from untrusted clients.
+* Adding ability to mount a `WebSocketServer` instance to an arbitrary number of Node http/https servers.
+* Adding browser shim so Browserify won't blow up when trying to package up code that uses WebSocket-Node. The shim is a no-op, it ***does not implement a wrapper*** providing the WebSocket-Node API in the browser.
+* Incorporating upstream enhancements for the native C++ UTF-8 validation and xor masking functions. (Thanks [einaros](https://github.com/einaros) and [kkoopa](https://github.com/kkoopa))
+
+
+Version 1.0.8
+-------------
+*Released 2012-12-26*
+
+* Fixed remaining naming inconsistency of "websocketVersion" as opposed to "webSocketVersion" throughout the code, and added deprecation warnings for use of the old casing throughout.
+* Fixed an issue with our case-insensitive handling of WebSocket subprotocols. Clients that requested a mixed-case subprotocol would end up failing the connection when the server accepted the connection, returning a lower-case version of the subprotocol name. Now we return the subprotocol name in the exact casing that was requested by the client, while still maintaining the case-insensitive verification logic for convenience and practicality.
+* Making sure that any socket-level activity timeout that may have been set on a TCP socket is removed when initializing a connection.
+* Added support for native TCP Keep-Alive instead of using the WebSocket ping/pong packets to serve that function.
+* Fixed cookie parsing to be compliant with RFC 2109
+
+Version 1.0.7
+-------------
+*Released 2012-08-12*
+
+* ***Native modules are now optional!*** If they fail to compile, WebSocket-Node will still work but will not verify that received UTF-8 data is valid, and xor masking/unmasking of payload data for security purposes will not be as efficient as it is performed in JavaScript instead of native code.
+* Reduced Node.JS version requirement back to v0.6.10
+
+Version 1.0.6
+-------------
+*Released 2012-05-22*
+
+* Now requires Node v0.6.13 since that's the first version that I can manage to successfully build the native UTF-8 validator with node-gyp through npm.
+
+Version 1.0.5
+-------------
+*Released 2012-05-21*
+
+* Fixes the issues that users were having building the native UTF-8 validator on Windows platforms. Special Thanks to:
+ * [zerodivisi0n](https://github.com/zerodivisi0n)
+ * [andreasbotsikas](https://github.com/andreasbotsikas)
+* Fixed accidental global variable usage (Thanks, [hakobera](https://github.com/hakobera)!)
+* Added callbacks to the send* methods that provide notification of messages being sent on the wire and any socket errors that may occur when sending a message. (Thanks, [zerodivisi0n](https://github.com/zerodivisi0n)!)
+* Added option to disable logging in the echo-server in the test folder (Thanks, [oberstet](https://github.com/oberstet)!)
+
+
+Version 1.0.4
+-------------
+*Released 2011-12-18*
+
+* Now validates that incoming UTF-8 messages do, in fact, contain valid UTF-8 data. The connection is dropped with prejudice if invalid data is received. This strict behavior conforms to the WebSocket RFC and is verified by the Autobahn Test Suite. This is accomplished in a performant way by using a native C++ Node module created by [einaros](https://github.com/einaros).
+* Updated handling of connection closure to pass more of the Autobahn Test Suite.
+
+Version 1.0.3
+-------------
+*Released 2011-12-18*
+
+* Substantial speed increase (~150% on my machine, depending on the circumstances) due to an optimization in FastBufferList.js that drastically reduces the number of memory alloctions and buffer copying. ([kazuyukitanimura](https://github.com/kazuyukitanimura))
+
+
+Version 1.0.2
+-------------
+*Released 2011-11-28*
+
+* Fixing whiteboard example to work under Node 0.6.x ([theturtle32](https://github.com/theturtle32))
+* Now correctly emitting a `close` event with a 1006 error code if there is a TCP error while writing to the socket during the handshake. ([theturtle32](https://github.com/theturtle32))
+* Catching errors when writing to the TCP socket during the handshake. ([justoneplanet](https://github.com/justoneplanet))
+* No longer outputting console.warn messages when there is an error writing to the TCP socket ([justoneplanet](https://github.com/justoneplanet))
+* Fixing some formatting errors, commas, semicolons, etc. ([kaisellgren](https://github.com/kaisellgren))
+
+
+Version 1.0.1
+-------------
+*Released 2011-11-21*
+
+* Now works with Node 0.6.2 as well as 0.4.12
+* Support TLS in WebSocketClient
+* Added support for setting and reading cookies
+* Added WebSocketServer.prototype.broadcast(data) convenience method
+* Added `resourceURL` property to WebSocketRequest objects. It is a Node URL object with the `resource` and any query string params already parsed.
+* The WebSocket request router no longer includes the entire query string when trying to match the path name of the request.
+* WebSocketRouterRequest objects now include all the properties and events of WebSocketRequest objects.
+* Removed more console.log statements. Please rely on the various events emitted to be notified of error conditions. I decided that it is not a library's place to spew information to the console.
+* Renamed the `websocketVersion` property to `webSocketVersion` throughout the code to fix inconsistent capitalization. `websocketVersion` has been kept for compatibility but is deprecated and may be removed in the future.
+* Now outputting the sanitized version of custom header names rather than the raw value. This prevents invalid HTTP from being put onto the wire if given an illegal header name.
+
+
+I decided it's time to start maintaining a changelog now, starting with version 1.0.1.
--- /dev/null
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
--- /dev/null
+all:
+ node-gyp configure build
+
+clean:
+ node-gyp clean
+
+autobahn:
+ @NODE_PATH=lib node test/autobahn-test-client.js --host=127.0.0.1 --port=9000
+
+autobahn-server:
+ @NODE_PATH=lib node test/echo-server.js
--- /dev/null
+WebSocket Client & Server Implementation for Node
+=================================================
+
+[![npm version](https://badge.fury.io/js/websocket.svg)](http://badge.fury.io/js/websocket)
+
+[![NPM Downloads](https://img.shields.io/npm/dm/websocket.svg)](https://www.npmjs.com/package/websocket)
+
+[![NPM](https://nodei.co/npm/websocket.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/websocket/)
+
+[![NPM](https://nodei.co/npm-dl/websocket.png?height=3)](https://nodei.co/npm/websocket/)
+
+[ ![Codeship Status for theturtle32/WebSocket-Node](https://codeship.com/projects/70458270-8ee7-0132-7756-0a0cf4fe8e66/status?branch=master)](https://codeship.com/projects/61106)
+
+Overview
+--------
+This is a (mostly) pure JavaScript implementation of the WebSocket protocol versions 8 and 13 for Node. There are some example client and server applications that implement various interoperability testing protocols in the "test/scripts" folder.
+
+For a WebSocket client written in ActionScript 3, see my [AS3WebScocket](https://github.com/theturtle32/AS3WebSocket) project.
+
+
+Documentation
+=============
+
+[You can read the full API documentation in the docs folder.](docs/index.md)
+
+
+Changelog
+---------
+
+***Current Version: 1.0.30*** — Released 2019-09-12
+
+* Moved gulp back to devDependencies
+
+[View the full changelog](CHANGELOG.md)
+
+Browser Support
+---------------
+
+All current browsers are fully supported.
+
+* Firefox 7-9 (Old) (Protocol Version 8)
+* Firefox 10+ (Protocol Version 13)
+* Chrome 14,15 (Old) (Protocol Version 8)
+* Chrome 16+ (Protocol Version 13)
+* Internet Explorer 10+ (Protocol Version 13)
+* Safari 6+ (Protocol Version 13)
+
+***Safari older than 6.0 is not supported since it uses a very old draft of WebSockets***
+
+***If you need to simultaneously support legacy browser versions that had implemented draft-75/draft-76/draft-00, take a look here: https://gist.github.com/1428579***
+
+Benchmarks
+----------
+There are some basic benchmarking sections in the Autobahn test suite. I've put up a [benchmark page](http://theturtle32.github.com/WebSocket-Node/benchmarks/) that shows the results from the Autobahn tests run against AutobahnServer 0.4.10, WebSocket-Node 1.0.2, WebSocket-Node 1.0.4, and ws 0.3.4.
+
+Autobahn Tests
+--------------
+The very complete [Autobahn Test Suite](http://autobahn.ws/testsuite/) is used by most WebSocket implementations to test spec compliance and interoperability.
+
+- [View Server Test Results](http://theturtle32.github.com/WebSocket-Node/test-report/servers/)
+
+Installation
+------------
+
+A few users have reported difficulties building the native extensions without first manually installing node-gyp. If you have trouble building the native extensions, make sure you've got a C++ compiler, and have done `npm install -g node-gyp` first.
+
+Native extensions are optional, however, and WebSocket-Node will work even if the extensions cannot be compiled.
+
+In your project root:
+
+ $ npm install websocket
+
+Then in your code:
+
+```javascript
+var WebSocketServer = require('websocket').server;
+var WebSocketClient = require('websocket').client;
+var WebSocketFrame = require('websocket').frame;
+var WebSocketRouter = require('websocket').router;
+var W3CWebSocket = require('websocket').w3cwebsocket;
+```
+
+Note for Windows Users
+----------------------
+Because there is a small C++ component used for validating UTF-8 data, you will need to install a few other software packages in addition to Node to be able to build this module:
+
+- [Microsoft Visual C++](http://www.microsoft.com/visualstudio/en-us/products/2010-editions/visual-cpp-express)
+- [Python 2.7](http://www.python.org/download/) (NOT Python 3.x)
+
+
+Current Features:
+-----------------
+- Licensed under the Apache License, Version 2.0
+- Protocol version "8" and "13" (Draft-08 through the final RFC) framing and handshake
+- Can handle/aggregate received fragmented messages
+- Can fragment outgoing messages
+- Router to mount multiple applications to various path and protocol combinations
+- TLS supported for outbound connections via WebSocketClient
+- TLS supported for server connections (use https.createServer instead of http.createServer)
+ - Thanks to [pors](https://github.com/pors) for confirming this!
+- Cookie setting and parsing
+- Tunable settings
+ - Max Receivable Frame Size
+ - Max Aggregate ReceivedMessage Size
+ - Whether to fragment outgoing messages
+ - Fragmentation chunk size for outgoing messages
+ - Whether to automatically send ping frames for the purposes of keepalive
+ - Keep-alive ping interval
+ - Whether or not to automatically assemble received fragments (allows application to handle individual fragments directly)
+ - How long to wait after sending a close frame for acknowledgment before closing the socket.
+- [W3C WebSocket API](http://www.w3.org/TR/websockets/) for applications running on both Node and browsers (via the `W3CWebSocket` class).
+
+
+Known Issues/Missing Features:
+------------------------------
+- No API for user-provided protocol extensions.
+
+
+Usage Examples
+==============
+
+Server Example
+--------------
+
+Here's a short example showing a server that echos back anything sent to it, whether utf-8 or binary.
+
+```javascript
+#!/usr/bin/env node
+var WebSocketServer = require('websocket').server;
+var http = require('http');
+
+var server = http.createServer(function(request, response) {
+ console.log((new Date()) + ' Received request for ' + request.url);
+ response.writeHead(404);
+ response.end();
+});
+server.listen(8080, function() {
+ console.log((new Date()) + ' Server is listening on port 8080');
+});
+
+wsServer = new WebSocketServer({
+ httpServer: server,
+ // You should not use autoAcceptConnections for production
+ // applications, as it defeats all standard cross-origin protection
+ // facilities built into the protocol and the browser. You should
+ // *always* verify the connection's origin and decide whether or not
+ // to accept it.
+ autoAcceptConnections: false
+});
+
+function originIsAllowed(origin) {
+ // put logic here to detect whether the specified origin is allowed.
+ return true;
+}
+
+wsServer.on('request', function(request) {
+ if (!originIsAllowed(request.origin)) {
+ // Make sure we only accept requests from an allowed origin
+ request.reject();
+ console.log((new Date()) + ' Connection from origin ' + request.origin + ' rejected.');
+ return;
+ }
+
+ var connection = request.accept('echo-protocol', request.origin);
+ console.log((new Date()) + ' Connection accepted.');
+ connection.on('message', function(message) {
+ if (message.type === 'utf8') {
+ console.log('Received Message: ' + message.utf8Data);
+ connection.sendUTF(message.utf8Data);
+ }
+ else if (message.type === 'binary') {
+ console.log('Received Binary Message of ' + message.binaryData.length + ' bytes');
+ connection.sendBytes(message.binaryData);
+ }
+ });
+ connection.on('close', function(reasonCode, description) {
+ console.log((new Date()) + ' Peer ' + connection.remoteAddress + ' disconnected.');
+ });
+});
+```
+
+Client Example
+--------------
+
+This is a simple example client that will print out any utf-8 messages it receives on the console, and periodically sends a random number.
+
+*This code demonstrates a client in Node.js, not in the browser*
+
+```javascript
+#!/usr/bin/env node
+var WebSocketClient = require('websocket').client;
+
+var client = new WebSocketClient();
+
+client.on('connectFailed', function(error) {
+ console.log('Connect Error: ' + error.toString());
+});
+
+client.on('connect', function(connection) {
+ console.log('WebSocket Client Connected');
+ connection.on('error', function(error) {
+ console.log("Connection Error: " + error.toString());
+ });
+ connection.on('close', function() {
+ console.log('echo-protocol Connection Closed');
+ });
+ connection.on('message', function(message) {
+ if (message.type === 'utf8') {
+ console.log("Received: '" + message.utf8Data + "'");
+ }
+ });
+
+ function sendNumber() {
+ if (connection.connected) {
+ var number = Math.round(Math.random() * 0xFFFFFF);
+ connection.sendUTF(number.toString());
+ setTimeout(sendNumber, 1000);
+ }
+ }
+ sendNumber();
+});
+
+client.connect('ws://localhost:8080/', 'echo-protocol');
+```
+
+Client Example using the *W3C WebSocket API*
+--------------------------------------------
+
+Same example as above but using the [W3C WebSocket API](http://www.w3.org/TR/websockets/).
+
+```javascript
+var W3CWebSocket = require('websocket').w3cwebsocket;
+
+var client = new W3CWebSocket('ws://localhost:8080/', 'echo-protocol');
+
+client.onerror = function() {
+ console.log('Connection Error');
+};
+
+client.onopen = function() {
+ console.log('WebSocket Client Connected');
+
+ function sendNumber() {
+ if (client.readyState === client.OPEN) {
+ var number = Math.round(Math.random() * 0xFFFFFF);
+ client.send(number.toString());
+ setTimeout(sendNumber, 1000);
+ }
+ }
+ sendNumber();
+};
+
+client.onclose = function() {
+ console.log('echo-protocol Client Closed');
+};
+
+client.onmessage = function(e) {
+ if (typeof e.data === 'string') {
+ console.log("Received: '" + e.data + "'");
+ }
+};
+```
+
+Request Router Example
+----------------------
+
+For an example of using the request router, see `libwebsockets-test-server.js` in the `test` folder.
+
+
+Resources
+---------
+
+A presentation on the state of the WebSockets protocol that I gave on July 23, 2011 at the LA Hacker News meetup. [WebSockets: The Real-Time Web, Delivered](http://www.scribd.com/doc/60898569/WebSockets-The-Real-Time-Web-Delivered)
--- /dev/null
+{
+ 'targets': [
+ {
+ 'target_name': 'validation',
+ 'include_dirs': ["<!(node -e \"require('nan')\")"],
+ 'cflags!': [ '-O3' ],
+ 'cflags': [ '-O2' ],
+ 'sources': [ 'src/validation.cc' ]
+ },
+ {
+ 'target_name': 'bufferutil',
+ 'include_dirs': ["<!(node -e \"require('nan')\")"],
+ 'cflags!': [ '-O3' ],
+ 'cflags': [ '-O2' ],
+ 'sources': [ 'src/bufferutil.cc' ]
+ }
+ ]
+}
--- /dev/null
+# We borrow heavily from the kernel build setup, though we are simpler since
+# we don't have Kconfig tweaking settings on us.
+
+# The implicit make rules have it looking for RCS files, among other things.
+# We instead explicitly write all the rules we care about.
+# It's even quicker (saves ~200ms) to pass -r on the command line.
+MAKEFLAGS=-r
+
+# The source directory tree.
+srcdir := ..
+abs_srcdir := $(abspath $(srcdir))
+
+# The name of the builddir.
+builddir_name ?= .
+
+# The V=1 flag on command line makes us verbosely print command lines.
+ifdef V
+ quiet=
+else
+ quiet=quiet_
+endif
+
+# Specify BUILDTYPE=Release on the command line for a release build.
+BUILDTYPE ?= Release
+
+# Directory all our build output goes into.
+# Note that this must be two directories beneath src/ for unit tests to pass,
+# as they reach into the src/ directory for data with relative paths.
+builddir ?= $(builddir_name)/$(BUILDTYPE)
+abs_builddir := $(abspath $(builddir))
+depsdir := $(builddir)/.deps
+
+# Object output directory.
+obj := $(builddir)/obj
+abs_obj := $(abspath $(obj))
+
+# We build up a list of every single one of the targets so we can slurp in the
+# generated dependency rule Makefiles in one pass.
+all_deps :=
+
+
+
+CC.target ?= $(CC)
+CFLAGS.target ?= $(CFLAGS)
+CXX.target ?= $(CXX)
+CXXFLAGS.target ?= $(CXXFLAGS) $(CPPFLAGS)
+LINK.target ?= $(LINK)
+LDFLAGS.target ?= $(LDFLAGS)
+AR.target ?= $(AR)
+
+# C++ apps need to be linked with g++.
+LINK ?= $(CXX.target)
+
+# TODO(evan): move all cross-compilation logic to gyp-time so we don't need
+# to replicate this environment fallback in make as well.
+CC.host ?= gcc
+CFLAGS.host ?=
+CXX.host ?= g++
+CXXFLAGS.host ?=
+LINK.host ?= $(CXX.host)
+LDFLAGS.host ?=
+AR.host ?= ar
+
+# Define a dir function that can handle spaces.
+# http://www.gnu.org/software/make/manual/make.html#Syntax-of-Functions
+# "leading spaces cannot appear in the text of the first argument as written.
+# These characters can be put into the argument value by variable substitution."
+empty :=
+space := $(empty) $(empty)
+
+# http://stackoverflow.com/questions/1189781/using-make-dir-or-notdir-on-a-path-with-spaces
+replace_spaces = $(subst $(space),?,$1)
+unreplace_spaces = $(subst ?,$(space),$1)
+dirx = $(call unreplace_spaces,$(dir $(call replace_spaces,$1)))
+
+# Flags to make gcc output dependency info. Note that you need to be
+# careful here to use the flags that ccache and distcc can understand.
+# We write to a dep file on the side first and then rename at the end
+# so we can't end up with a broken dep file.
+depfile = $(depsdir)/$(call replace_spaces,$@).d
+DEPFLAGS = -MMD -MF $(depfile).raw
+
+# We have to fixup the deps output in a few ways.
+# (1) the file output should mention the proper .o file.
+# ccache or distcc lose the path to the target, so we convert a rule of
+# the form:
+# foobar.o: DEP1 DEP2
+# into
+# path/to/foobar.o: DEP1 DEP2
+# (2) we want missing files not to cause us to fail to build.
+# We want to rewrite
+# foobar.o: DEP1 DEP2 \
+# DEP3
+# to
+# DEP1:
+# DEP2:
+# DEP3:
+# so if the files are missing, they're just considered phony rules.
+# We have to do some pretty insane escaping to get those backslashes
+# and dollar signs past make, the shell, and sed at the same time.
+# Doesn't work with spaces, but that's fine: .d files have spaces in
+# their names replaced with other characters.
+define fixup_dep
+# The depfile may not exist if the input file didn't have any #includes.
+touch $(depfile).raw
+# Fixup path as in (1).
+sed -e "s|^$(notdir $@)|$@|" $(depfile).raw >> $(depfile)
+# Add extra rules as in (2).
+# We remove slashes and replace spaces with new lines;
+# remove blank lines;
+# delete the first line and append a colon to the remaining lines.
+sed -e 's|\\||' -e 'y| |\n|' $(depfile).raw |\
+ grep -v '^$$' |\
+ sed -e 1d -e 's|$$|:|' \
+ >> $(depfile)
+rm $(depfile).raw
+endef
+
+# Command definitions:
+# - cmd_foo is the actual command to run;
+# - quiet_cmd_foo is the brief-output summary of the command.
+
+quiet_cmd_cc = CC($(TOOLSET)) $@
+cmd_cc = $(CC.$(TOOLSET)) $(GYP_CFLAGS) $(DEPFLAGS) $(CFLAGS.$(TOOLSET)) -c -o $@ $<
+
+quiet_cmd_cxx = CXX($(TOOLSET)) $@
+cmd_cxx = $(CXX.$(TOOLSET)) $(GYP_CXXFLAGS) $(DEPFLAGS) $(CXXFLAGS.$(TOOLSET)) -c -o $@ $<
+
+quiet_cmd_touch = TOUCH $@
+cmd_touch = touch $@
+
+quiet_cmd_copy = COPY $@
+# send stderr to /dev/null to ignore messages when linking directories.
+cmd_copy = ln -f "$<" "$@" 2>/dev/null || (rm -rf "$@" && cp -af "$<" "$@")
+
+quiet_cmd_alink = AR($(TOOLSET)) $@
+cmd_alink = rm -f $@ && $(AR.$(TOOLSET)) crs $@ $(filter %.o,$^)
+
+quiet_cmd_alink_thin = AR($(TOOLSET)) $@
+cmd_alink_thin = rm -f $@ && $(AR.$(TOOLSET)) crsT $@ $(filter %.o,$^)
+
+# Due to circular dependencies between libraries :(, we wrap the
+# special "figure out circular dependencies" flags around the entire
+# input list during linking.
+quiet_cmd_link = LINK($(TOOLSET)) $@
+cmd_link = $(LINK.$(TOOLSET)) $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -o $@ -Wl,--start-group $(LD_INPUTS) -Wl,--end-group $(LIBS)
+
+# We support two kinds of shared objects (.so):
+# 1) shared_library, which is just bundling together many dependent libraries
+# into a link line.
+# 2) loadable_module, which is generating a module intended for dlopen().
+#
+# They differ only slightly:
+# In the former case, we want to package all dependent code into the .so.
+# In the latter case, we want to package just the API exposed by the
+# outermost module.
+# This means shared_library uses --whole-archive, while loadable_module doesn't.
+# (Note that --whole-archive is incompatible with the --start-group used in
+# normal linking.)
+
+# Other shared-object link notes:
+# - Set SONAME to the library filename so our binaries don't reference
+# the local, absolute paths used on the link command-line.
+quiet_cmd_solink = SOLINK($(TOOLSET)) $@
+cmd_solink = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--whole-archive $(LD_INPUTS) -Wl,--no-whole-archive $(LIBS)
+
+quiet_cmd_solink_module = SOLINK_MODULE($(TOOLSET)) $@
+cmd_solink_module = $(LINK.$(TOOLSET)) -shared $(GYP_LDFLAGS) $(LDFLAGS.$(TOOLSET)) -Wl,-soname=$(@F) -o $@ -Wl,--start-group $(filter-out FORCE_DO_CMD, $^) -Wl,--end-group $(LIBS)
+
+
+# Define an escape_quotes function to escape single quotes.
+# This allows us to handle quotes properly as long as we always use
+# use single quotes and escape_quotes.
+escape_quotes = $(subst ','\'',$(1))
+# This comment is here just to include a ' to unconfuse syntax highlighting.
+# Define an escape_vars function to escape '$' variable syntax.
+# This allows us to read/write command lines with shell variables (e.g.
+# $LD_LIBRARY_PATH), without triggering make substitution.
+escape_vars = $(subst $$,$$$$,$(1))
+# Helper that expands to a shell command to echo a string exactly as it is in
+# make. This uses printf instead of echo because printf's behaviour with respect
+# to escape sequences is more portable than echo's across different shells
+# (e.g., dash, bash).
+exact_echo = printf '%s\n' '$(call escape_quotes,$(1))'
+
+# Helper to compare the command we're about to run against the command
+# we logged the last time we ran the command. Produces an empty
+# string (false) when the commands match.
+# Tricky point: Make has no string-equality test function.
+# The kernel uses the following, but it seems like it would have false
+# positives, where one string reordered its arguments.
+# arg_check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
+# $(filter-out $(cmd_$@), $(cmd_$(1))))
+# We instead substitute each for the empty string into the other, and
+# say they're equal if both substitutions produce the empty string.
+# .d files contain ? instead of spaces, take that into account.
+command_changed = $(or $(subst $(cmd_$(1)),,$(cmd_$(call replace_spaces,$@))),\
+ $(subst $(cmd_$(call replace_spaces,$@)),,$(cmd_$(1))))
+
+# Helper that is non-empty when a prerequisite changes.
+# Normally make does this implicitly, but we force rules to always run
+# so we can check their command lines.
+# $? -- new prerequisites
+# $| -- order-only dependencies
+prereq_changed = $(filter-out FORCE_DO_CMD,$(filter-out $|,$?))
+
+# Helper that executes all postbuilds until one fails.
+define do_postbuilds
+ @E=0;\
+ for p in $(POSTBUILDS); do\
+ eval $$p;\
+ E=$$?;\
+ if [ $$E -ne 0 ]; then\
+ break;\
+ fi;\
+ done;\
+ if [ $$E -ne 0 ]; then\
+ rm -rf "$@";\
+ exit $$E;\
+ fi
+endef
+
+# do_cmd: run a command via the above cmd_foo names, if necessary.
+# Should always run for a given target to handle command-line changes.
+# Second argument, if non-zero, makes it do asm/C/C++ dependency munging.
+# Third argument, if non-zero, makes it do POSTBUILDS processing.
+# Note: We intentionally do NOT call dirx for depfile, since it contains ? for
+# spaces already and dirx strips the ? characters.
+define do_cmd
+$(if $(or $(command_changed),$(prereq_changed)),
+ @$(call exact_echo, $($(quiet)cmd_$(1)))
+ @mkdir -p "$(call dirx,$@)" "$(dir $(depfile))"
+ $(if $(findstring flock,$(word 1,$(cmd_$1))),
+ @$(cmd_$(1))
+ @echo " $(quiet_cmd_$(1)): Finished",
+ @$(cmd_$(1))
+ )
+ @$(call exact_echo,$(call escape_vars,cmd_$(call replace_spaces,$@) := $(cmd_$(1)))) > $(depfile)
+ @$(if $(2),$(fixup_dep))
+ $(if $(and $(3), $(POSTBUILDS)),
+ $(call do_postbuilds)
+ )
+)
+endef
+
+# Declare the "all" target first so it is the default,
+# even though we don't have the deps yet.
+.PHONY: all
+all:
+
+# make looks for ways to re-generate included makefiles, but in our case, we
+# don't have a direct way. Explicitly telling make that it has nothing to do
+# for them makes it go faster.
+%.d: ;
+
+# Use FORCE_DO_CMD to force a target to run. Should be coupled with
+# do_cmd.
+.PHONY: FORCE_DO_CMD
+FORCE_DO_CMD:
+
+TOOLSET := target
+# Suffix rules, putting all outputs into $(obj).
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(srcdir)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+# Try building from generated source, too.
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj).$(TOOLSET)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+$(obj).$(TOOLSET)/%.o: $(obj)/%.c FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cpp FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.cxx FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.S FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+$(obj).$(TOOLSET)/%.o: $(obj)/%.s FORCE_DO_CMD
+ @$(call do_cmd,cc,1)
+
+
+ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
+ $(findstring $(join ^,$(prefix)),\
+ $(join ^,bufferutil.target.mk)))),)
+ include bufferutil.target.mk
+endif
+ifeq ($(strip $(foreach prefix,$(NO_LOAD),\
+ $(findstring $(join ^,$(prefix)),\
+ $(join ^,validation.target.mk)))),)
+ include validation.target.mk
+endif
+
+quiet_cmd_regen_makefile = ACTION Regenerating $@
+cmd_regen_makefile = cd $(srcdir); /usr/share/node-gyp/gyp/gyp_main.py -fmake --ignore-environment "--toplevel-dir=." -I/home/pi/VSoRC/node_modules/websocket/build/config.gypi -I/usr/share/node-gyp/addon.gypi -I/usr/include/nodejs/common.gypi "--depth=." "-Goutput_dir=." "--generator-output=build" "-Dlibrary=shared_library" "-Dvisibility=default" "-Dnode_root_dir=/usr/include/nodejs" "-Dnode_gyp_dir=/usr/share/node-gyp" "-Dnode_lib_file=node.lib" "-Dmodule_root_dir=/home/pi/VSoRC/node_modules/websocket" binding.gyp
+Makefile: $(srcdir)/../../../../../usr/include/nodejs/common.gypi $(srcdir)/build/config.gypi $(srcdir)/binding.gyp $(srcdir)/../../../../../usr/share/node-gyp/addon.gypi
+ $(call do_cmd,regen_makefile)
+
+# "all" is a concatenation of the "all" targets from all the included
+# sub-makefiles. This is just here to clarify.
+all:
+
+# Add in dependency-tracking rules. $(all_deps) is the list of every single
+# target in our tree. Only consider the ones with .d (dependency) info:
+d_files := $(wildcard $(foreach f,$(all_deps),$(depsdir)/$(f).d))
+ifneq ($(d_files),)
+ include $(d_files)
+endif
--- /dev/null
+cmd_Release/bufferutil.node := ln -f "Release/obj.target/bufferutil.node" "Release/bufferutil.node" 2>/dev/null || (rm -rf "Release/bufferutil.node" && cp -af "Release/obj.target/bufferutil.node" "Release/bufferutil.node")
--- /dev/null
+cmd_Release/obj.target/bufferutil.node := g++ -shared -pthread -rdynamic -Wl,-soname=bufferutil.node -o Release/obj.target/bufferutil.node -Wl,--start-group Release/obj.target/bufferutil/src/bufferutil.o -Wl,--end-group
--- /dev/null
+cmd_Release/obj.target/bufferutil/src/bufferutil.o := g++ '-DNODE_GYP_MODULE_NAME=bufferutil' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/include/node -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -O2 -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++0x -MMD -MF ./Release/.deps/Release/obj.target/bufferutil/src/bufferutil.o.d.raw -c -o Release/obj.target/bufferutil/src/bufferutil.o ../src/bufferutil.cc
+Release/obj.target/bufferutil/src/bufferutil.o: ../src/bufferutil.cc \
+ /usr/include/nodejs/deps/v8/include/v8.h \
+ /usr/include/nodejs/deps/v8/include/v8-version.h \
+ /usr/include/nodejs/deps/v8/include/v8config.h \
+ /usr/include/nodejs/src/node.h /usr/include/nodejs/src/node_version.h \
+ /usr/include/nodejs/src/node_version.h \
+ /usr/include/nodejs/src/node_buffer.h /usr/include/nodejs/src/node.h \
+ /usr/include/nodejs/src/node_object_wrap.h ../node_modules/nan/nan.h \
+ /usr/include/nodejs/deps/uv/include/uv.h \
+ /usr/include/nodejs/deps/uv/include/uv-errno.h \
+ /usr/include/nodejs/deps/uv/include/uv-version.h \
+ /usr/include/nodejs/deps/uv/include/uv-unix.h \
+ /usr/include/nodejs/deps/uv/include/uv-threadpool.h \
+ /usr/include/nodejs/deps/uv/include/uv-linux.h \
+ ../node_modules/nan/nan_callbacks.h \
+ ../node_modules/nan/nan_callbacks_12_inl.h \
+ ../node_modules/nan/nan_maybe_43_inl.h \
+ ../node_modules/nan/nan_converters.h \
+ ../node_modules/nan/nan_converters_43_inl.h \
+ ../node_modules/nan/nan_new.h \
+ ../node_modules/nan/nan_implementation_12_inl.h \
+ ../node_modules/nan/nan_persistent_12_inl.h \
+ ../node_modules/nan/nan_weak.h ../node_modules/nan/nan_object_wrap.h \
+ ../node_modules/nan/nan_private.h \
+ ../node_modules/nan/nan_typedarray_contents.h \
+ ../node_modules/nan/nan_json.h
+../src/bufferutil.cc:
+/usr/include/nodejs/deps/v8/include/v8.h:
+/usr/include/nodejs/deps/v8/include/v8-version.h:
+/usr/include/nodejs/deps/v8/include/v8config.h:
+/usr/include/nodejs/src/node.h:
+/usr/include/nodejs/src/node_version.h:
+/usr/include/nodejs/src/node_version.h:
+/usr/include/nodejs/src/node_buffer.h:
+/usr/include/nodejs/src/node.h:
+/usr/include/nodejs/src/node_object_wrap.h:
+../node_modules/nan/nan.h:
+/usr/include/nodejs/deps/uv/include/uv.h:
+/usr/include/nodejs/deps/uv/include/uv-errno.h:
+/usr/include/nodejs/deps/uv/include/uv-version.h:
+/usr/include/nodejs/deps/uv/include/uv-unix.h:
+/usr/include/nodejs/deps/uv/include/uv-threadpool.h:
+/usr/include/nodejs/deps/uv/include/uv-linux.h:
+../node_modules/nan/nan_callbacks.h:
+../node_modules/nan/nan_callbacks_12_inl.h:
+../node_modules/nan/nan_maybe_43_inl.h:
+../node_modules/nan/nan_converters.h:
+../node_modules/nan/nan_converters_43_inl.h:
+../node_modules/nan/nan_new.h:
+../node_modules/nan/nan_implementation_12_inl.h:
+../node_modules/nan/nan_persistent_12_inl.h:
+../node_modules/nan/nan_weak.h:
+../node_modules/nan/nan_object_wrap.h:
+../node_modules/nan/nan_private.h:
+../node_modules/nan/nan_typedarray_contents.h:
+../node_modules/nan/nan_json.h:
--- /dev/null
+cmd_Release/obj.target/validation.node := g++ -shared -pthread -rdynamic -Wl,-soname=validation.node -o Release/obj.target/validation.node -Wl,--start-group Release/obj.target/validation/src/validation.o -Wl,--end-group
--- /dev/null
+cmd_Release/obj.target/validation/src/validation.o := g++ '-DNODE_GYP_MODULE_NAME=validation' '-DUSING_UV_SHARED=1' '-DUSING_V8_SHARED=1' '-DV8_DEPRECATION_WARNINGS=1' '-D_LARGEFILE_SOURCE' '-D_FILE_OFFSET_BITS=64' '-DBUILDING_NODE_EXTENSION' -I/usr/include/nodejs/include/node -I/usr/include/nodejs/src -I/usr/include/nodejs/deps/uv/include -I/usr/include/nodejs/deps/v8/include -I../node_modules/nan -fPIC -pthread -Wall -Wextra -Wno-unused-parameter -O2 -fno-omit-frame-pointer -fno-rtti -fno-exceptions -std=gnu++0x -MMD -MF ./Release/.deps/Release/obj.target/validation/src/validation.o.d.raw -c -o Release/obj.target/validation/src/validation.o ../src/validation.cc
+Release/obj.target/validation/src/validation.o: ../src/validation.cc \
+ /usr/include/nodejs/deps/v8/include/v8.h \
+ /usr/include/nodejs/deps/v8/include/v8-version.h \
+ /usr/include/nodejs/deps/v8/include/v8config.h \
+ /usr/include/nodejs/src/node.h /usr/include/nodejs/src/node_version.h \
+ /usr/include/nodejs/src/node_version.h \
+ /usr/include/nodejs/src/node_buffer.h /usr/include/nodejs/src/node.h \
+ /usr/include/nodejs/src/node_object_wrap.h ../node_modules/nan/nan.h \
+ /usr/include/nodejs/deps/uv/include/uv.h \
+ /usr/include/nodejs/deps/uv/include/uv-errno.h \
+ /usr/include/nodejs/deps/uv/include/uv-version.h \
+ /usr/include/nodejs/deps/uv/include/uv-unix.h \
+ /usr/include/nodejs/deps/uv/include/uv-threadpool.h \
+ /usr/include/nodejs/deps/uv/include/uv-linux.h \
+ ../node_modules/nan/nan_callbacks.h \
+ ../node_modules/nan/nan_callbacks_12_inl.h \
+ ../node_modules/nan/nan_maybe_43_inl.h \
+ ../node_modules/nan/nan_converters.h \
+ ../node_modules/nan/nan_converters_43_inl.h \
+ ../node_modules/nan/nan_new.h \
+ ../node_modules/nan/nan_implementation_12_inl.h \
+ ../node_modules/nan/nan_persistent_12_inl.h \
+ ../node_modules/nan/nan_weak.h ../node_modules/nan/nan_object_wrap.h \
+ ../node_modules/nan/nan_private.h \
+ ../node_modules/nan/nan_typedarray_contents.h \
+ ../node_modules/nan/nan_json.h
+../src/validation.cc:
+/usr/include/nodejs/deps/v8/include/v8.h:
+/usr/include/nodejs/deps/v8/include/v8-version.h:
+/usr/include/nodejs/deps/v8/include/v8config.h:
+/usr/include/nodejs/src/node.h:
+/usr/include/nodejs/src/node_version.h:
+/usr/include/nodejs/src/node_version.h:
+/usr/include/nodejs/src/node_buffer.h:
+/usr/include/nodejs/src/node.h:
+/usr/include/nodejs/src/node_object_wrap.h:
+../node_modules/nan/nan.h:
+/usr/include/nodejs/deps/uv/include/uv.h:
+/usr/include/nodejs/deps/uv/include/uv-errno.h:
+/usr/include/nodejs/deps/uv/include/uv-version.h:
+/usr/include/nodejs/deps/uv/include/uv-unix.h:
+/usr/include/nodejs/deps/uv/include/uv-threadpool.h:
+/usr/include/nodejs/deps/uv/include/uv-linux.h:
+../node_modules/nan/nan_callbacks.h:
+../node_modules/nan/nan_callbacks_12_inl.h:
+../node_modules/nan/nan_maybe_43_inl.h:
+../node_modules/nan/nan_converters.h:
+../node_modules/nan/nan_converters_43_inl.h:
+../node_modules/nan/nan_new.h:
+../node_modules/nan/nan_implementation_12_inl.h:
+../node_modules/nan/nan_persistent_12_inl.h:
+../node_modules/nan/nan_weak.h:
+../node_modules/nan/nan_object_wrap.h:
+../node_modules/nan/nan_private.h:
+../node_modules/nan/nan_typedarray_contents.h:
+../node_modules/nan/nan_json.h:
--- /dev/null
+cmd_Release/validation.node := ln -f "Release/obj.target/validation.node" "Release/validation.node" 2>/dev/null || (rm -rf "Release/validation.node" && cp -af "Release/obj.target/validation.node" "Release/validation.node")
--- /dev/null
+# This file is generated by gyp; do not edit.
+
+export builddir_name ?= ./build/.
+.PHONY: all
+all:
+ $(MAKE) bufferutil validation
--- /dev/null
+# This file is generated by gyp; do not edit.
+
+TOOLSET := target
+TARGET := bufferutil
+DEFS_Debug := \
+ '-DNODE_GYP_MODULE_NAME=bufferutil' \
+ '-DUSING_UV_SHARED=1' \
+ '-DUSING_V8_SHARED=1' \
+ '-DV8_DEPRECATION_WARNINGS=1' \
+ '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DBUILDING_NODE_EXTENSION' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DV8_ENABLE_CHECKS'
+
+# Flags passed to all source files.
+CFLAGS_Debug := \
+ -fPIC \
+ -pthread \
+ -Wall \
+ -Wextra \
+ -Wno-unused-parameter \
+ -O2 \
+ -g \
+ -O0
+
+# Flags passed to only C files.
+CFLAGS_C_Debug :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Debug := \
+ -fno-rtti \
+ -fno-exceptions \
+ -std=gnu++0x
+
+INCS_Debug := \
+ -I/usr/include/nodejs/include/node \
+ -I/usr/include/nodejs/src \
+ -I/usr/include/nodejs/deps/uv/include \
+ -I/usr/include/nodejs/deps/v8/include \
+ -I$(srcdir)/node_modules/nan
+
+DEFS_Release := \
+ '-DNODE_GYP_MODULE_NAME=bufferutil' \
+ '-DUSING_UV_SHARED=1' \
+ '-DUSING_V8_SHARED=1' \
+ '-DV8_DEPRECATION_WARNINGS=1' \
+ '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DBUILDING_NODE_EXTENSION'
+
+# Flags passed to all source files.
+CFLAGS_Release := \
+ -fPIC \
+ -pthread \
+ -Wall \
+ -Wextra \
+ -Wno-unused-parameter \
+ -O2 \
+ -fno-omit-frame-pointer
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := \
+ -fno-rtti \
+ -fno-exceptions \
+ -std=gnu++0x
+
+INCS_Release := \
+ -I/usr/include/nodejs/include/node \
+ -I/usr/include/nodejs/src \
+ -I/usr/include/nodejs/deps/uv/include \
+ -I/usr/include/nodejs/deps/v8/include \
+ -I$(srcdir)/node_modules/nan
+
+OBJS := \
+ $(obj).target/$(TARGET)/src/bufferutil.o
+
+# Add to the list of files we specially track dependencies for.
+all_deps += $(OBJS)
+
+# CFLAGS et al overrides must be target-local.
+# See "Target-specific Variable Values" in the GNU Make manual.
+$(OBJS): TOOLSET := $(TOOLSET)
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+
+# Suffix rules, putting all outputs into $(obj).
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+# Try building from generated source, too.
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+# End of this set of suffix rules
+### Rules for final target.
+LDFLAGS_Debug := \
+ -pthread \
+ -rdynamic
+
+LDFLAGS_Release := \
+ -pthread \
+ -rdynamic
+
+LIBS :=
+
+$(obj).target/bufferutil.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
+$(obj).target/bufferutil.node: LIBS := $(LIBS)
+$(obj).target/bufferutil.node: TOOLSET := $(TOOLSET)
+$(obj).target/bufferutil.node: $(OBJS) FORCE_DO_CMD
+ $(call do_cmd,solink_module)
+
+all_deps += $(obj).target/bufferutil.node
+# Add target alias
+.PHONY: bufferutil
+bufferutil: $(builddir)/bufferutil.node
+
+# Copy this to the executable output path.
+$(builddir)/bufferutil.node: TOOLSET := $(TOOLSET)
+$(builddir)/bufferutil.node: $(obj).target/bufferutil.node FORCE_DO_CMD
+ $(call do_cmd,copy)
+
+all_deps += $(builddir)/bufferutil.node
+# Short alias for building this executable.
+.PHONY: bufferutil.node
+bufferutil.node: $(obj).target/bufferutil.node $(builddir)/bufferutil.node
+
+# Add executable to "all" target.
+.PHONY: all
+all: $(builddir)/bufferutil.node
+
--- /dev/null
+# Do not edit. File was generated by node-gyp's "configure" step
+{
+ "target_defaults": {
+ "cflags": [],
+ "default_configuration": "Release",
+ "defines": [],
+ "include_dirs": [],
+ "libraries": []
+ },
+ "variables": {
+ "arm_float_abi": "hard",
+ "arm_fpu": "vfp",
+ "arm_thumb": 0,
+ "arm_version": "6",
+ "asan": 0,
+ "coverage": "false",
+ "debug_devtools": "node",
+ "debug_http2": "false",
+ "debug_nghttp2": "false",
+ "force_dynamic_crt": 0,
+ "host_arch": "arm",
+ "icu_gyp_path": "tools/icu/icu-system.gyp",
+ "icu_small": "false",
+ "llvm_version": 0,
+ "node_byteorder": "little",
+ "node_enable_d8": "false",
+ "node_enable_v8_vtunejit": "false",
+ "node_install_npm": "false",
+ "node_module_version": 57,
+ "node_no_browser_globals": "false",
+ "node_prefix": "/usr",
+ "node_release_urlbase": "",
+ "node_shared": "false",
+ "node_shared_cares": "true",
+ "node_shared_http_parser": "true",
+ "node_shared_libuv": "true",
+ "node_shared_nghttp2": "false",
+ "node_shared_openssl": "true",
+ "node_shared_zlib": "true",
+ "node_tag": "",
+ "node_use_bundled_v8": "true",
+ "node_use_dtrace": "false",
+ "node_use_etw": "false",
+ "node_use_lttng": "false",
+ "node_use_openssl": "true",
+ "node_use_perfctr": "false",
+ "node_use_v8_platform": "true",
+ "node_without_node_options": "false",
+ "openssl_fips": "",
+ "openssl_no_asm": 0,
+ "shlib_suffix": "so.57",
+ "target_arch": "arm",
+ "uv_parent_path": "/deps/uv/",
+ "uv_use_dtrace": "false",
+ "v8_enable_gdbjit": 0,
+ "v8_enable_i18n_support": 1,
+ "v8_enable_inspector": 1,
+ "v8_no_strict_aliasing": 1,
+ "v8_optimized_debug": 0,
+ "v8_promise_internal_field_count": 1,
+ "v8_random_seed": 0,
+ "v8_trace_maps": 0,
+ "v8_use_snapshot": "false",
+ "want_separate_host_toolset": 0,
+ "nodedir": "/usr/include/nodejs",
+ "copy_dev_lib": "true",
+ "standalone_static_library": 1,
+ "cache_lock_stale": "60000",
+ "sign_git_tag": "",
+ "user_agent": "npm/1.4.21 node/v8.11.1 linux arm",
+ "always_auth": "",
+ "bin_links": "true",
+ "key": "",
+ "description": "true",
+ "fetch_retries": "2",
+ "heading": "npm",
+ "user": "",
+ "force": "",
+ "cache_min": "10",
+ "init_license": "ISC",
+ "editor": "vi",
+ "rollback": "true",
+ "cache_max": "Infinity",
+ "userconfig": "/home/pi/.npmrc",
+ "engine_strict": "",
+ "init_author_name": "",
+ "init_author_url": "",
+ "tmp": "/tmp",
+ "depth": "Infinity",
+ "save_dev": "",
+ "usage": "",
+ "https_proxy": "",
+ "onload_script": "",
+ "rebuild_bundle": "true",
+ "save_bundle": "",
+ "shell": "/bin/bash",
+ "prefix": "/usr/local",
+ "registry": "https://registry.npmjs.org/",
+ "__DO_NOT_MODIFY_THIS_FILE___use__etc_npmrc_instead_": "true",
+ "browser": "",
+ "cache_lock_wait": "10000",
+ "save_optional": "",
+ "searchopts": "",
+ "versions": "",
+ "cache": "/home/pi/.npm",
+ "ignore_scripts": "",
+ "searchsort": "name",
+ "version": "",
+ "local_address": "",
+ "viewer": "man",
+ "color": "true",
+ "fetch_retry_mintimeout": "10000",
+ "umask": "18",
+ "fetch_retry_maxtimeout": "60000",
+ "message": "%s",
+ "ca": "",
+ "cert": "",
+ "global": "",
+ "link": "",
+ "save": "",
+ "unicode": "true",
+ "long": "",
+ "production": "",
+ "unsafe_perm": "true",
+ "node_version": "8.11.1",
+ "tag": "latest",
+ "git_tag_version": "true",
+ "shrinkwrap": "true",
+ "fetch_retry_factor": "10",
+ "npat": "",
+ "proprietary_attribs": "true",
+ "save_exact": "",
+ "strict_ssl": "true",
+ "username": "",
+ "globalconfig": "/etc/npmrc",
+ "dev": "",
+ "init_module": "/home/pi/.npm-init.js",
+ "parseable": "",
+ "globalignorefile": "/etc/npmignore",
+ "cache_lock_retries": "10",
+ "save_prefix": "^",
+ "group": "1000",
+ "init_author_email": "",
+ "searchexclude": "",
+ "git": "git",
+ "optional": "true",
+ "email": "",
+ "json": "",
+ "spin": "true"
+ }
+}
--- /dev/null
+# This file is generated by gyp; do not edit.
+
+TOOLSET := target
+TARGET := validation
+DEFS_Debug := \
+ '-DNODE_GYP_MODULE_NAME=validation' \
+ '-DUSING_UV_SHARED=1' \
+ '-DUSING_V8_SHARED=1' \
+ '-DV8_DEPRECATION_WARNINGS=1' \
+ '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DBUILDING_NODE_EXTENSION' \
+ '-DDEBUG' \
+ '-D_DEBUG' \
+ '-DV8_ENABLE_CHECKS'
+
+# Flags passed to all source files.
+CFLAGS_Debug := \
+ -fPIC \
+ -pthread \
+ -Wall \
+ -Wextra \
+ -Wno-unused-parameter \
+ -O2 \
+ -g \
+ -O0
+
+# Flags passed to only C files.
+CFLAGS_C_Debug :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Debug := \
+ -fno-rtti \
+ -fno-exceptions \
+ -std=gnu++0x
+
+INCS_Debug := \
+ -I/usr/include/nodejs/include/node \
+ -I/usr/include/nodejs/src \
+ -I/usr/include/nodejs/deps/uv/include \
+ -I/usr/include/nodejs/deps/v8/include \
+ -I$(srcdir)/node_modules/nan
+
+DEFS_Release := \
+ '-DNODE_GYP_MODULE_NAME=validation' \
+ '-DUSING_UV_SHARED=1' \
+ '-DUSING_V8_SHARED=1' \
+ '-DV8_DEPRECATION_WARNINGS=1' \
+ '-D_LARGEFILE_SOURCE' \
+ '-D_FILE_OFFSET_BITS=64' \
+ '-DBUILDING_NODE_EXTENSION'
+
+# Flags passed to all source files.
+CFLAGS_Release := \
+ -fPIC \
+ -pthread \
+ -Wall \
+ -Wextra \
+ -Wno-unused-parameter \
+ -O2 \
+ -fno-omit-frame-pointer
+
+# Flags passed to only C files.
+CFLAGS_C_Release :=
+
+# Flags passed to only C++ files.
+CFLAGS_CC_Release := \
+ -fno-rtti \
+ -fno-exceptions \
+ -std=gnu++0x
+
+INCS_Release := \
+ -I/usr/include/nodejs/include/node \
+ -I/usr/include/nodejs/src \
+ -I/usr/include/nodejs/deps/uv/include \
+ -I/usr/include/nodejs/deps/v8/include \
+ -I$(srcdir)/node_modules/nan
+
+OBJS := \
+ $(obj).target/$(TARGET)/src/validation.o
+
+# Add to the list of files we specially track dependencies for.
+all_deps += $(OBJS)
+
+# CFLAGS et al overrides must be target-local.
+# See "Target-specific Variable Values" in the GNU Make manual.
+$(OBJS): TOOLSET := $(TOOLSET)
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE)) $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
+
+# Suffix rules, putting all outputs into $(obj).
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+# Try building from generated source, too.
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
+ @$(call do_cmd,cxx,1)
+
+# End of this set of suffix rules
+### Rules for final target.
+LDFLAGS_Debug := \
+ -pthread \
+ -rdynamic
+
+LDFLAGS_Release := \
+ -pthread \
+ -rdynamic
+
+LIBS :=
+
+$(obj).target/validation.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
+$(obj).target/validation.node: LIBS := $(LIBS)
+$(obj).target/validation.node: TOOLSET := $(TOOLSET)
+$(obj).target/validation.node: $(OBJS) FORCE_DO_CMD
+ $(call do_cmd,solink_module)
+
+all_deps += $(obj).target/validation.node
+# Add target alias
+.PHONY: validation
+validation: $(builddir)/validation.node
+
+# Copy this to the executable output path.
+$(builddir)/validation.node: TOOLSET := $(TOOLSET)
+$(builddir)/validation.node: $(obj).target/validation.node FORCE_DO_CMD
+ $(call do_cmd,copy)
+
+all_deps += $(builddir)/validation.node
+# Short alias for building this executable.
+.PHONY: validation.node
+validation.node: $(obj).target/validation.node $(builddir)/validation.node
+
+# Add executable to "all" target.
+.PHONY: all
+all: $(builddir)/validation.node
+
--- /dev/null
+/**
+ * Dependencies.
+ */
+var gulp = require('gulp');
+var jshint = require('gulp-jshint');
+
+gulp.task('lint', function() {
+ return gulp.src(['gulpfile.js', 'lib/**/*.js', 'test/**/*.js'])
+ .pipe(jshint('.jshintrc'))
+ .pipe(jshint.reporter('jshint-stylish', {verbose: true}))
+ .pipe(jshint.reporter('fail'));
+});
+
+gulp.task('default', gulp.series('lint'));
--- /dev/null
+module.exports = require('./lib/websocket');
\ No newline at end of file
--- /dev/null
+/*!
+ * Copied from:
+ * ws: a node.js websocket client
+ * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+ * MIT Licensed
+ */
+
+/* jshint -W086 */
+
+module.exports.BufferUtil = {
+ merge: function(mergedBuffer, buffers) {
+ var offset = 0;
+ for (var i = 0, l = buffers.length; i < l; ++i) {
+ var buf = buffers[i];
+ buf.copy(mergedBuffer, offset);
+ offset += buf.length;
+ }
+ },
+ mask: function(source, mask, output, offset, length) {
+ var maskNum = mask.readUInt32LE(0);
+ var i = 0;
+ for (; i < length - 3; i += 4) {
+ var num = maskNum ^ source.readUInt32LE(i);
+ if (num < 0) { num = 4294967296 + num; }
+ output.writeUInt32LE(num, offset + i);
+ }
+ switch (length % 4) {
+ case 3: output[offset + i + 2] = source[i + 2] ^ mask[2];
+ case 2: output[offset + i + 1] = source[i + 1] ^ mask[1];
+ case 1: output[offset + i] = source[i] ^ mask[0];
+ case 0:
+ }
+ },
+ unmask: function(data, mask) {
+ var maskNum = mask.readUInt32LE(0);
+ var length = data.length;
+ var i = 0;
+ for (; i < length - 3; i += 4) {
+ var num = maskNum ^ data.readUInt32LE(i);
+ if (num < 0) { num = 4294967296 + num; }
+ data.writeUInt32LE(num, i);
+ }
+ switch (length % 4) {
+ case 3: data[i + 2] = data[i + 2] ^ mask[2];
+ case 2: data[i + 1] = data[i + 1] ^ mask[1];
+ case 1: data[i] = data[i] ^ mask[0];
+ case 0:
+ }
+ }
+};
+
+/* jshint +W086 */
\ No newline at end of file
--- /dev/null
+/*!
+ * Copied from:
+ * ws: a node.js websocket client
+ * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+ * MIT Licensed
+ */
+
+try {
+ module.exports = require('../build/Release/bufferutil');
+} catch (e) { try {
+ module.exports = require('../build/default/bufferutil');
+} catch (e) { try {
+ module.exports = require('./BufferUtil.fallback');
+} catch (e) {
+ console.error('bufferutil.node seems to not have been built. Run npm install.');
+ throw e;
+}}}
--- /dev/null
+/************************************************************************
+ * Copyright 2010-2015 Brian McKelvey.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+
+var Deprecation = {
+ disableWarnings: false,
+
+ deprecationWarningMap: {
+
+ },
+
+ warn: function(deprecationName) {
+ if (!this.disableWarnings && this.deprecationWarningMap[deprecationName]) {
+ console.warn('DEPRECATION WARNING: ' + this.deprecationWarningMap[deprecationName]);
+ this.deprecationWarningMap[deprecationName] = false;
+ }
+ }
+};
+
+module.exports = Deprecation;
--- /dev/null
+/*!
+ * UTF-8 Validation Fallback Code originally from:
+ * ws: a node.js websocket client
+ * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+ * MIT Licensed
+ */
+
+module.exports.Validation = {
+ isValidUTF8: function() {
+ return true;
+ }
+};
--- /dev/null
+/*!
+ * UTF-8 Validation Code originally from:
+ * ws: a node.js websocket client
+ * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+ * MIT Licensed
+ */
+
+try {
+ module.exports = require('../build/Release/validation');
+} catch (e) { try {
+ module.exports = require('../build/default/validation');
+} catch (e) { try {
+ module.exports = require('./Validation.fallback');
+} catch (e) {
+ console.error('validation.node seems not to have been built. Run npm install.');
+ throw e;
+}}}
--- /dev/null
+/************************************************************************
+ * Copyright 2010-2015 Brian McKelvey.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+
+var WebSocketClient = require('./WebSocketClient');
+var toBuffer = require('typedarray-to-buffer');
+var yaeti = require('yaeti');
+
+
+const CONNECTING = 0;
+const OPEN = 1;
+const CLOSING = 2;
+const CLOSED = 3;
+
+
+module.exports = W3CWebSocket;
+
+
+function W3CWebSocket(url, protocols, origin, headers, requestOptions, clientConfig) {
+ // Make this an EventTarget.
+ yaeti.EventTarget.call(this);
+
+ // Sanitize clientConfig.
+ clientConfig = clientConfig || {};
+ clientConfig.assembleFragments = true; // Required in the W3C API.
+
+ var self = this;
+
+ this._url = url;
+ this._readyState = CONNECTING;
+ this._protocol = undefined;
+ this._extensions = '';
+ this._bufferedAmount = 0; // Hack, always 0.
+ this._binaryType = 'arraybuffer'; // TODO: Should be 'blob' by default, but Node has no Blob.
+
+ // The WebSocketConnection instance.
+ this._connection = undefined;
+
+ // WebSocketClient instance.
+ this._client = new WebSocketClient(clientConfig);
+
+ this._client.on('connect', function(connection) {
+ onConnect.call(self, connection);
+ });
+
+ this._client.on('connectFailed', function() {
+ onConnectFailed.call(self);
+ });
+
+ this._client.connect(url, protocols, origin, headers, requestOptions);
+}
+
+
+// Expose W3C read only attributes.
+Object.defineProperties(W3CWebSocket.prototype, {
+ url: { get: function() { return this._url; } },
+ readyState: { get: function() { return this._readyState; } },
+ protocol: { get: function() { return this._protocol; } },
+ extensions: { get: function() { return this._extensions; } },
+ bufferedAmount: { get: function() { return this._bufferedAmount; } }
+});
+
+
+// Expose W3C write/read attributes.
+Object.defineProperties(W3CWebSocket.prototype, {
+ binaryType: {
+ get: function() {
+ return this._binaryType;
+ },
+ set: function(type) {
+ // TODO: Just 'arraybuffer' supported.
+ if (type !== 'arraybuffer') {
+ throw new SyntaxError('just "arraybuffer" type allowed for "binaryType" attribute');
+ }
+ this._binaryType = type;
+ }
+ }
+});
+
+
+// Expose W3C readyState constants into the WebSocket instance as W3C states.
+[['CONNECTING',CONNECTING], ['OPEN',OPEN], ['CLOSING',CLOSING], ['CLOSED',CLOSED]].forEach(function(property) {
+ Object.defineProperty(W3CWebSocket.prototype, property[0], {
+ get: function() { return property[1]; }
+ });
+});
+
+// Also expose W3C readyState constants into the WebSocket class (not defined by the W3C,
+// but there are so many libs relying on them).
+[['CONNECTING',CONNECTING], ['OPEN',OPEN], ['CLOSING',CLOSING], ['CLOSED',CLOSED]].forEach(function(property) {
+ Object.defineProperty(W3CWebSocket, property[0], {
+ get: function() { return property[1]; }
+ });
+});
+
+
+W3CWebSocket.prototype.send = function(data) {
+ if (this._readyState !== OPEN) {
+ throw new Error('cannot call send() while not connected');
+ }
+
+ // Text.
+ if (typeof data === 'string' || data instanceof String) {
+ this._connection.sendUTF(data);
+ }
+ // Binary.
+ else {
+ // Node Buffer.
+ if (data instanceof Buffer) {
+ this._connection.sendBytes(data);
+ }
+ // If ArrayBuffer or ArrayBufferView convert it to Node Buffer.
+ else if (data.byteLength || data.byteLength === 0) {
+ data = toBuffer(data);
+ this._connection.sendBytes(data);
+ }
+ else {
+ throw new Error('unknown binary data:', data);
+ }
+ }
+};
+
+
+W3CWebSocket.prototype.close = function(code, reason) {
+ switch(this._readyState) {
+ case CONNECTING:
+ // NOTE: We don't have the WebSocketConnection instance yet so no
+ // way to close the TCP connection.
+ // Artificially invoke the onConnectFailed event.
+ onConnectFailed.call(this);
+ // And close if it connects after a while.
+ this._client.on('connect', function(connection) {
+ if (code) {
+ connection.close(code, reason);
+ } else {
+ connection.close();
+ }
+ });
+ break;
+ case OPEN:
+ this._readyState = CLOSING;
+ if (code) {
+ this._connection.close(code, reason);
+ } else {
+ this._connection.close();
+ }
+ break;
+ case CLOSING:
+ case CLOSED:
+ break;
+ }
+};
+
+
+/**
+ * Private API.
+ */
+
+
+function createCloseEvent(code, reason) {
+ var event = new yaeti.Event('close');
+
+ event.code = code;
+ event.reason = reason;
+ event.wasClean = (typeof code === 'undefined' || code === 1000);
+
+ return event;
+}
+
+
+function createMessageEvent(data) {
+ var event = new yaeti.Event('message');
+
+ event.data = data;
+
+ return event;
+}
+
+
+function onConnect(connection) {
+ var self = this;
+
+ this._readyState = OPEN;
+ this._connection = connection;
+ this._protocol = connection.protocol;
+ this._extensions = connection.extensions;
+
+ this._connection.on('close', function(code, reason) {
+ onClose.call(self, code, reason);
+ });
+
+ this._connection.on('message', function(msg) {
+ onMessage.call(self, msg);
+ });
+
+ this.dispatchEvent(new yaeti.Event('open'));
+}
+
+
+function onConnectFailed() {
+ destroy.call(this);
+ this._readyState = CLOSED;
+
+ try {
+ this.dispatchEvent(new yaeti.Event('error'));
+ } finally {
+ this.dispatchEvent(createCloseEvent(1006, 'connection failed'));
+ }
+}
+
+
+function onClose(code, reason) {
+ destroy.call(this);
+ this._readyState = CLOSED;
+
+ this.dispatchEvent(createCloseEvent(code, reason || ''));
+}
+
+
+function onMessage(message) {
+ if (message.utf8Data) {
+ this.dispatchEvent(createMessageEvent(message.utf8Data));
+ }
+ else if (message.binaryData) {
+ // Must convert from Node Buffer to ArrayBuffer.
+ // TODO: or to a Blob (which does not exist in Node!).
+ if (this.binaryType === 'arraybuffer') {
+ var buffer = message.binaryData;
+ var arraybuffer = new ArrayBuffer(buffer.length);
+ var view = new Uint8Array(arraybuffer);
+ for (var i=0, len=buffer.length; i<len; ++i) {
+ view[i] = buffer[i];
+ }
+ this.dispatchEvent(createMessageEvent(arraybuffer));
+ }
+ }
+}
+
+
+function destroy() {
+ this._client.removeAllListeners();
+ if (this._connection) {
+ this._connection.removeAllListeners();
+ }
+}
--- /dev/null
+/************************************************************************
+ * Copyright 2010-2015 Brian McKelvey.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+
+var utils = require('./utils');
+var extend = utils.extend;
+var util = require('util');
+var EventEmitter = require('events').EventEmitter;
+var http = require('http');
+var https = require('https');
+var url = require('url');
+var crypto = require('crypto');
+var WebSocketConnection = require('./WebSocketConnection');
+var bufferAllocUnsafe = utils.bufferAllocUnsafe;
+
+var protocolSeparators = [
+ '(', ')', '<', '>', '@',
+ ',', ';', ':', '\\', '\"',
+ '/', '[', ']', '?', '=',
+ '{', '}', ' ', String.fromCharCode(9)
+];
+
+var excludedTlsOptions = ['hostname','port','method','path','headers'];
+
+function WebSocketClient(config) {
+ // Superclass Constructor
+ EventEmitter.call(this);
+
+ // TODO: Implement extensions
+
+ this.config = {
+ // 1MiB max frame size.
+ maxReceivedFrameSize: 0x100000,
+
+ // 8MiB max message size, only applicable if
+ // assembleFragments is true
+ maxReceivedMessageSize: 0x800000,
+
+ // Outgoing messages larger than fragmentationThreshold will be
+ // split into multiple fragments.
+ fragmentOutgoingMessages: true,
+
+ // Outgoing frames are fragmented if they exceed this threshold.
+ // Default is 16KiB
+ fragmentationThreshold: 0x4000,
+
+ // Which version of the protocol to use for this session. This
+ // option will be removed once the protocol is finalized by the IETF
+ // It is only available to ease the transition through the
+ // intermediate draft protocol versions.
+ // At present, it only affects the name of the Origin header.
+ webSocketVersion: 13,
+
+ // If true, fragmented messages will be automatically assembled
+ // and the full message will be emitted via a 'message' event.
+ // If false, each frame will be emitted via a 'frame' event and
+ // the application will be responsible for aggregating multiple
+ // fragmented frames. Single-frame messages will emit a 'message'
+ // event in addition to the 'frame' event.
+ // Most users will want to leave this set to 'true'
+ assembleFragments: true,
+
+ // The Nagle Algorithm makes more efficient use of network resources
+ // by introducing a small delay before sending small packets so that
+ // multiple messages can be batched together before going onto the
+ // wire. This however comes at the cost of latency, so the default
+ // is to disable it. If you don't need low latency and are streaming
+ // lots of small messages, you can change this to 'false'
+ disableNagleAlgorithm: true,
+
+ // The number of milliseconds to wait after sending a close frame
+ // for an acknowledgement to come back before giving up and just
+ // closing the socket.
+ closeTimeout: 5000,
+
+ // Options to pass to https.connect if connecting via TLS
+ tlsOptions: {}
+ };
+
+ if (config) {
+ var tlsOptions;
+ if (config.tlsOptions) {
+ tlsOptions = config.tlsOptions;
+ delete config.tlsOptions;
+ }
+ else {
+ tlsOptions = {};
+ }
+ extend(this.config, config);
+ extend(this.config.tlsOptions, tlsOptions);
+ }
+
+ this._req = null;
+
+ switch (this.config.webSocketVersion) {
+ case 8:
+ case 13:
+ break;
+ default:
+ throw new Error('Requested webSocketVersion is not supported. Allowed values are 8 and 13.');
+ }
+}
+
+util.inherits(WebSocketClient, EventEmitter);
+
+WebSocketClient.prototype.connect = function(requestUrl, protocols, origin, headers, extraRequestOptions) {
+ var self = this;
+
+ if (typeof(protocols) === 'string') {
+ if (protocols.length > 0) {
+ protocols = [protocols];
+ }
+ else {
+ protocols = [];
+ }
+ }
+ if (!(protocols instanceof Array)) {
+ protocols = [];
+ }
+ this.protocols = protocols;
+ this.origin = origin;
+
+ if (typeof(requestUrl) === 'string') {
+ this.url = url.parse(requestUrl);
+ }
+ else {
+ this.url = requestUrl; // in case an already parsed url is passed in.
+ }
+ if (!this.url.protocol) {
+ throw new Error('You must specify a full WebSocket URL, including protocol.');
+ }
+ if (!this.url.host) {
+ throw new Error('You must specify a full WebSocket URL, including hostname. Relative URLs are not supported.');
+ }
+
+ this.secure = (this.url.protocol === 'wss:');
+
+ // validate protocol characters:
+ this.protocols.forEach(function(protocol) {
+ for (var i=0; i < protocol.length; i ++) {
+ var charCode = protocol.charCodeAt(i);
+ var character = protocol.charAt(i);
+ if (charCode < 0x0021 || charCode > 0x007E || protocolSeparators.indexOf(character) !== -1) {
+ throw new Error('Protocol list contains invalid character "' + String.fromCharCode(charCode) + '"');
+ }
+ }
+ });
+
+ var defaultPorts = {
+ 'ws:': '80',
+ 'wss:': '443'
+ };
+
+ if (!this.url.port) {
+ this.url.port = defaultPorts[this.url.protocol];
+ }
+
+ var nonce = bufferAllocUnsafe(16);
+ for (var i=0; i < 16; i++) {
+ nonce[i] = Math.round(Math.random()*0xFF);
+ }
+ this.base64nonce = nonce.toString('base64');
+
+ var hostHeaderValue = this.url.hostname;
+ if ((this.url.protocol === 'ws:' && this.url.port !== '80') ||
+ (this.url.protocol === 'wss:' && this.url.port !== '443')) {
+ hostHeaderValue += (':' + this.url.port);
+ }
+
+ var reqHeaders = {};
+ if (this.secure && this.config.tlsOptions.hasOwnProperty('headers')) {
+ // Allow for additional headers to be provided when connecting via HTTPS
+ extend(reqHeaders, this.config.tlsOptions.headers);
+ }
+ if (headers) {
+ // Explicitly provided headers take priority over any from tlsOptions
+ extend(reqHeaders, headers);
+ }
+ extend(reqHeaders, {
+ 'Upgrade': 'websocket',
+ 'Connection': 'Upgrade',
+ 'Sec-WebSocket-Version': this.config.webSocketVersion.toString(10),
+ 'Sec-WebSocket-Key': this.base64nonce,
+ 'Host': reqHeaders.Host || hostHeaderValue
+ });
+
+ if (this.protocols.length > 0) {
+ reqHeaders['Sec-WebSocket-Protocol'] = this.protocols.join(', ');
+ }
+ if (this.origin) {
+ if (this.config.webSocketVersion === 13) {
+ reqHeaders['Origin'] = this.origin;
+ }
+ else if (this.config.webSocketVersion === 8) {
+ reqHeaders['Sec-WebSocket-Origin'] = this.origin;
+ }
+ }
+
+ // TODO: Implement extensions
+
+ var pathAndQuery;
+ // Ensure it begins with '/'.
+ if (this.url.pathname) {
+ pathAndQuery = this.url.path;
+ }
+ else if (this.url.path) {
+ pathAndQuery = '/' + this.url.path;
+ }
+ else {
+ pathAndQuery = '/';
+ }
+
+ function handleRequestError(error) {
+ self._req = null;
+ self.emit('connectFailed', error);
+ }
+
+ var requestOptions = {
+ agent: false
+ };
+ if (extraRequestOptions) {
+ extend(requestOptions, extraRequestOptions);
+ }
+ // These options are always overridden by the library. The user is not
+ // allowed to specify these directly.
+ extend(requestOptions, {
+ hostname: this.url.hostname,
+ port: this.url.port,
+ method: 'GET',
+ path: pathAndQuery,
+ headers: reqHeaders
+ });
+ if (this.secure) {
+ var tlsOptions = this.config.tlsOptions;
+ for (var key in tlsOptions) {
+ if (tlsOptions.hasOwnProperty(key) && excludedTlsOptions.indexOf(key) === -1) {
+ requestOptions[key] = tlsOptions[key];
+ }
+ }
+ }
+
+ var req = this._req = (this.secure ? https : http).request(requestOptions);
+ req.on('upgrade', function handleRequestUpgrade(response, socket, head) {
+ self._req = null;
+ req.removeListener('error', handleRequestError);
+ self.socket = socket;
+ self.response = response;
+ self.firstDataChunk = head;
+ self.validateHandshake();
+ });
+ req.on('error', handleRequestError);
+
+ req.on('response', function(response) {
+ self._req = null;
+ if (utils.eventEmitterListenerCount(self, 'httpResponse') > 0) {
+ self.emit('httpResponse', response, self);
+ if (response.socket) {
+ response.socket.end();
+ }
+ }
+ else {
+ var headerDumpParts = [];
+ for (var headerName in response.headers) {
+ headerDumpParts.push(headerName + ': ' + response.headers[headerName]);
+ }
+ self.failHandshake(
+ 'Server responded with a non-101 status: ' +
+ response.statusCode + ' ' + response.statusMessage +
+ '\nResponse Headers Follow:\n' +
+ headerDumpParts.join('\n') + '\n'
+ );
+ }
+ });
+ req.end();
+};
+
+WebSocketClient.prototype.validateHandshake = function() {
+ var headers = this.response.headers;
+
+ if (this.protocols.length > 0) {
+ this.protocol = headers['sec-websocket-protocol'];
+ if (this.protocol) {
+ if (this.protocols.indexOf(this.protocol) === -1) {
+ this.failHandshake('Server did not respond with a requested protocol.');
+ return;
+ }
+ }
+ else {
+ this.failHandshake('Expected a Sec-WebSocket-Protocol header.');
+ return;
+ }
+ }
+
+ if (!(headers['connection'] && headers['connection'].toLocaleLowerCase() === 'upgrade')) {
+ this.failHandshake('Expected a Connection: Upgrade header from the server');
+ return;
+ }
+
+ if (!(headers['upgrade'] && headers['upgrade'].toLocaleLowerCase() === 'websocket')) {
+ this.failHandshake('Expected an Upgrade: websocket header from the server');
+ return;
+ }
+
+ var sha1 = crypto.createHash('sha1');
+ sha1.update(this.base64nonce + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11');
+ var expectedKey = sha1.digest('base64');
+
+ if (!headers['sec-websocket-accept']) {
+ this.failHandshake('Expected Sec-WebSocket-Accept header from server');
+ return;
+ }
+
+ if (headers['sec-websocket-accept'] !== expectedKey) {
+ this.failHandshake('Sec-WebSocket-Accept header from server didn\'t match expected value of ' + expectedKey);
+ return;
+ }
+
+ // TODO: Support extensions
+
+ this.succeedHandshake();
+};
+
+WebSocketClient.prototype.failHandshake = function(errorDescription) {
+ if (this.socket && this.socket.writable) {
+ this.socket.end();
+ }
+ this.emit('connectFailed', new Error(errorDescription));
+};
+
+WebSocketClient.prototype.succeedHandshake = function() {
+ var connection = new WebSocketConnection(this.socket, [], this.protocol, true, this.config);
+
+ connection.webSocketVersion = this.config.webSocketVersion;
+ connection._addSocketEventListeners();
+
+ this.emit('connect', connection);
+ if (this.firstDataChunk.length > 0) {
+ connection.handleSocketData(this.firstDataChunk);
+ }
+ this.firstDataChunk = null;
+};
+
+WebSocketClient.prototype.abort = function() {
+ if (this._req) {
+ this._req.abort();
+ }
+};
+
+module.exports = WebSocketClient;
--- /dev/null
+/************************************************************************
+ * Copyright 2010-2015 Brian McKelvey.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+
+var util = require('util');
+var utils = require('./utils');
+var EventEmitter = require('events').EventEmitter;
+var WebSocketFrame = require('./WebSocketFrame');
+var BufferList = require('../vendor/FastBufferList');
+var Validation = require('./Validation').Validation;
+var bufferAllocUnsafe = utils.bufferAllocUnsafe;
+var bufferFromString = utils.bufferFromString;
+
+// Connected, fully-open, ready to send and receive frames
+const STATE_OPEN = 'open';
+// Received a close frame from the remote peer
+const STATE_PEER_REQUESTED_CLOSE = 'peer_requested_close';
+// Sent close frame to remote peer. No further data can be sent.
+const STATE_ENDING = 'ending';
+// Connection is fully closed. No further data can be sent or received.
+const STATE_CLOSED = 'closed';
+
+var setImmediateImpl = ('setImmediate' in global) ?
+ global.setImmediate.bind(global) :
+ process.nextTick.bind(process);
+
+var idCounter = 0;
+
+function WebSocketConnection(socket, extensions, protocol, maskOutgoingPackets, config) {
+ this._debug = utils.BufferingLogger('websocket:connection', ++idCounter);
+ this._debug('constructor');
+
+ if (this._debug.enabled) {
+ instrumentSocketForDebugging(this, socket);
+ }
+
+ // Superclass Constructor
+ EventEmitter.call(this);
+
+ this._pingListenerCount = 0;
+ this.on('newListener', function(ev) {
+ if (ev === 'ping'){
+ this._pingListenerCount++;
+ }
+ }).on('removeListener', function(ev) {
+ if (ev === 'ping') {
+ this._pingListenerCount--;
+ }
+ });
+
+ this.config = config;
+ this.socket = socket;
+ this.protocol = protocol;
+ this.extensions = extensions;
+ this.remoteAddress = socket.remoteAddress;
+ this.closeReasonCode = -1;
+ this.closeDescription = null;
+ this.closeEventEmitted = false;
+
+ // We have to mask outgoing packets if we're acting as a WebSocket client.
+ this.maskOutgoingPackets = maskOutgoingPackets;
+
+ // We re-use the same buffers for the mask and frame header for all frames
+ // received on each connection to avoid a small memory allocation for each
+ // frame.
+ this.maskBytes = bufferAllocUnsafe(4);
+ this.frameHeader = bufferAllocUnsafe(10);
+
+ // the BufferList will handle the data streaming in
+ this.bufferList = new BufferList();
+
+ // Prepare for receiving first frame
+ this.currentFrame = new WebSocketFrame(this.maskBytes, this.frameHeader, this.config);
+ this.fragmentationSize = 0; // data received so far...
+ this.frameQueue = [];
+
+ // Various bits of connection state
+ this.connected = true;
+ this.state = STATE_OPEN;
+ this.waitingForCloseResponse = false;
+ // Received TCP FIN, socket's readable stream is finished.
+ this.receivedEnd = false;
+
+ this.closeTimeout = this.config.closeTimeout;
+ this.assembleFragments = this.config.assembleFragments;
+ this.maxReceivedMessageSize = this.config.maxReceivedMessageSize;
+
+ this.outputBufferFull = false;
+ this.inputPaused = false;
+ this.receivedDataHandler = this.processReceivedData.bind(this);
+ this._closeTimerHandler = this.handleCloseTimer.bind(this);
+
+ // Disable nagle algorithm?
+ this.socket.setNoDelay(this.config.disableNagleAlgorithm);
+
+ // Make sure there is no socket inactivity timeout
+ this.socket.setTimeout(0);
+
+ if (this.config.keepalive && !this.config.useNativeKeepalive) {
+ if (typeof(this.config.keepaliveInterval) !== 'number') {
+ throw new Error('keepaliveInterval must be specified and numeric ' +
+ 'if keepalive is true.');
+ }
+ this._keepaliveTimerHandler = this.handleKeepaliveTimer.bind(this);
+ this.setKeepaliveTimer();
+
+ if (this.config.dropConnectionOnKeepaliveTimeout) {
+ if (typeof(this.config.keepaliveGracePeriod) !== 'number') {
+ throw new Error('keepaliveGracePeriod must be specified and ' +
+ 'numeric if dropConnectionOnKeepaliveTimeout ' +
+ 'is true.');
+ }
+ this._gracePeriodTimerHandler = this.handleGracePeriodTimer.bind(this);
+ }
+ }
+ else if (this.config.keepalive && this.config.useNativeKeepalive) {
+ if (!('setKeepAlive' in this.socket)) {
+ throw new Error('Unable to use native keepalive: unsupported by ' +
+ 'this version of Node.');
+ }
+ this.socket.setKeepAlive(true, this.config.keepaliveInterval);
+ }
+
+ // The HTTP Client seems to subscribe to socket error events
+ // and re-dispatch them in such a way that doesn't make sense
+ // for users of our client, so we want to make sure nobody
+ // else is listening for error events on the socket besides us.
+ this.socket.removeAllListeners('error');
+}
+
+WebSocketConnection.CLOSE_REASON_NORMAL = 1000;
+WebSocketConnection.CLOSE_REASON_GOING_AWAY = 1001;
+WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR = 1002;
+WebSocketConnection.CLOSE_REASON_UNPROCESSABLE_INPUT = 1003;
+WebSocketConnection.CLOSE_REASON_RESERVED = 1004; // Reserved value. Undefined meaning.
+WebSocketConnection.CLOSE_REASON_NOT_PROVIDED = 1005; // Not to be used on the wire
+WebSocketConnection.CLOSE_REASON_ABNORMAL = 1006; // Not to be used on the wire
+WebSocketConnection.CLOSE_REASON_INVALID_DATA = 1007;
+WebSocketConnection.CLOSE_REASON_POLICY_VIOLATION = 1008;
+WebSocketConnection.CLOSE_REASON_MESSAGE_TOO_BIG = 1009;
+WebSocketConnection.CLOSE_REASON_EXTENSION_REQUIRED = 1010;
+WebSocketConnection.CLOSE_REASON_INTERNAL_SERVER_ERROR = 1011;
+WebSocketConnection.CLOSE_REASON_TLS_HANDSHAKE_FAILED = 1015; // Not to be used on the wire
+
+WebSocketConnection.CLOSE_DESCRIPTIONS = {
+ 1000: 'Normal connection closure',
+ 1001: 'Remote peer is going away',
+ 1002: 'Protocol error',
+ 1003: 'Unprocessable input',
+ 1004: 'Reserved',
+ 1005: 'Reason not provided',
+ 1006: 'Abnormal closure, no further detail available',
+ 1007: 'Invalid data received',
+ 1008: 'Policy violation',
+ 1009: 'Message too big',
+ 1010: 'Extension requested by client is required',
+ 1011: 'Internal Server Error',
+ 1015: 'TLS Handshake Failed'
+};
+
+function validateCloseReason(code) {
+ if (code < 1000) {
+ // Status codes in the range 0-999 are not used
+ return false;
+ }
+ if (code >= 1000 && code <= 2999) {
+ // Codes from 1000 - 2999 are reserved for use by the protocol. Only
+ // a few codes are defined, all others are currently illegal.
+ return [1000, 1001, 1002, 1003, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014].indexOf(code) !== -1;
+ }
+ if (code >= 3000 && code <= 3999) {
+ // Reserved for use by libraries, frameworks, and applications.
+ // Should be registered with IANA. Interpretation of these codes is
+ // undefined by the WebSocket protocol.
+ return true;
+ }
+ if (code >= 4000 && code <= 4999) {
+ // Reserved for private use. Interpretation of these codes is
+ // undefined by the WebSocket protocol.
+ return true;
+ }
+ if (code >= 5000) {
+ return false;
+ }
+}
+
+util.inherits(WebSocketConnection, EventEmitter);
+
+WebSocketConnection.prototype._addSocketEventListeners = function() {
+ this.socket.on('error', this.handleSocketError.bind(this));
+ this.socket.on('end', this.handleSocketEnd.bind(this));
+ this.socket.on('close', this.handleSocketClose.bind(this));
+ this.socket.on('drain', this.handleSocketDrain.bind(this));
+ this.socket.on('pause', this.handleSocketPause.bind(this));
+ this.socket.on('resume', this.handleSocketResume.bind(this));
+ this.socket.on('data', this.handleSocketData.bind(this));
+};
+
+// set or reset the keepalive timer when data is received.
+WebSocketConnection.prototype.setKeepaliveTimer = function() {
+ this._debug('setKeepaliveTimer');
+ if (!this.config.keepalive || this.config.useNativeKeepalive) { return; }
+ this.clearKeepaliveTimer();
+ this.clearGracePeriodTimer();
+ this._keepaliveTimeoutID = setTimeout(this._keepaliveTimerHandler, this.config.keepaliveInterval);
+};
+
+WebSocketConnection.prototype.clearKeepaliveTimer = function() {
+ if (this._keepaliveTimeoutID) {
+ clearTimeout(this._keepaliveTimeoutID);
+ }
+};
+
+// No data has been received within config.keepaliveTimeout ms.
+WebSocketConnection.prototype.handleKeepaliveTimer = function() {
+ this._debug('handleKeepaliveTimer');
+ this._keepaliveTimeoutID = null;
+ this.ping();
+
+ // If we are configured to drop connections if the client doesn't respond
+ // then set the grace period timer.
+ if (this.config.dropConnectionOnKeepaliveTimeout) {
+ this.setGracePeriodTimer();
+ }
+ else {
+ // Otherwise reset the keepalive timer to send the next ping.
+ this.setKeepaliveTimer();
+ }
+};
+
+WebSocketConnection.prototype.setGracePeriodTimer = function() {
+ this._debug('setGracePeriodTimer');
+ this.clearGracePeriodTimer();
+ this._gracePeriodTimeoutID = setTimeout(this._gracePeriodTimerHandler, this.config.keepaliveGracePeriod);
+};
+
+WebSocketConnection.prototype.clearGracePeriodTimer = function() {
+ if (this._gracePeriodTimeoutID) {
+ clearTimeout(this._gracePeriodTimeoutID);
+ }
+};
+
+WebSocketConnection.prototype.handleGracePeriodTimer = function() {
+ this._debug('handleGracePeriodTimer');
+ // If this is called, the client has not responded and is assumed dead.
+ this._gracePeriodTimeoutID = null;
+ this.drop(WebSocketConnection.CLOSE_REASON_ABNORMAL, 'Peer not responding.', true);
+};
+
+WebSocketConnection.prototype.handleSocketData = function(data) {
+ this._debug('handleSocketData');
+ // Reset the keepalive timer when receiving data of any kind.
+ this.setKeepaliveTimer();
+
+ // Add received data to our bufferList, which efficiently holds received
+ // data chunks in a linked list of Buffer objects.
+ this.bufferList.write(data);
+
+ this.processReceivedData();
+};
+
+WebSocketConnection.prototype.processReceivedData = function() {
+ this._debug('processReceivedData');
+ // If we're not connected, we should ignore any data remaining on the buffer.
+ if (!this.connected) { return; }
+
+ // Receiving/parsing is expected to be halted when paused.
+ if (this.inputPaused) { return; }
+
+ var frame = this.currentFrame;
+
+ // WebSocketFrame.prototype.addData returns true if all data necessary to
+ // parse the frame was available. It returns false if we are waiting for
+ // more data to come in on the wire.
+ if (!frame.addData(this.bufferList)) { this._debug('-- insufficient data for frame'); return; }
+
+ var self = this;
+
+ // Handle possible parsing errors
+ if (frame.protocolError) {
+ // Something bad happened.. get rid of this client.
+ this._debug('-- protocol error');
+ process.nextTick(function() {
+ self.drop(WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR, frame.dropReason);
+ });
+ return;
+ }
+ else if (frame.frameTooLarge) {
+ this._debug('-- frame too large');
+ process.nextTick(function() {
+ self.drop(WebSocketConnection.CLOSE_REASON_MESSAGE_TOO_BIG, frame.dropReason);
+ });
+ return;
+ }
+
+ // For now since we don't support extensions, all RSV bits are illegal
+ if (frame.rsv1 || frame.rsv2 || frame.rsv3) {
+ this._debug('-- illegal rsv flag');
+ process.nextTick(function() {
+ self.drop(WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR,
+ 'Unsupported usage of rsv bits without negotiated extension.');
+ });
+ return;
+ }
+
+ if (!this.assembleFragments) {
+ this._debug('-- emitting frame');
+ process.nextTick(function() { self.emit('frame', frame); });
+ }
+
+ process.nextTick(function() { self.processFrame(frame); });
+
+ this.currentFrame = new WebSocketFrame(this.maskBytes, this.frameHeader, this.config);
+
+ // If there's data remaining, schedule additional processing, but yield
+ // for now so that other connections have a chance to have their data
+ // processed. We use setImmediate here instead of process.nextTick to
+ // explicitly indicate that we wish for other I/O to be handled first.
+ if (this.bufferList.length > 0) {
+ setImmediateImpl(this.receivedDataHandler);
+ }
+};
+
+WebSocketConnection.prototype.handleSocketError = function(error) {
+ this._debug('handleSocketError: %j', error);
+ if (this.state === STATE_CLOSED) {
+ // See https://github.com/theturtle32/WebSocket-Node/issues/288
+ this._debug(' --- Socket \'error\' after \'close\'');
+ return;
+ }
+ this.closeReasonCode = WebSocketConnection.CLOSE_REASON_ABNORMAL;
+ this.closeDescription = 'Socket Error: ' + error.syscall + ' ' + error.code;
+ this.connected = false;
+ this.state = STATE_CLOSED;
+ this.fragmentationSize = 0;
+ if (utils.eventEmitterListenerCount(this, 'error') > 0) {
+ this.emit('error', error);
+ }
+ this.socket.destroy(error);
+ this._debug.printOutput();
+};
+
+WebSocketConnection.prototype.handleSocketEnd = function() {
+ this._debug('handleSocketEnd: received socket end. state = %s', this.state);
+ this.receivedEnd = true;
+ if (this.state === STATE_CLOSED) {
+ // When using the TLS module, sometimes the socket will emit 'end'
+ // after it emits 'close'. I don't think that's correct behavior,
+ // but we should deal with it gracefully by ignoring it.
+ this._debug(' --- Socket \'end\' after \'close\'');
+ return;
+ }
+ if (this.state !== STATE_PEER_REQUESTED_CLOSE &&
+ this.state !== STATE_ENDING) {
+ this._debug(' --- UNEXPECTED socket end.');
+ this.socket.end();
+ }
+};
+
+WebSocketConnection.prototype.handleSocketClose = function(hadError) {
+ this._debug('handleSocketClose: received socket close');
+ this.socketHadError = hadError;
+ this.connected = false;
+ this.state = STATE_CLOSED;
+ // If closeReasonCode is still set to -1 at this point then we must
+ // not have received a close frame!!
+ if (this.closeReasonCode === -1) {
+ this.closeReasonCode = WebSocketConnection.CLOSE_REASON_ABNORMAL;
+ this.closeDescription = 'Connection dropped by remote peer.';
+ }
+ this.clearCloseTimer();
+ this.clearKeepaliveTimer();
+ this.clearGracePeriodTimer();
+ if (!this.closeEventEmitted) {
+ this.closeEventEmitted = true;
+ this._debug('-- Emitting WebSocketConnection close event');
+ this.emit('close', this.closeReasonCode, this.closeDescription);
+ }
+};
+
+WebSocketConnection.prototype.handleSocketDrain = function() {
+ this._debug('handleSocketDrain: socket drain event');
+ this.outputBufferFull = false;
+ this.emit('drain');
+};
+
+WebSocketConnection.prototype.handleSocketPause = function() {
+ this._debug('handleSocketPause: socket pause event');
+ this.inputPaused = true;
+ this.emit('pause');
+};
+
+WebSocketConnection.prototype.handleSocketResume = function() {
+ this._debug('handleSocketResume: socket resume event');
+ this.inputPaused = false;
+ this.emit('resume');
+ this.processReceivedData();
+};
+
+WebSocketConnection.prototype.pause = function() {
+ this._debug('pause: pause requested');
+ this.socket.pause();
+};
+
+WebSocketConnection.prototype.resume = function() {
+ this._debug('resume: resume requested');
+ this.socket.resume();
+};
+
+WebSocketConnection.prototype.close = function(reasonCode, description) {
+ if (this.connected) {
+ this._debug('close: Initating clean WebSocket close sequence.');
+ if ('number' !== typeof reasonCode) {
+ reasonCode = WebSocketConnection.CLOSE_REASON_NORMAL;
+ }
+ if (!validateCloseReason(reasonCode)) {
+ throw new Error('Close code ' + reasonCode + ' is not valid.');
+ }
+ if ('string' !== typeof description) {
+ description = WebSocketConnection.CLOSE_DESCRIPTIONS[reasonCode];
+ }
+ this.closeReasonCode = reasonCode;
+ this.closeDescription = description;
+ this.setCloseTimer();
+ this.sendCloseFrame(this.closeReasonCode, this.closeDescription);
+ this.state = STATE_ENDING;
+ this.connected = false;
+ }
+};
+
+WebSocketConnection.prototype.drop = function(reasonCode, description, skipCloseFrame) {
+ this._debug('drop');
+ if (typeof(reasonCode) !== 'number') {
+ reasonCode = WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR;
+ }
+
+ if (typeof(description) !== 'string') {
+ // If no description is provided, try to look one up based on the
+ // specified reasonCode.
+ description = WebSocketConnection.CLOSE_DESCRIPTIONS[reasonCode];
+ }
+
+ this._debug('Forcefully dropping connection. skipCloseFrame: %s, code: %d, description: %s',
+ skipCloseFrame, reasonCode, description
+ );
+
+ this.closeReasonCode = reasonCode;
+ this.closeDescription = description;
+ this.frameQueue = [];
+ this.fragmentationSize = 0;
+ if (!skipCloseFrame) {
+ this.sendCloseFrame(reasonCode, description);
+ }
+ this.connected = false;
+ this.state = STATE_CLOSED;
+ this.clearCloseTimer();
+ this.clearKeepaliveTimer();
+ this.clearGracePeriodTimer();
+
+ if (!this.closeEventEmitted) {
+ this.closeEventEmitted = true;
+ this._debug('Emitting WebSocketConnection close event');
+ this.emit('close', this.closeReasonCode, this.closeDescription);
+ }
+
+ this._debug('Drop: destroying socket');
+ this.socket.destroy();
+};
+
+WebSocketConnection.prototype.setCloseTimer = function() {
+ this._debug('setCloseTimer');
+ this.clearCloseTimer();
+ this._debug('Setting close timer');
+ this.waitingForCloseResponse = true;
+ this.closeTimer = setTimeout(this._closeTimerHandler, this.closeTimeout);
+};
+
+WebSocketConnection.prototype.clearCloseTimer = function() {
+ this._debug('clearCloseTimer');
+ if (this.closeTimer) {
+ this._debug('Clearing close timer');
+ clearTimeout(this.closeTimer);
+ this.waitingForCloseResponse = false;
+ this.closeTimer = null;
+ }
+};
+
+WebSocketConnection.prototype.handleCloseTimer = function() {
+ this._debug('handleCloseTimer');
+ this.closeTimer = null;
+ if (this.waitingForCloseResponse) {
+ this._debug('Close response not received from client. Forcing socket end.');
+ this.waitingForCloseResponse = false;
+ this.state = STATE_CLOSED;
+ this.socket.end();
+ }
+};
+
+WebSocketConnection.prototype.processFrame = function(frame) {
+ this._debug('processFrame');
+ this._debug(' -- frame: %s', frame);
+
+ // Any non-control opcode besides 0x00 (continuation) received in the
+ // middle of a fragmented message is illegal.
+ if (this.frameQueue.length !== 0 && (frame.opcode > 0x00 && frame.opcode < 0x08)) {
+ this.drop(WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR,
+ 'Illegal frame opcode 0x' + frame.opcode.toString(16) + ' ' +
+ 'received in middle of fragmented message.');
+ return;
+ }
+
+ switch(frame.opcode) {
+ case 0x02: // WebSocketFrame.BINARY_FRAME
+ this._debug('-- Binary Frame');
+ if (this.assembleFragments) {
+ if (frame.fin) {
+ // Complete single-frame message received
+ this._debug('---- Emitting \'message\' event');
+ this.emit('message', {
+ type: 'binary',
+ binaryData: frame.binaryPayload
+ });
+ }
+ else {
+ // beginning of a fragmented message
+ this.frameQueue.push(frame);
+ this.fragmentationSize = frame.length;
+ }
+ }
+ break;
+ case 0x01: // WebSocketFrame.TEXT_FRAME
+ this._debug('-- Text Frame');
+ if (this.assembleFragments) {
+ if (frame.fin) {
+ if (!Validation.isValidUTF8(frame.binaryPayload)) {
+ this.drop(WebSocketConnection.CLOSE_REASON_INVALID_DATA,
+ 'Invalid UTF-8 Data Received');
+ return;
+ }
+ // Complete single-frame message received
+ this._debug('---- Emitting \'message\' event');
+ this.emit('message', {
+ type: 'utf8',
+ utf8Data: frame.binaryPayload.toString('utf8')
+ });
+ }
+ else {
+ // beginning of a fragmented message
+ this.frameQueue.push(frame);
+ this.fragmentationSize = frame.length;
+ }
+ }
+ break;
+ case 0x00: // WebSocketFrame.CONTINUATION
+ this._debug('-- Continuation Frame');
+ if (this.assembleFragments) {
+ if (this.frameQueue.length === 0) {
+ this.drop(WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR,
+ 'Unexpected Continuation Frame');
+ return;
+ }
+
+ this.fragmentationSize += frame.length;
+
+ if (this.fragmentationSize > this.maxReceivedMessageSize) {
+ this.drop(WebSocketConnection.CLOSE_REASON_MESSAGE_TOO_BIG,
+ 'Maximum message size exceeded.');
+ return;
+ }
+
+ this.frameQueue.push(frame);
+
+ if (frame.fin) {
+ // end of fragmented message, so we process the whole
+ // message now. We also have to decode the utf-8 data
+ // for text frames after combining all the fragments.
+ var bytesCopied = 0;
+ var binaryPayload = bufferAllocUnsafe(this.fragmentationSize);
+ var opcode = this.frameQueue[0].opcode;
+ this.frameQueue.forEach(function (currentFrame) {
+ currentFrame.binaryPayload.copy(binaryPayload, bytesCopied);
+ bytesCopied += currentFrame.binaryPayload.length;
+ });
+ this.frameQueue = [];
+ this.fragmentationSize = 0;
+
+ switch (opcode) {
+ case 0x02: // WebSocketOpcode.BINARY_FRAME
+ this.emit('message', {
+ type: 'binary',
+ binaryData: binaryPayload
+ });
+ break;
+ case 0x01: // WebSocketOpcode.TEXT_FRAME
+ if (!Validation.isValidUTF8(binaryPayload)) {
+ this.drop(WebSocketConnection.CLOSE_REASON_INVALID_DATA,
+ 'Invalid UTF-8 Data Received');
+ return;
+ }
+ this.emit('message', {
+ type: 'utf8',
+ utf8Data: binaryPayload.toString('utf8')
+ });
+ break;
+ default:
+ this.drop(WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR,
+ 'Unexpected first opcode in fragmentation sequence: 0x' + opcode.toString(16));
+ return;
+ }
+ }
+ }
+ break;
+ case 0x09: // WebSocketFrame.PING
+ this._debug('-- Ping Frame');
+
+ if (this._pingListenerCount > 0) {
+ // logic to emit the ping frame: this is only done when a listener is known to exist
+ // Expose a function allowing the user to override the default ping() behavior
+ var cancelled = false;
+ var cancel = function() {
+ cancelled = true;
+ };
+ this.emit('ping', cancel, frame.binaryPayload);
+
+ // Only send a pong if the client did not indicate that he would like to cancel
+ if (!cancelled) {
+ this.pong(frame.binaryPayload);
+ }
+ }
+ else {
+ this.pong(frame.binaryPayload);
+ }
+
+ break;
+ case 0x0A: // WebSocketFrame.PONG
+ this._debug('-- Pong Frame');
+ this.emit('pong', frame.binaryPayload);
+ break;
+ case 0x08: // WebSocketFrame.CONNECTION_CLOSE
+ this._debug('-- Close Frame');
+ if (this.waitingForCloseResponse) {
+ // Got response to our request to close the connection.
+ // Close is complete, so we just hang up.
+ this._debug('---- Got close response from peer. Completing closing handshake.');
+ this.clearCloseTimer();
+ this.waitingForCloseResponse = false;
+ this.state = STATE_CLOSED;
+ this.socket.end();
+ return;
+ }
+
+ this._debug('---- Closing handshake initiated by peer.');
+ // Got request from other party to close connection.
+ // Send back acknowledgement and then hang up.
+ this.state = STATE_PEER_REQUESTED_CLOSE;
+ var respondCloseReasonCode;
+
+ // Make sure the close reason provided is legal according to
+ // the protocol spec. Providing no close status is legal.
+ // WebSocketFrame sets closeStatus to -1 by default, so if it
+ // is still -1, then no status was provided.
+ if (frame.invalidCloseFrameLength) {
+ this.closeReasonCode = 1005; // 1005 = No reason provided.
+ respondCloseReasonCode = WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR;
+ }
+ else if (frame.closeStatus === -1 || validateCloseReason(frame.closeStatus)) {
+ this.closeReasonCode = frame.closeStatus;
+ respondCloseReasonCode = WebSocketConnection.CLOSE_REASON_NORMAL;
+ }
+ else {
+ this.closeReasonCode = frame.closeStatus;
+ respondCloseReasonCode = WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR;
+ }
+
+ // If there is a textual description in the close frame, extract it.
+ if (frame.binaryPayload.length > 1) {
+ if (!Validation.isValidUTF8(frame.binaryPayload)) {
+ this.drop(WebSocketConnection.CLOSE_REASON_INVALID_DATA,
+ 'Invalid UTF-8 Data Received');
+ return;
+ }
+ this.closeDescription = frame.binaryPayload.toString('utf8');
+ }
+ else {
+ this.closeDescription = WebSocketConnection.CLOSE_DESCRIPTIONS[this.closeReasonCode];
+ }
+ this._debug(
+ '------ Remote peer %s - code: %d - %s - close frame payload length: %d',
+ this.remoteAddress, this.closeReasonCode,
+ this.closeDescription, frame.length
+ );
+ this._debug('------ responding to remote peer\'s close request.');
+ this.sendCloseFrame(respondCloseReasonCode, null);
+ this.connected = false;
+ break;
+ default:
+ this._debug('-- Unrecognized Opcode %d', frame.opcode);
+ this.drop(WebSocketConnection.CLOSE_REASON_PROTOCOL_ERROR,
+ 'Unrecognized Opcode: 0x' + frame.opcode.toString(16));
+ break;
+ }
+};
+
+WebSocketConnection.prototype.send = function(data, cb) {
+ this._debug('send');
+ if (Buffer.isBuffer(data)) {
+ this.sendBytes(data, cb);
+ }
+ else if (typeof(data['toString']) === 'function') {
+ this.sendUTF(data, cb);
+ }
+ else {
+ throw new Error('Data provided must either be a Node Buffer or implement toString()');
+ }
+};
+
+WebSocketConnection.prototype.sendUTF = function(data, cb) {
+ data = bufferFromString(data.toString(), 'utf8');
+ this._debug('sendUTF: %d bytes', data.length);
+ var frame = new WebSocketFrame(this.maskBytes, this.frameHeader, this.config);
+ frame.opcode = 0x01; // WebSocketOpcode.TEXT_FRAME
+ frame.binaryPayload = data;
+ this.fragmentAndSend(frame, cb);
+};
+
+WebSocketConnection.prototype.sendBytes = function(data, cb) {
+ this._debug('sendBytes');
+ if (!Buffer.isBuffer(data)) {
+ throw new Error('You must pass a Node Buffer object to WebSocketConnection.prototype.sendBytes()');
+ }
+ var frame = new WebSocketFrame(this.maskBytes, this.frameHeader, this.config);
+ frame.opcode = 0x02; // WebSocketOpcode.BINARY_FRAME
+ frame.binaryPayload = data;
+ this.fragmentAndSend(frame, cb);
+};
+
+WebSocketConnection.prototype.ping = function(data) {
+ this._debug('ping');
+ var frame = new WebSocketFrame(this.maskBytes, this.frameHeader, this.config);
+ frame.opcode = 0x09; // WebSocketOpcode.PING
+ frame.fin = true;
+ if (data) {
+ if (!Buffer.isBuffer(data)) {
+ data = bufferFromString(data.toString(), 'utf8');
+ }
+ if (data.length > 125) {
+ this._debug('WebSocket: Data for ping is longer than 125 bytes. Truncating.');
+ data = data.slice(0,124);
+ }
+ frame.binaryPayload = data;
+ }
+ this.sendFrame(frame);
+};
+
+// Pong frames have to echo back the contents of the data portion of the
+// ping frame exactly, byte for byte.
+WebSocketConnection.prototype.pong = function(binaryPayload) {
+ this._debug('pong');
+ var frame = new WebSocketFrame(this.maskBytes, this.frameHeader, this.config);
+ frame.opcode = 0x0A; // WebSocketOpcode.PONG
+ if (Buffer.isBuffer(binaryPayload) && binaryPayload.length > 125) {
+ this._debug('WebSocket: Data for pong is longer than 125 bytes. Truncating.');
+ binaryPayload = binaryPayload.slice(0,124);
+ }
+ frame.binaryPayload = binaryPayload;
+ frame.fin = true;
+ this.sendFrame(frame);
+};
+
+WebSocketConnection.prototype.fragmentAndSend = function(frame, cb) {
+ this._debug('fragmentAndSend');
+ if (frame.opcode > 0x07) {
+ throw new Error('You cannot fragment control frames.');
+ }
+
+ var threshold = this.config.fragmentationThreshold;
+ var length = frame.binaryPayload.length;
+
+ // Send immediately if fragmentation is disabled or the message is not
+ // larger than the fragmentation threshold.
+ if (!this.config.fragmentOutgoingMessages || (frame.binaryPayload && length <= threshold)) {
+ frame.fin = true;
+ this.sendFrame(frame, cb);
+ return;
+ }
+
+ var numFragments = Math.ceil(length / threshold);
+ var sentFragments = 0;
+ var sentCallback = function fragmentSentCallback(err) {
+ if (err) {
+ if (typeof cb === 'function') {
+ // pass only the first error
+ cb(err);
+ cb = null;
+ }
+ return;
+ }
+ ++sentFragments;
+ if ((sentFragments === numFragments) && (typeof cb === 'function')) {
+ cb();
+ }
+ };
+ for (var i=1; i <= numFragments; i++) {
+ var currentFrame = new WebSocketFrame(this.maskBytes, this.frameHeader, this.config);
+
+ // continuation opcode except for first frame.
+ currentFrame.opcode = (i === 1) ? frame.opcode : 0x00;
+
+ // fin set on last frame only
+ currentFrame.fin = (i === numFragments);
+
+ // length is likely to be shorter on the last fragment
+ var currentLength = (i === numFragments) ? length - (threshold * (i-1)) : threshold;
+ var sliceStart = threshold * (i-1);
+
+ // Slice the right portion of the original payload
+ currentFrame.binaryPayload = frame.binaryPayload.slice(sliceStart, sliceStart + currentLength);
+
+ this.sendFrame(currentFrame, sentCallback);
+ }
+};
+
+WebSocketConnection.prototype.sendCloseFrame = function(reasonCode, description, cb) {
+ if (typeof(reasonCode) !== 'number') {
+ reasonCode = WebSocketConnection.CLOSE_REASON_NORMAL;
+ }
+
+ this._debug('sendCloseFrame state: %s, reasonCode: %d, description: %s', this.state, reasonCode, description);
+
+ if (this.state !== STATE_OPEN && this.state !== STATE_PEER_REQUESTED_CLOSE) { return; }
+
+ var frame = new WebSocketFrame(this.maskBytes, this.frameHeader, this.config);
+ frame.fin = true;
+ frame.opcode = 0x08; // WebSocketOpcode.CONNECTION_CLOSE
+ frame.closeStatus = reasonCode;
+ if (typeof(description) === 'string') {
+ frame.binaryPayload = bufferFromString(description, 'utf8');
+ }
+
+ this.sendFrame(frame, cb);
+ this.socket.end();
+};
+
+WebSocketConnection.prototype.sendFrame = function(frame, cb) {
+ this._debug('sendFrame');
+ frame.mask = this.maskOutgoingPackets;
+ var flushed = this.socket.write(frame.toBuffer(), cb);
+ this.outputBufferFull = !flushed;
+ return flushed;
+};
+
+module.exports = WebSocketConnection;
+
+
+
+function instrumentSocketForDebugging(connection, socket) {
+ /* jshint loopfunc: true */
+ if (!connection._debug.enabled) { return; }
+
+ var originalSocketEmit = socket.emit;
+ socket.emit = function(event) {
+ connection._debug('||| Socket Event \'%s\'', event);
+ originalSocketEmit.apply(this, arguments);
+ };
+
+ for (var key in socket) {
+ if ('function' !== typeof(socket[key])) { continue; }
+ if (['emit'].indexOf(key) !== -1) { continue; }
+ (function(key) {
+ var original = socket[key];
+ if (key === 'on') {
+ socket[key] = function proxyMethod__EventEmitter__On() {
+ connection._debug('||| Socket method called: %s (%s)', key, arguments[0]);
+ return original.apply(this, arguments);
+ };
+ return;
+ }
+ socket[key] = function proxyMethod() {
+ connection._debug('||| Socket method called: %s', key);
+ return original.apply(this, arguments);
+ };
+ })(key);
+ }
+}
--- /dev/null
+/************************************************************************
+ * Copyright 2010-2015 Brian McKelvey.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+
+var bufferUtil = require('./BufferUtil').BufferUtil;
+var bufferAllocUnsafe = require('./utils').bufferAllocUnsafe;
+
+const DECODE_HEADER = 1;
+const WAITING_FOR_16_BIT_LENGTH = 2;
+const WAITING_FOR_64_BIT_LENGTH = 3;
+const WAITING_FOR_MASK_KEY = 4;
+const WAITING_FOR_PAYLOAD = 5;
+const COMPLETE = 6;
+
+// WebSocketConnection will pass shared buffer objects for maskBytes and
+// frameHeader into the constructor to avoid tons of small memory allocations
+// for each frame we have to parse. This is only used for parsing frames
+// we receive off the wire.
+function WebSocketFrame(maskBytes, frameHeader, config) {
+ this.maskBytes = maskBytes;
+ this.frameHeader = frameHeader;
+ this.config = config;
+ this.maxReceivedFrameSize = config.maxReceivedFrameSize;
+ this.protocolError = false;
+ this.frameTooLarge = false;
+ this.invalidCloseFrameLength = false;
+ this.parseState = DECODE_HEADER;
+ this.closeStatus = -1;
+}
+
+WebSocketFrame.prototype.addData = function(bufferList) {
+ if (this.parseState === DECODE_HEADER) {
+ if (bufferList.length >= 2) {
+ bufferList.joinInto(this.frameHeader, 0, 0, 2);
+ bufferList.advance(2);
+ var firstByte = this.frameHeader[0];
+ var secondByte = this.frameHeader[1];
+
+ this.fin = Boolean(firstByte & 0x80);
+ this.rsv1 = Boolean(firstByte & 0x40);
+ this.rsv2 = Boolean(firstByte & 0x20);
+ this.rsv3 = Boolean(firstByte & 0x10);
+ this.mask = Boolean(secondByte & 0x80);
+
+ this.opcode = firstByte & 0x0F;
+ this.length = secondByte & 0x7F;
+
+ // Control frame sanity check
+ if (this.opcode >= 0x08) {
+ if (this.length > 125) {
+ this.protocolError = true;
+ this.dropReason = 'Illegal control frame longer than 125 bytes.';
+ return true;
+ }
+ if (!this.fin) {
+ this.protocolError = true;
+ this.dropReason = 'Control frames must not be fragmented.';
+ return true;
+ }
+ }
+
+ if (this.length === 126) {
+ this.parseState = WAITING_FOR_16_BIT_LENGTH;
+ }
+ else if (this.length === 127) {
+ this.parseState = WAITING_FOR_64_BIT_LENGTH;
+ }
+ else {
+ this.parseState = WAITING_FOR_MASK_KEY;
+ }
+ }
+ }
+ if (this.parseState === WAITING_FOR_16_BIT_LENGTH) {
+ if (bufferList.length >= 2) {
+ bufferList.joinInto(this.frameHeader, 2, 0, 2);
+ bufferList.advance(2);
+ this.length = this.frameHeader.readUInt16BE(2);
+ this.parseState = WAITING_FOR_MASK_KEY;
+ }
+ }
+ else if (this.parseState === WAITING_FOR_64_BIT_LENGTH) {
+ if (bufferList.length >= 8) {
+ bufferList.joinInto(this.frameHeader, 2, 0, 8);
+ bufferList.advance(8);
+ var lengthPair = [
+ this.frameHeader.readUInt32BE(2),
+ this.frameHeader.readUInt32BE(2+4)
+ ];
+
+ if (lengthPair[0] !== 0) {
+ this.protocolError = true;
+ this.dropReason = 'Unsupported 64-bit length frame received';
+ return true;
+ }
+ this.length = lengthPair[1];
+ this.parseState = WAITING_FOR_MASK_KEY;
+ }
+ }
+
+ if (this.parseState === WAITING_FOR_MASK_KEY) {
+ if (this.mask) {
+ if (bufferList.length >= 4) {
+ bufferList.joinInto(this.maskBytes, 0, 0, 4);
+ bufferList.advance(4);
+ this.parseState = WAITING_FOR_PAYLOAD;
+ }
+ }
+ else {
+ this.parseState = WAITING_FOR_PAYLOAD;
+ }
+ }
+
+ if (this.parseState === WAITING_FOR_PAYLOAD) {
+ if (this.length > this.maxReceivedFrameSize) {
+ this.frameTooLarge = true;
+ this.dropReason = 'Frame size of ' + this.length.toString(10) +
+ ' bytes exceeds maximum accepted frame size';
+ return true;
+ }
+
+ if (this.length === 0) {
+ this.binaryPayload = bufferAllocUnsafe(0);
+ this.parseState = COMPLETE;
+ return true;
+ }
+ if (bufferList.length >= this.length) {
+ this.binaryPayload = bufferList.take(this.length);
+ bufferList.advance(this.length);
+ if (this.mask) {
+ bufferUtil.unmask(this.binaryPayload, this.maskBytes);
+ // xor(this.binaryPayload, this.maskBytes, 0);
+ }
+
+ if (this.opcode === 0x08) { // WebSocketOpcode.CONNECTION_CLOSE
+ if (this.length === 1) {
+ // Invalid length for a close frame. Must be zero or at least two.
+ this.binaryPayload = bufferAllocUnsafe(0);
+ this.invalidCloseFrameLength = true;
+ }
+ if (this.length >= 2) {
+ this.closeStatus = this.binaryPayload.readUInt16BE(0);
+ this.binaryPayload = this.binaryPayload.slice(2);
+ }
+ }
+
+ this.parseState = COMPLETE;
+ return true;
+ }
+ }
+ return false;
+};
+
+WebSocketFrame.prototype.throwAwayPayload = function(bufferList) {
+ if (bufferList.length >= this.length) {
+ bufferList.advance(this.length);
+ this.parseState = COMPLETE;
+ return true;
+ }
+ return false;
+};
+
+WebSocketFrame.prototype.toBuffer = function(nullMask) {
+ var maskKey;
+ var headerLength = 2;
+ var data;
+ var outputPos;
+ var firstByte = 0x00;
+ var secondByte = 0x00;
+
+ if (this.fin) {
+ firstByte |= 0x80;
+ }
+ if (this.rsv1) {
+ firstByte |= 0x40;
+ }
+ if (this.rsv2) {
+ firstByte |= 0x20;
+ }
+ if (this.rsv3) {
+ firstByte |= 0x10;
+ }
+ if (this.mask) {
+ secondByte |= 0x80;
+ }
+
+ firstByte |= (this.opcode & 0x0F);
+
+ // the close frame is a special case because the close reason is
+ // prepended to the payload data.
+ if (this.opcode === 0x08) {
+ this.length = 2;
+ if (this.binaryPayload) {
+ this.length += this.binaryPayload.length;
+ }
+ data = bufferAllocUnsafe(this.length);
+ data.writeUInt16BE(this.closeStatus, 0);
+ if (this.length > 2) {
+ this.binaryPayload.copy(data, 2);
+ }
+ }
+ else if (this.binaryPayload) {
+ data = this.binaryPayload;
+ this.length = data.length;
+ }
+ else {
+ this.length = 0;
+ }
+
+ if (this.length <= 125) {
+ // encode the length directly into the two-byte frame header
+ secondByte |= (this.length & 0x7F);
+ }
+ else if (this.length > 125 && this.length <= 0xFFFF) {
+ // Use 16-bit length
+ secondByte |= 126;
+ headerLength += 2;
+ }
+ else if (this.length > 0xFFFF) {
+ // Use 64-bit length
+ secondByte |= 127;
+ headerLength += 8;
+ }
+
+ var output = bufferAllocUnsafe(this.length + headerLength + (this.mask ? 4 : 0));
+
+ // write the frame header
+ output[0] = firstByte;
+ output[1] = secondByte;
+
+ outputPos = 2;
+
+ if (this.length > 125 && this.length <= 0xFFFF) {
+ // write 16-bit length
+ output.writeUInt16BE(this.length, outputPos);
+ outputPos += 2;
+ }
+ else if (this.length > 0xFFFF) {
+ // write 64-bit length
+ output.writeUInt32BE(0x00000000, outputPos);
+ output.writeUInt32BE(this.length, outputPos + 4);
+ outputPos += 8;
+ }
+
+ if (this.mask) {
+ maskKey = nullMask ? 0 : ((Math.random() * 0xFFFFFFFF) >>> 0);
+ this.maskBytes.writeUInt32BE(maskKey, 0);
+
+ // write the mask key
+ this.maskBytes.copy(output, outputPos);
+ outputPos += 4;
+
+ if (data) {
+ bufferUtil.mask(data, this.maskBytes, output, outputPos, this.length);
+ }
+ }
+ else if (data) {
+ data.copy(output, outputPos);
+ }
+
+ return output;
+};
+
+WebSocketFrame.prototype.toString = function() {
+ return 'Opcode: ' + this.opcode + ', fin: ' + this.fin + ', length: ' + this.length + ', hasPayload: ' + Boolean(this.binaryPayload) + ', masked: ' + this.mask;
+};
+
+
+module.exports = WebSocketFrame;
--- /dev/null
+/************************************************************************
+ * Copyright 2010-2015 Brian McKelvey.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+
+var crypto = require('crypto');
+var util = require('util');
+var url = require('url');
+var EventEmitter = require('events').EventEmitter;
+var WebSocketConnection = require('./WebSocketConnection');
+
+var headerValueSplitRegExp = /,\s*/;
+var headerParamSplitRegExp = /;\s*/;
+var headerSanitizeRegExp = /[\r\n]/g;
+var xForwardedForSeparatorRegExp = /,\s*/;
+var separators = [
+ '(', ')', '<', '>', '@',
+ ',', ';', ':', '\\', '\"',
+ '/', '[', ']', '?', '=',
+ '{', '}', ' ', String.fromCharCode(9)
+];
+var controlChars = [String.fromCharCode(127) /* DEL */];
+for (var i=0; i < 31; i ++) {
+ /* US-ASCII Control Characters */
+ controlChars.push(String.fromCharCode(i));
+}
+
+var cookieNameValidateRegEx = /([\x00-\x20\x22\x28\x29\x2c\x2f\x3a-\x3f\x40\x5b-\x5e\x7b\x7d\x7f])/;
+var cookieValueValidateRegEx = /[^\x21\x23-\x2b\x2d-\x3a\x3c-\x5b\x5d-\x7e]/;
+var cookieValueDQuoteValidateRegEx = /^"[^"]*"$/;
+var controlCharsAndSemicolonRegEx = /[\x00-\x20\x3b]/g;
+
+var cookieSeparatorRegEx = /[;,] */;
+
+var httpStatusDescriptions = {
+ 100: 'Continue',
+ 101: 'Switching Protocols',
+ 200: 'OK',
+ 201: 'Created',
+ 203: 'Non-Authoritative Information',
+ 204: 'No Content',
+ 205: 'Reset Content',
+ 206: 'Partial Content',
+ 300: 'Multiple Choices',
+ 301: 'Moved Permanently',
+ 302: 'Found',
+ 303: 'See Other',
+ 304: 'Not Modified',
+ 305: 'Use Proxy',
+ 307: 'Temporary Redirect',
+ 400: 'Bad Request',
+ 401: 'Unauthorized',
+ 402: 'Payment Required',
+ 403: 'Forbidden',
+ 404: 'Not Found',
+ 406: 'Not Acceptable',
+ 407: 'Proxy Authorization Required',
+ 408: 'Request Timeout',
+ 409: 'Conflict',
+ 410: 'Gone',
+ 411: 'Length Required',
+ 412: 'Precondition Failed',
+ 413: 'Request Entity Too Long',
+ 414: 'Request-URI Too Long',
+ 415: 'Unsupported Media Type',
+ 416: 'Requested Range Not Satisfiable',
+ 417: 'Expectation Failed',
+ 426: 'Upgrade Required',
+ 500: 'Internal Server Error',
+ 501: 'Not Implemented',
+ 502: 'Bad Gateway',
+ 503: 'Service Unavailable',
+ 504: 'Gateway Timeout',
+ 505: 'HTTP Version Not Supported'
+};
+
+function WebSocketRequest(socket, httpRequest, serverConfig) {
+ // Superclass Constructor
+ EventEmitter.call(this);
+
+ this.socket = socket;
+ this.httpRequest = httpRequest;
+ this.resource = httpRequest.url;
+ this.remoteAddress = socket.remoteAddress;
+ this.remoteAddresses = [this.remoteAddress];
+ this.serverConfig = serverConfig;
+
+ // Watch for the underlying TCP socket closing before we call accept
+ this._socketIsClosing = false;
+ this._socketCloseHandler = this._handleSocketCloseBeforeAccept.bind(this);
+ this.socket.on('end', this._socketCloseHandler);
+ this.socket.on('close', this._socketCloseHandler);
+
+ this._resolved = false;
+}
+
+util.inherits(WebSocketRequest, EventEmitter);
+
+WebSocketRequest.prototype.readHandshake = function() {
+ var self = this;
+ var request = this.httpRequest;
+
+ // Decode URL
+ this.resourceURL = url.parse(this.resource, true);
+
+ this.host = request.headers['host'];
+ if (!this.host) {
+ throw new Error('Client must provide a Host header.');
+ }
+
+ this.key = request.headers['sec-websocket-key'];
+ if (!this.key) {
+ throw new Error('Client must provide a value for Sec-WebSocket-Key.');
+ }
+
+ this.webSocketVersion = parseInt(request.headers['sec-websocket-version'], 10);
+
+ if (!this.webSocketVersion || isNaN(this.webSocketVersion)) {
+ throw new Error('Client must provide a value for Sec-WebSocket-Version.');
+ }
+
+ switch (this.webSocketVersion) {
+ case 8:
+ case 13:
+ break;
+ default:
+ var e = new Error('Unsupported websocket client version: ' + this.webSocketVersion +
+ 'Only versions 8 and 13 are supported.');
+ e.httpCode = 426;
+ e.headers = {
+ 'Sec-WebSocket-Version': '13'
+ };
+ throw e;
+ }
+
+ if (this.webSocketVersion === 13) {
+ this.origin = request.headers['origin'];
+ }
+ else if (this.webSocketVersion === 8) {
+ this.origin = request.headers['sec-websocket-origin'];
+ }
+
+ // Protocol is optional.
+ var protocolString = request.headers['sec-websocket-protocol'];
+ this.protocolFullCaseMap = {};
+ this.requestedProtocols = [];
+ if (protocolString) {
+ var requestedProtocolsFullCase = protocolString.split(headerValueSplitRegExp);
+ requestedProtocolsFullCase.forEach(function(protocol) {
+ var lcProtocol = protocol.toLocaleLowerCase();
+ self.requestedProtocols.push(lcProtocol);
+ self.protocolFullCaseMap[lcProtocol] = protocol;
+ });
+ }
+
+ if (!this.serverConfig.ignoreXForwardedFor &&
+ request.headers['x-forwarded-for']) {
+ var immediatePeerIP = this.remoteAddress;
+ this.remoteAddresses = request.headers['x-forwarded-for']
+ .split(xForwardedForSeparatorRegExp);
+ this.remoteAddresses.push(immediatePeerIP);
+ this.remoteAddress = this.remoteAddresses[0];
+ }
+
+ // Extensions are optional.
+ var extensionsString = request.headers['sec-websocket-extensions'];
+ this.requestedExtensions = this.parseExtensions(extensionsString);
+
+ // Cookies are optional
+ var cookieString = request.headers['cookie'];
+ this.cookies = this.parseCookies(cookieString);
+};
+
+WebSocketRequest.prototype.parseExtensions = function(extensionsString) {
+ if (!extensionsString || extensionsString.length === 0) {
+ return [];
+ }
+ var extensions = extensionsString.toLocaleLowerCase().split(headerValueSplitRegExp);
+ extensions.forEach(function(extension, index, array) {
+ var params = extension.split(headerParamSplitRegExp);
+ var extensionName = params[0];
+ var extensionParams = params.slice(1);
+ extensionParams.forEach(function(rawParam, index, array) {
+ var arr = rawParam.split('=');
+ var obj = {
+ name: arr[0],
+ value: arr[1]
+ };
+ array.splice(index, 1, obj);
+ });
+ var obj = {
+ name: extensionName,
+ params: extensionParams
+ };
+ array.splice(index, 1, obj);
+ });
+ return extensions;
+};
+
+// This function adapted from node-cookie
+// https://github.com/shtylman/node-cookie
+WebSocketRequest.prototype.parseCookies = function(str) {
+ // Sanity Check
+ if (!str || typeof(str) !== 'string') {
+ return [];
+ }
+
+ var cookies = [];
+ var pairs = str.split(cookieSeparatorRegEx);
+
+ pairs.forEach(function(pair) {
+ var eq_idx = pair.indexOf('=');
+ if (eq_idx === -1) {
+ cookies.push({
+ name: pair,
+ value: null
+ });
+ return;
+ }
+
+ var key = pair.substr(0, eq_idx).trim();
+ var val = pair.substr(++eq_idx, pair.length).trim();
+
+ // quoted values
+ if ('"' === val[0]) {
+ val = val.slice(1, -1);
+ }
+
+ cookies.push({
+ name: key,
+ value: decodeURIComponent(val)
+ });
+ });
+
+ return cookies;
+};
+
+WebSocketRequest.prototype.accept = function(acceptedProtocol, allowedOrigin, cookies) {
+ this._verifyResolution();
+
+ // TODO: Handle extensions
+
+ var protocolFullCase;
+
+ if (acceptedProtocol) {
+ protocolFullCase = this.protocolFullCaseMap[acceptedProtocol.toLocaleLowerCase()];
+ if (typeof(protocolFullCase) === 'undefined') {
+ protocolFullCase = acceptedProtocol;
+ }
+ }
+ else {
+ protocolFullCase = acceptedProtocol;
+ }
+ this.protocolFullCaseMap = null;
+
+ // Create key validation hash
+ var sha1 = crypto.createHash('sha1');
+ sha1.update(this.key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11');
+ var acceptKey = sha1.digest('base64');
+
+ var response = 'HTTP/1.1 101 Switching Protocols\r\n' +
+ 'Upgrade: websocket\r\n' +
+ 'Connection: Upgrade\r\n' +
+ 'Sec-WebSocket-Accept: ' + acceptKey + '\r\n';
+
+ if (protocolFullCase) {
+ // validate protocol
+ for (var i=0; i < protocolFullCase.length; i++) {
+ var charCode = protocolFullCase.charCodeAt(i);
+ var character = protocolFullCase.charAt(i);
+ if (charCode < 0x21 || charCode > 0x7E || separators.indexOf(character) !== -1) {
+ this.reject(500);
+ throw new Error('Illegal character "' + String.fromCharCode(character) + '" in subprotocol.');
+ }
+ }
+ if (this.requestedProtocols.indexOf(acceptedProtocol) === -1) {
+ this.reject(500);
+ throw new Error('Specified protocol was not requested by the client.');
+ }
+
+ protocolFullCase = protocolFullCase.replace(headerSanitizeRegExp, '');
+ response += 'Sec-WebSocket-Protocol: ' + protocolFullCase + '\r\n';
+ }
+ this.requestedProtocols = null;
+
+ if (allowedOrigin) {
+ allowedOrigin = allowedOrigin.replace(headerSanitizeRegExp, '');
+ if (this.webSocketVersion === 13) {
+ response += 'Origin: ' + allowedOrigin + '\r\n';
+ }
+ else if (this.webSocketVersion === 8) {
+ response += 'Sec-WebSocket-Origin: ' + allowedOrigin + '\r\n';
+ }
+ }
+
+ if (cookies) {
+ if (!Array.isArray(cookies)) {
+ this.reject(500);
+ throw new Error('Value supplied for "cookies" argument must be an array.');
+ }
+ var seenCookies = {};
+ cookies.forEach(function(cookie) {
+ if (!cookie.name || !cookie.value) {
+ this.reject(500);
+ throw new Error('Each cookie to set must at least provide a "name" and "value"');
+ }
+
+ // Make sure there are no \r\n sequences inserted
+ cookie.name = cookie.name.replace(controlCharsAndSemicolonRegEx, '');
+ cookie.value = cookie.value.replace(controlCharsAndSemicolonRegEx, '');
+
+ if (seenCookies[cookie.name]) {
+ this.reject(500);
+ throw new Error('You may not specify the same cookie name twice.');
+ }
+ seenCookies[cookie.name] = true;
+
+ // token (RFC 2616, Section 2.2)
+ var invalidChar = cookie.name.match(cookieNameValidateRegEx);
+ if (invalidChar) {
+ this.reject(500);
+ throw new Error('Illegal character ' + invalidChar[0] + ' in cookie name');
+ }
+
+ // RFC 6265, Section 4.1.1
+ // *cookie-octet / ( DQUOTE *cookie-octet DQUOTE ) | %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
+ if (cookie.value.match(cookieValueDQuoteValidateRegEx)) {
+ invalidChar = cookie.value.slice(1, -1).match(cookieValueValidateRegEx);
+ } else {
+ invalidChar = cookie.value.match(cookieValueValidateRegEx);
+ }
+ if (invalidChar) {
+ this.reject(500);
+ throw new Error('Illegal character ' + invalidChar[0] + ' in cookie value');
+ }
+
+ var cookieParts = [cookie.name + '=' + cookie.value];
+
+ // RFC 6265, Section 4.1.1
+ // 'Path=' path-value | <any CHAR except CTLs or ';'>
+ if(cookie.path){
+ invalidChar = cookie.path.match(controlCharsAndSemicolonRegEx);
+ if (invalidChar) {
+ this.reject(500);
+ throw new Error('Illegal character ' + invalidChar[0] + ' in cookie path');
+ }
+ cookieParts.push('Path=' + cookie.path);
+ }
+
+ // RFC 6265, Section 4.1.2.3
+ // 'Domain=' subdomain
+ if (cookie.domain) {
+ if (typeof(cookie.domain) !== 'string') {
+ this.reject(500);
+ throw new Error('Domain must be specified and must be a string.');
+ }
+ invalidChar = cookie.domain.match(controlCharsAndSemicolonRegEx);
+ if (invalidChar) {
+ this.reject(500);
+ throw new Error('Illegal character ' + invalidChar[0] + ' in cookie domain');
+ }
+ cookieParts.push('Domain=' + cookie.domain.toLowerCase());
+ }
+
+ // RFC 6265, Section 4.1.1
+ //'Expires=' sane-cookie-date | Force Date object requirement by using only epoch
+ if (cookie.expires) {
+ if (!(cookie.expires instanceof Date)){
+ this.reject(500);
+ throw new Error('Value supplied for cookie "expires" must be a vaild date object');
+ }
+ cookieParts.push('Expires=' + cookie.expires.toGMTString());
+ }
+
+ // RFC 6265, Section 4.1.1
+ //'Max-Age=' non-zero-digit *DIGIT
+ if (cookie.maxage) {
+ var maxage = cookie.maxage;
+ if (typeof(maxage) === 'string') {
+ maxage = parseInt(maxage, 10);
+ }
+ if (isNaN(maxage) || maxage <= 0 ) {
+ this.reject(500);
+ throw new Error('Value supplied for cookie "maxage" must be a non-zero number');
+ }
+ maxage = Math.round(maxage);
+ cookieParts.push('Max-Age=' + maxage.toString(10));
+ }
+
+ // RFC 6265, Section 4.1.1
+ //'Secure;'
+ if (cookie.secure) {
+ if (typeof(cookie.secure) !== 'boolean') {
+ this.reject(500);
+ throw new Error('Value supplied for cookie "secure" must be of type boolean');
+ }
+ cookieParts.push('Secure');
+ }
+
+ // RFC 6265, Section 4.1.1
+ //'HttpOnly;'
+ if (cookie.httponly) {
+ if (typeof(cookie.httponly) !== 'boolean') {
+ this.reject(500);
+ throw new Error('Value supplied for cookie "httponly" must be of type boolean');
+ }
+ cookieParts.push('HttpOnly');
+ }
+
+ response += ('Set-Cookie: ' + cookieParts.join(';') + '\r\n');
+ }.bind(this));
+ }
+
+ // TODO: handle negotiated extensions
+ // if (negotiatedExtensions) {
+ // response += 'Sec-WebSocket-Extensions: ' + negotiatedExtensions.join(', ') + '\r\n';
+ // }
+
+ // Mark the request resolved now so that the user can't call accept or
+ // reject a second time.
+ this._resolved = true;
+ this.emit('requestResolved', this);
+
+ response += '\r\n';
+
+ var connection = new WebSocketConnection(this.socket, [], acceptedProtocol, false, this.serverConfig);
+ connection.webSocketVersion = this.webSocketVersion;
+ connection.remoteAddress = this.remoteAddress;
+ connection.remoteAddresses = this.remoteAddresses;
+
+ var self = this;
+
+ if (this._socketIsClosing) {
+ // Handle case when the client hangs up before we get a chance to
+ // accept the connection and send our side of the opening handshake.
+ cleanupFailedConnection(connection);
+ }
+ else {
+ this.socket.write(response, 'ascii', function(error) {
+ if (error) {
+ cleanupFailedConnection(connection);
+ return;
+ }
+
+ self._removeSocketCloseListeners();
+ connection._addSocketEventListeners();
+ });
+ }
+
+ this.emit('requestAccepted', connection);
+ return connection;
+};
+
+WebSocketRequest.prototype.reject = function(status, reason, extraHeaders) {
+ this._verifyResolution();
+
+ // Mark the request resolved now so that the user can't call accept or
+ // reject a second time.
+ this._resolved = true;
+ this.emit('requestResolved', this);
+
+ if (typeof(status) !== 'number') {
+ status = 403;
+ }
+ var response = 'HTTP/1.1 ' + status + ' ' + httpStatusDescriptions[status] + '\r\n' +
+ 'Connection: close\r\n';
+ if (reason) {
+ reason = reason.replace(headerSanitizeRegExp, '');
+ response += 'X-WebSocket-Reject-Reason: ' + reason + '\r\n';
+ }
+
+ if (extraHeaders) {
+ for (var key in extraHeaders) {
+ var sanitizedValue = extraHeaders[key].toString().replace(headerSanitizeRegExp, '');
+ var sanitizedKey = key.replace(headerSanitizeRegExp, '');
+ response += (sanitizedKey + ': ' + sanitizedValue + '\r\n');
+ }
+ }
+
+ response += '\r\n';
+ this.socket.end(response, 'ascii');
+
+ this.emit('requestRejected', this);
+};
+
+WebSocketRequest.prototype._handleSocketCloseBeforeAccept = function() {
+ this._socketIsClosing = true;
+ this._removeSocketCloseListeners();
+};
+
+WebSocketRequest.prototype._removeSocketCloseListeners = function() {
+ this.socket.removeListener('end', this._socketCloseHandler);
+ this.socket.removeListener('close', this._socketCloseHandler);
+};
+
+WebSocketRequest.prototype._verifyResolution = function() {
+ if (this._resolved) {
+ throw new Error('WebSocketRequest may only be accepted or rejected one time.');
+ }
+};
+
+function cleanupFailedConnection(connection) {
+ // Since we have to return a connection object even if the socket is
+ // already dead in order not to break the API, we schedule a 'close'
+ // event on the connection object to occur immediately.
+ process.nextTick(function() {
+ // WebSocketConnection.CLOSE_REASON_ABNORMAL = 1006
+ // Third param: Skip sending the close frame to a dead socket
+ connection.drop(1006, 'TCP connection lost before handshake completed.', true);
+ });
+}
+
+module.exports = WebSocketRequest;
--- /dev/null
+/************************************************************************
+ * Copyright 2010-2015 Brian McKelvey.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+
+var extend = require('./utils').extend;
+var util = require('util');
+var EventEmitter = require('events').EventEmitter;
+var WebSocketRouterRequest = require('./WebSocketRouterRequest');
+
+function WebSocketRouter(config) {
+ // Superclass Constructor
+ EventEmitter.call(this);
+
+ this.config = {
+ // The WebSocketServer instance to attach to.
+ server: null
+ };
+ if (config) {
+ extend(this.config, config);
+ }
+ this.handlers = [];
+
+ this._requestHandler = this.handleRequest.bind(this);
+ if (this.config.server) {
+ this.attachServer(this.config.server);
+ }
+}
+
+util.inherits(WebSocketRouter, EventEmitter);
+
+WebSocketRouter.prototype.attachServer = function(server) {
+ if (server) {
+ this.server = server;
+ this.server.on('request', this._requestHandler);
+ }
+ else {
+ throw new Error('You must specify a WebSocketServer instance to attach to.');
+ }
+};
+
+WebSocketRouter.prototype.detachServer = function() {
+ if (this.server) {
+ this.server.removeListener('request', this._requestHandler);
+ this.server = null;
+ }
+ else {
+ throw new Error('Cannot detach from server: not attached.');
+ }
+};
+
+WebSocketRouter.prototype.mount = function(path, protocol, callback) {
+ if (!path) {
+ throw new Error('You must specify a path for this handler.');
+ }
+ if (!protocol) {
+ protocol = '____no_protocol____';
+ }
+ if (!callback) {
+ throw new Error('You must specify a callback for this handler.');
+ }
+
+ path = this.pathToRegExp(path);
+ if (!(path instanceof RegExp)) {
+ throw new Error('Path must be specified as either a string or a RegExp.');
+ }
+ var pathString = path.toString();
+
+ // normalize protocol to lower-case
+ protocol = protocol.toLocaleLowerCase();
+
+ if (this.findHandlerIndex(pathString, protocol) !== -1) {
+ throw new Error('You may only mount one handler per path/protocol combination.');
+ }
+
+ this.handlers.push({
+ 'path': path,
+ 'pathString': pathString,
+ 'protocol': protocol,
+ 'callback': callback
+ });
+};
+WebSocketRouter.prototype.unmount = function(path, protocol) {
+ var index = this.findHandlerIndex(this.pathToRegExp(path).toString(), protocol);
+ if (index !== -1) {
+ this.handlers.splice(index, 1);
+ }
+ else {
+ throw new Error('Unable to find a route matching the specified path and protocol.');
+ }
+};
+
+WebSocketRouter.prototype.findHandlerIndex = function(pathString, protocol) {
+ protocol = protocol.toLocaleLowerCase();
+ for (var i=0, len=this.handlers.length; i < len; i++) {
+ var handler = this.handlers[i];
+ if (handler.pathString === pathString && handler.protocol === protocol) {
+ return i;
+ }
+ }
+ return -1;
+};
+
+WebSocketRouter.prototype.pathToRegExp = function(path) {
+ if (typeof(path) === 'string') {
+ if (path === '*') {
+ path = /^.*$/;
+ }
+ else {
+ path = path.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
+ path = new RegExp('^' + path + '$');
+ }
+ }
+ return path;
+};
+
+WebSocketRouter.prototype.handleRequest = function(request) {
+ var requestedProtocols = request.requestedProtocols;
+ if (requestedProtocols.length === 0) {
+ requestedProtocols = ['____no_protocol____'];
+ }
+
+ // Find a handler with the first requested protocol first
+ for (var i=0; i < requestedProtocols.length; i++) {
+ var requestedProtocol = requestedProtocols[i].toLocaleLowerCase();
+
+ // find the first handler that can process this request
+ for (var j=0, len=this.handlers.length; j < len; j++) {
+ var handler = this.handlers[j];
+ if (handler.path.test(request.resourceURL.pathname)) {
+ if (requestedProtocol === handler.protocol ||
+ handler.protocol === '*')
+ {
+ var routerRequest = new WebSocketRouterRequest(request, requestedProtocol);
+ handler.callback(routerRequest);
+ return;
+ }
+ }
+ }
+ }
+
+ // If we get here we were unable to find a suitable handler.
+ request.reject(404, 'No handler is available for the given request.');
+};
+
+module.exports = WebSocketRouter;
--- /dev/null
+/************************************************************************
+ * Copyright 2010-2015 Brian McKelvey.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+
+var util = require('util');
+var EventEmitter = require('events').EventEmitter;
+
+function WebSocketRouterRequest(webSocketRequest, resolvedProtocol) {
+ // Superclass Constructor
+ EventEmitter.call(this);
+
+ this.webSocketRequest = webSocketRequest;
+ if (resolvedProtocol === '____no_protocol____') {
+ this.protocol = null;
+ }
+ else {
+ this.protocol = resolvedProtocol;
+ }
+ this.origin = webSocketRequest.origin;
+ this.resource = webSocketRequest.resource;
+ this.resourceURL = webSocketRequest.resourceURL;
+ this.httpRequest = webSocketRequest.httpRequest;
+ this.remoteAddress = webSocketRequest.remoteAddress;
+ this.webSocketVersion = webSocketRequest.webSocketVersion;
+ this.requestedExtensions = webSocketRequest.requestedExtensions;
+ this.cookies = webSocketRequest.cookies;
+}
+
+util.inherits(WebSocketRouterRequest, EventEmitter);
+
+WebSocketRouterRequest.prototype.accept = function(origin, cookies) {
+ var connection = this.webSocketRequest.accept(this.protocol, origin, cookies);
+ this.emit('requestAccepted', connection);
+ return connection;
+};
+
+WebSocketRouterRequest.prototype.reject = function(status, reason, extraHeaders) {
+ this.webSocketRequest.reject(status, reason, extraHeaders);
+ this.emit('requestRejected', this);
+};
+
+module.exports = WebSocketRouterRequest;
--- /dev/null
+/************************************************************************
+ * Copyright 2010-2015 Brian McKelvey.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ ***********************************************************************/
+
+var extend = require('./utils').extend;
+var utils = require('./utils');
+var util = require('util');
+var debug = require('debug')('websocket:server');
+var EventEmitter = require('events').EventEmitter;
+var WebSocketRequest = require('./WebSocketRequest');
+
+var WebSocketServer = function WebSocketServer(config) {
+ // Superclass Constructor
+ EventEmitter.call(this);
+
+ this._handlers = {
+ upgrade: this.handleUpgrade.bind(this),
+ requestAccepted: this.handleRequestAccepted.bind(this),
+ requestResolved: this.handleRequestResolved.bind(this)
+ };
+ this.connections = [];
+ this.pendingRequests = [];
+ if (config) {
+ this.mount(config);
+ }
+};
+
+util.inherits(WebSocketServer, EventEmitter);
+
+WebSocketServer.prototype.mount = function(config) {
+ this.config = {
+ // The http server instance to attach to. Required.
+ httpServer: null,
+
+ // 64KiB max frame size.
+ maxReceivedFrameSize: 0x10000,
+
+ // 1MiB max message size, only applicable if
+ // assembleFragments is true
+ maxReceivedMessageSize: 0x100000,
+
+ // Outgoing messages larger than fragmentationThreshold will be
+ // split into multiple fragments.
+ fragmentOutgoingMessages: true,
+
+ // Outgoing frames are fragmented if they exceed this threshold.
+ // Default is 16KiB
+ fragmentationThreshold: 0x4000,
+
+ // If true, the server will automatically send a ping to all
+ // clients every 'keepaliveInterval' milliseconds. The timer is
+ // reset on any received data from the client.
+ keepalive: true,
+
+ // The interval to send keepalive pings to connected clients if the
+ // connection is idle. Any received data will reset the counter.
+ keepaliveInterval: 20000,
+
+ // If true, the server will consider any connection that has not
+ // received any data within the amount of time specified by
+ // 'keepaliveGracePeriod' after a keepalive ping has been sent to
+ // be dead, and will drop the connection.
+ // Ignored if keepalive is false.
+ dropConnectionOnKeepaliveTimeout: true,
+
+ // The amount of time to wait after sending a keepalive ping before
+ // closing the connection if the connected peer does not respond.
+ // Ignored if keepalive is false.
+ keepaliveGracePeriod: 10000,
+
+ // Whether to use native TCP keep-alive instead of WebSockets ping
+ // and pong packets. Native TCP keep-alive sends smaller packets
+ // on the wire and so uses bandwidth more efficiently. This may
+ // be more important when talking to mobile devices.
+ // If this value is set to true, then these values will be ignored:
+ // keepaliveGracePeriod
+ // dropConnectionOnKeepaliveTimeout
+ useNativeKeepalive: false,
+
+ // If true, fragmented messages will be automatically assembled
+ // and the full message will be emitted via a 'message' event.
+ // If false, each frame will be emitted via a 'frame' event and
+ // the application will be responsible for aggregating multiple
+ // fragmented frames. Single-frame messages will emit a 'message'
+ // event in addition to the 'frame' event.
+ // Most users will want to leave this set to 'true'
+ assembleFragments: true,
+
+ // If this is true, websocket connections will be accepted
+ // regardless of the path and protocol specified by the client.
+ // The protocol accepted will be the first that was requested
+ // by the client. Clients from any origin will be accepted.
+ // This should only be used in the simplest of cases. You should
+ // probably leave this set to 'false' and inspect the request
+ // object to make sure it's acceptable before accepting it.
+ autoAcceptConnections: false,
+
+ // Whether or not the X-Forwarded-For header should be respected.
+ // It's important to set this to 'true' when accepting connections
+ // from untrusted clients, as a malicious client could spoof its
+ // IP address by simply setting this header. It's meant to be added
+ // by a trusted proxy or other intermediary within your own
+ // infrastructure.
+ // See: http://en.wikipedia.org/wiki/X-Forwarded-For
+ ignoreXForwardedFor: false,
+
+ // The Nagle Algorithm makes more efficient use of network resources
+ // by introducing a small delay before sending small packets so that
+ // multiple messages can be batched together before going onto the
+ // wire. This however comes at the cost of latency, so the default
+ // is to disable it. If you don't need low latency and are streaming
+ // lots of small messages, you can change this to 'false'
+ disableNagleAlgorithm: true,
+
+ // The number of milliseconds to wait after sending a close frame
+ // for an acknowledgement to come back before giving up and just
+ // closing the socket.
+ closeTimeout: 5000
+ };
+ extend(this.config, config);
+
+ if (this.config.httpServer) {
+ if (!Array.isArray(this.config.httpServer)) {
+ this.config.httpServer = [this.config.httpServer];
+ }
+ var upgradeHandler = this._handlers.upgrade;
+ this.config.httpServer.forEach(function(httpServer) {
+ httpServer.on('upgrade', upgradeHandler);
+ });
+ }
+ else {
+ throw new Error('You must specify an httpServer on which to mount the WebSocket server.');
+ }
+};
+
+WebSocketServer.prototype.unmount = function() {
+ var upgradeHandler = this._handlers.upgrade;
+ this.config.httpServer.forEach(function(httpServer) {
+ httpServer.removeListener('upgrade', upgradeHandler);
+ });
+};
+
+WebSocketServer.prototype.closeAllConnections = function() {
+ this.connections.forEach(function(connection) {
+ connection.close();
+ });
+ this.pendingRequests.forEach(function(request) {
+ process.nextTick(function() {
+ request.reject(503); // HTTP 503 Service Unavailable
+ });
+ });
+};
+
+WebSocketServer.prototype.broadcast = function(data) {
+ if (Buffer.isBuffer(data)) {
+ this.broadcastBytes(data);
+ }
+ else if (typeof(data.toString) === 'function') {
+ this.broadcastUTF(data);
+ }
+};
+
+WebSocketServer.prototype.broadcastUTF = function(utfData) {
+ this.connections.forEach(function(connection) {
+ connection.sendUTF(utfData);
+ });
+};
+
+WebSocketServer.prototype.broadcastBytes = function(binaryData) {
+ this.connections.forEach(function(connection) {
+ connection.sendBytes(binaryData);
+ });
+};
+
+WebSocketServer.prototype.shutDown = function() {
+ this.unmount();
+ this.closeAllConnections();
+};
+
+WebSocketServer.prototype.handleUpgrade = function(request, socket) {
+ var wsRequest = new WebSocketRequest(socket, request, this.config);
+ try {
+ wsRequest.readHandshake();
+ }
+ catch(e) {
+ wsRequest.reject(
+ e.httpCode ? e.httpCode : 400,
+ e.message,
+ e.headers
+ );
+ debug('Invalid handshake: %s', e.message);
+ return;
+ }
+
+ this.pendingRequests.push(wsRequest);
+
+ wsRequest.once('requestAccepted', this._handlers.requestAccepted);
+ wsRequest.once('requestResolved', this._handlers.requestResolved);
+
+ if (!this.config.autoAcceptConnections && utils.eventEmitterListenerCount(this, 'request') > 0) {
+ this.emit('request', wsRequest);
+ }
+ else if (this.config.autoAcceptConnections) {
+ wsRequest.accept(wsRequest.requestedProtocols[0], wsRequest.origin);
+ }
+ else {
+ wsRequest.reject(404, 'No handler is configured to accept the connection.');
+ }
+};
+
+WebSocketServer.prototype.handleRequestAccepted = function(connection) {
+ var self = this;
+ connection.once('close', function(closeReason, description) {
+ self.handleConnectionClose(connection, closeReason, description);
+ });
+ this.connections.push(connection);
+ this.emit('connect', connection);
+};
+
+WebSocketServer.prototype.handleConnectionClose = function(connection, closeReason, description) {
+ var index = this.connections.indexOf(connection);
+ if (index !== -1) {
+ this.connections.splice(index, 1);
+ }
+ this.emit('close', connection, closeReason, description);
+};
+
+WebSocketServer.prototype.handleRequestResolved = function(request) {
+ var index = this.pendingRequests.indexOf(request);
+ if (index !== -1) { this.pendingRequests.splice(index, 1); }
+};
+
+module.exports = WebSocketServer;
--- /dev/null
+var _global = (function () {
+ if (!this && typeof global !== 'undefined') {
+ return global;
+ }
+ return this;
+})();
+var NativeWebSocket = _global.WebSocket || _global.MozWebSocket;
+var websocket_version = require('./version');
+
+
+/**
+ * Expose a W3C WebSocket class with just one or two arguments.
+ */
+function W3CWebSocket(uri, protocols) {
+ var native_instance;
+
+ if (protocols) {
+ native_instance = new NativeWebSocket(uri, protocols);
+ }
+ else {
+ native_instance = new NativeWebSocket(uri);
+ }
+
+ /**
+ * 'native_instance' is an instance of nativeWebSocket (the browser's WebSocket
+ * class). Since it is an Object it will be returned as it is when creating an
+ * instance of W3CWebSocket via 'new W3CWebSocket()'.
+ *
+ * ECMAScript 5: http://bclary.com/2004/11/07/#a-13.2.2
+ */
+ return native_instance;
+}
+if (NativeWebSocket) {
+ ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'].forEach(function(prop) {
+ Object.defineProperty(W3CWebSocket, prop, {
+ get: function() { return NativeWebSocket[prop]; }
+ });
+ });
+}
+
+/**
+ * Module exports.
+ */
+module.exports = {
+ 'w3cwebsocket' : NativeWebSocket ? W3CWebSocket : null,
+ 'version' : websocket_version
+};
--- /dev/null
+var noop = exports.noop = function(){};
+
+exports.extend = function extend(dest, source) {
+ for (var prop in source) {
+ dest[prop] = source[prop];
+ }
+};
+
+exports.eventEmitterListenerCount =
+ require('events').EventEmitter.listenerCount ||
+ function(emitter, type) { return emitter.listeners(type).length; };
+
+exports.bufferAllocUnsafe = Buffer.allocUnsafe ?
+ Buffer.allocUnsafe :
+ function oldBufferAllocUnsafe(size) { return new Buffer(size); };
+
+exports.bufferFromString = Buffer.from ?
+ Buffer.from :
+ function oldBufferFromString(string, encoding) {
+ return new Buffer(string, encoding);
+ };
+
+exports.BufferingLogger = function createBufferingLogger(identifier, uniqueID) {
+ var logFunction = require('debug')(identifier);
+ if (logFunction.enabled) {
+ var logger = new BufferingLogger(identifier, uniqueID, logFunction);
+ var debug = logger.log.bind(logger);
+ debug.printOutput = logger.printOutput.bind(logger);
+ debug.enabled = logFunction.enabled;
+ return debug;
+ }
+ logFunction.printOutput = noop;
+ return logFunction;
+};
+
+function BufferingLogger(identifier, uniqueID, logFunction) {
+ this.logFunction = logFunction;
+ this.identifier = identifier;
+ this.uniqueID = uniqueID;
+ this.buffer = [];
+}
+
+BufferingLogger.prototype.log = function() {
+ this.buffer.push([ new Date(), Array.prototype.slice.call(arguments) ]);
+ return this;
+};
+
+BufferingLogger.prototype.clear = function() {
+ this.buffer = [];
+ return this;
+};
+
+BufferingLogger.prototype.printOutput = function(logFunction) {
+ if (!logFunction) { logFunction = this.logFunction; }
+ var uniqueID = this.uniqueID;
+ this.buffer.forEach(function(entry) {
+ var date = entry[0].toLocaleString();
+ var args = entry[1].slice();
+ var formatString = args[0];
+ if (formatString !== (void 0) && formatString !== null) {
+ formatString = '%s - %s - ' + formatString.toString();
+ args.splice(0, 1, formatString, date, uniqueID);
+ logFunction.apply(global, args);
+ }
+ });
+};
--- /dev/null
+module.exports = require('../package.json').version;
--- /dev/null
+module.exports = {
+ 'server' : require('./WebSocketServer'),
+ 'client' : require('./WebSocketClient'),
+ 'router' : require('./WebSocketRouter'),
+ 'frame' : require('./WebSocketFrame'),
+ 'request' : require('./WebSocketRequest'),
+ 'connection' : require('./WebSocketConnection'),
+ 'w3cwebsocket' : require('./W3CWebSocket'),
+ 'deprecation' : require('./Deprecation'),
+ 'version' : require('./version')
+};
--- /dev/null
+# NAN ChangeLog
+
+**Version 2.14.0: current Node 12.2.0, Node 0.12: 0.12.18, Node 0.10: 0.10.48, iojs: 3.3.1**
+
+### 2.14.0 May 16 2019
+
+ - Feature: Add missing methods to Nan::Maybe<T> (#852) 4e962489fb84a184035b9fa74f245f650249aca6
+
+### 2.13.2 Mar 24 2019
+
+ - Bugfix: remove usage of deprecated `IsNearDeath` (#842) fbaf42252af279c3d867c6b193571f9711c39847
+
+### 2.13.1 Mar 14 2019
+
+ - Bugfix: check V8 version directly instead of inferring from NMV (#840) 12f9df9f393285de8fb4a8cd01478dc4fe3b089d
+
+### 2.13.0 Mar 13 2019
+
+ - Feature: add support for node master (#831) 113c0282072e7ff4f9dfc98b432fd894b798c2c
+
+### 2.12.1 Dec 18 2018
+
+ - Bugfix: Fix build breakage with Node.js 10.0.0-10.9.0. (#833) 625e90e8fef8d39ffa7247250a76a100b2487474
+
+### 2.12.0 Dec 16 2018
+
+ - Bugfix: Add scope.Escape() to Call() (#817) 2e5ed4fc3a8ac80a6ef1f2a55099ab3ac8800dc6
+ - Bugfix: Fix Node.js v10.12.0 deprecation warnings. 509859cc23b1770376b56550a027840a2ce0f73d
+ - Feature: Allow SetWeak() for non-object persistent handles. (#824) e6ef6a48e7e671fe3e4b7dddaa8912a3f8262ecd
+
+### 2.11.1 Sep 29 2018
+
+ - Fix: adapt to V8 7.0 24a22c3b25eeeec2016c6ec239bdd6169e985447
+
+### 2.11.0 Aug 25 2018
+
+ - Removal: remove `FunctionCallbackInfo::Callee` for nodejs `>= 10` 1a56c0a6efd4fac944cb46c30912a8e023bda7d4
+ - Bugfix: Fix `AsyncProgressWorkerBase::WorkProgress` sends invalid data b0c764d1dab11e9f8b37ffb81e2560a4498aad5e
+ - Feature: Introduce `GetCurrentEventLoop` b4911b0bb1f6d47d860e10ec014d941c51efac5e
+ - Feature: Add `NAN_MODULE_WORKER_ENABLED` macro as a replacement for `NAN_MODULE` b058fb047d18a58250e66ae831444441c1f2ac7a
+
+### 2.10.0 Mar 16 2018
+
+ - Deprecation: Deprecate `MakeCallback` 5e92b19a59e194241d6a658bd6ff7bfbda372950
+ - Feature: add `Nan::Call` overload 4482e1242fe124d166fc1a5b2be3c1cc849fe452
+ - Feature: add more `Nan::Call` overloads 8584e63e6d04c7d2eb8c4a664e4ef57d70bf672b
+ - Feature: Fix deprecation warnings for Node 10 1caf258243b0602ed56922bde74f1c91b0cbcb6a
+
+### 2.9.2 Feb 22 2018
+
+ - Bugfix: Bandaid for async hooks 212bd2f849be14ef1b02fc85010b053daa24252b
+
+### 2.9.1 Feb 22 2018
+
+ - Bugfix: Avoid deprecation warnings in deprecated `Nan::Callback::operator()` 372b14d91289df4604b0f81780709708c45a9aa4
+ - Bugfix: Avoid deprecation warnings in `Nan::JSON` 3bc294bce0b7d0a3ee4559926303e5ed4866fda2
+
+### 2.9.0 Feb 22 2018
+
+ - Deprecation: Deprecate legacy `Callback::Call` 6dd5fa690af61ca3523004b433304c581b3ea309
+ - Feature: introduce `AsyncResource` class 90c0a179c0d8cb5fd26f1a7d2b1d6231eb402d48o
+ - Feature: Add context aware `Nan::Callback::Call` functions 7169e09fb088418b6e388222e88b4c13f07ebaee
+ - Feature: Make `AsyncWorker` context aware 066ba21a6fb9e2b5230c9ed3a6fc51f1211736a4
+ - Feature: add `Callback` overload to `Nan::Call` 5328daf66e202658c1dc0d916c3aaba99b3cc606
+ - Bugfix: fix warning: suggest parentheses around `&&` within `||` b2bb63d68b8ae623a526b542764e1ac82319cb2c
+ - Bugfix: Fix compilation on io.js 3 d06114dba0a522fb436f0c5f47b994210968cd7b
+
+### 2.8.0 Nov 15 2017
+
+ - Deprecation: Deprecate `Nan::ForceSet` in favor of `Nan::DefineOwnProperty()` 95cbb976d6fbbba88ba0f86dd188223a8591b4e7
+ - Feature: Add `Nan::AsyncProgressQueueWorker` a976636ecc2ef617d1b061ce4a6edf39923691cb
+ - Feature: Add `Nan::DefineOwnProperty()` 95cbb976d6fbbba88ba0f86dd188223a8591b4e7
+ - Bugfix: Fix compiling on io.js 1 & 2 82705a64503ce60c62e98df5bd02972bba090900
+ - Bugfix: Use DefineOwnProperty instead of ForceSet 95cbb976d6fbbba88ba0f86dd188223a8591b4e7
+
+### 2.7.0 Aug 30 2017
+
+ - Feature: Add `Nan::To<v8::Function>()` overload. b93280670c9f6da42ed4cf6cbf085ffdd87bd65b
+ - Bugfix: Fix ternary in `Nan::MaybeLocal<T>::FromMaybe<S>()`. 79a26f7d362e756a9524e672a82c3d603b542867
+
+### 2.6.2 Apr 12 2017
+
+ - Bugfix: Fix v8::JSON::Parse() deprecation warning. 87f6a3c65815fa062296a994cc863e2fa124867d
+
+### 2.6.1 Apr 6 2017
+
+ - Bugfix: nan_json.h: fix build breakage in Node 6 ac8d47dc3c10bfbf3f15a6b951633120c0ee6d51
+
+### 2.6.0 Apr 6 2017
+
+ - Feature: nan: add support for JSON::Parse & Stringify b533226c629cce70e1932a873bb6f849044a56c5
+
+### 2.5.1 Jan 23 2017
+
+ - Bugfix: Fix disappearing handle for private value 6a80995694f162ef63dbc9948fbefd45d4485aa0
+ - Bugfix: Add missing scopes a93b8bae6bc7d32a170db6e89228b7f60ee57112
+ - Bugfix: Use string::data instead of string::front in NewOneByteString d5f920371e67e1f3b268295daee6e83af86b6e50
+
+### 2.5.0 Dec 21 2016
+
+ - Feature: Support Private accessors a86255cb357e8ad8ccbf1f6a4a901c921e39a178
+ - Bugfix: Abort in delete operators that shouldn't be called 0fe38215ff8581703967dfd26c12793feb960018
+
+### 2.4.0 Jul 10 2016
+
+ - Feature: Rewrite Callback to add Callback::Reset c4cf44d61f8275cd5f7b0c911d7a806d4004f649
+ - Feature: AsyncProgressWorker: add template types for .send 1242c9a11a7ed481c8f08ec06316385cacc513d0
+ - Bugfix: Add constness to old Persistent comparison operators bd43cb9982c7639605d60fd073efe8cae165d9b2
+
+### 2.3.5 May 31 2016
+
+ - Bugfix: Replace NAN_INLINE with 'inline' keyword. 71819d8725f822990f439479c9aba3b240804909
+
+### 2.3.4 May 31 2016
+
+ - Bugfix: Remove V8 deprecation warnings 0592fb0a47f3a1c7763087ebea8e1138829f24f9
+ - Bugfix: Fix new versions not to use WeakCallbackInfo::IsFirstPass 615c19d9e03d4be2049c10db0151edbc3b229246
+ - Bugfix: Make ObjectWrap::handle() const d19af99595587fe7a26bd850af6595c2a7145afc
+ - Bugfix: Fix compilation errors related to 0592fb0a47f3a1c7763087ebea8e1138829f24f9 e9191c525b94f652718325e28610a1adcf90fed8
+
+### 2.3.3 May 4 2016
+
+ - Bugfix: Refactor SetMethod() to deal with v8::Templates (#566) b9083cf6d5de6ebe6bcb49c7502fbb7c0d9ddda8
+
+### 2.3.2 Apr 27 2016
+
+ - Bugfix: Fix compilation on outdated versions due to Handle removal f8b7c875d04d425a41dfd4f3f8345bc3a11e6c52
+
+### 2.3.1 Apr 27 2016
+
+ - Bugfix: Don't use deprecated v8::Template::Set() in SetMethod a90951e9ea70fa1b3836af4b925322919159100e
+
+### 2.3.0 Apr 27 2016
+
+ - Feature: added Signal() for invoking async callbacks without sending data from AsyncProgressWorker d8adba45f20e077d00561b20199133620c990b38
+ - Bugfix: Don't use deprecated v8::Template::Set() 00dacf0a4b86027415867fa7f1059acc499dcece
+
+### 2.2.1 Mar 29 2016
+
+ - Bugfix: Use NewFromUnsigned in ReturnValue<T>::Set(uint32_t i) for pre_12 3a18f9bdce29826e0e4c217854bc476918241a58
+ - Performance: Remove unneeeded nullptr checks b715ef44887931c94f0d1605b3b1a4156eebece9
+
+### 2.2.0 Jan 9 2016
+
+ - Feature: Add Function::Call wrapper 4c157474dacf284d125c324177b45aa5dabc08c6
+ - Feature: Rename GC*logueCallback to GCCallback for > 4.0 3603435109f981606d300eb88004ca101283acec
+ - Bugfix: Fix Global::Pass for old versions 367e82a60fbaa52716232cc89db1cc3f685d77d9
+ - Bugfix: Remove weird MaybeLocal wrapping of what already is a MaybeLocal 23b4590db10c2ba66aee2338aebe9751c4cb190b
+
+### 2.1.0 Oct 8 2015
+
+ - Deprecation: Deprecate NanErrnoException in favor of ErrnoException 0af1ca4cf8b3f0f65ed31bc63a663ab3319da55c
+ - Feature: added helper class for accessing contents of typedarrays 17b51294c801e534479d5463697a73462d0ca555
+ - Feature: [Maybe types] Add MakeMaybe(...) 48d7b53d9702b0c7a060e69ea10fea8fb48d814d
+ - Feature: new: allow utf16 string with length 66ac6e65c8ab9394ef588adfc59131b3b9d8347b
+ - Feature: Introduce SetCallHandler and SetCallAsFunctionHandler 7764a9a115d60ba10dc24d86feb0fbc9b4f75537
+ - Bugfix: Enable creating Locals from Globals under Node 0.10. 9bf9b8b190821af889790fdc18ace57257e4f9ff
+ - Bugfix: Fix issue #462 where PropertyCallbackInfo data is not stored safely. 55f50adedd543098526c7b9f4fffd607d3f9861f
+
+### 2.0.9 Sep 8 2015
+
+ - Bugfix: EscapableHandleScope in Nan::NewBuffer for Node 0.8 and 0.10 b1654d7
+
+### 2.0.8 Aug 28 2015
+
+ - Work around duplicate linking bug in clang 11902da
+
+### 2.0.7 Aug 26 2015
+
+ - Build: Repackage
+
+### 2.0.6 Aug 26 2015
+
+ - Bugfix: Properly handle null callback in FunctionTemplate factory 6e99cb1
+ - Bugfix: Remove unused static std::map instances 525bddc
+ - Bugfix: Make better use of maybe versions of APIs bfba85b
+ - Bugfix: Fix shadowing issues with handle in ObjectWrap 0a9072d
+
+### 2.0.5 Aug 10 2015
+
+ - Bugfix: Reimplement weak callback in ObjectWrap 98d38c1
+ - Bugfix: Make sure callback classes are not assignable, copyable or movable 81f9b1d
+
+### 2.0.4 Aug 6 2015
+
+ - Build: Repackage
+
+### 2.0.3 Aug 6 2015
+
+ - Bugfix: Don't use clang++ / g++ syntax extension. 231450e
+
+### 2.0.2 Aug 6 2015
+
+ - Build: Repackage
+
+### 2.0.1 Aug 6 2015
+
+ - Bugfix: Add workaround for missing REPLACE_INVALID_UTF8 60d6687
+ - Bugfix: Reimplement ObjectWrap from scratch to prevent memory leaks 6484601
+ - Bugfix: Fix Persistent leak in FunctionCallbackInfo and PropertyCallbackInfo 641ef5f
+ - Bugfix: Add missing overload for Nan::NewInstance that takes argc/argv 29450ed
+
+### 2.0.0 Jul 31 2015
+
+ - Change: Renamed identifiers with leading underscores b5932b4
+ - Change: Replaced NanObjectWrapHandle with class NanObjectWrap 464f1e1
+ - Change: Replace NanScope and NanEscpableScope macros with classes 47751c4
+ - Change: Rename NanNewBufferHandle to NanNewBuffer 6745f99
+ - Change: Rename NanBufferUse to NanNewBuffer 3e8b0a5
+ - Change: Rename NanNewBuffer to NanCopyBuffer d6af78d
+ - Change: Remove Nan prefix from all names 72d1f67
+ - Change: Update Buffer API for new upstream changes d5d3291
+ - Change: Rename Scope and EscapableScope to HandleScope and EscapableHandleScope 21a7a6a
+ - Change: Get rid of Handles e6c0daf
+ - Feature: Support io.js 3 with V8 4.4
+ - Feature: Introduce NanPersistent 7fed696
+ - Feature: Introduce NanGlobal 4408da1
+ - Feature: Added NanTryCatch 10f1ca4
+ - Feature: Update for V8 v4.3 4b6404a
+ - Feature: Introduce NanNewOneByteString c543d32
+ - Feature: Introduce namespace Nan 67ed1b1
+ - Removal: Remove NanLocker and NanUnlocker dd6e401
+ - Removal: Remove string converters, except NanUtf8String, which now follows the node implementation b5d00a9
+ - Removal: Remove NanReturn* macros d90a25c
+ - Removal: Remove HasInstance e8f84fe
+
+
+### 1.9.0 Jul 31 2015
+
+ - Feature: Added `NanFatalException` 81d4a2c
+ - Feature: Added more error types 4265f06
+ - Feature: Added dereference and function call operators to NanCallback c4b2ed0
+ - Feature: Added indexed GetFromPersistent and SaveToPersistent edd510c
+ - Feature: Added more overloads of SaveToPersistent and GetFromPersistent 8b1cef6
+ - Feature: Added NanErrnoException dd87d9e
+ - Correctness: Prevent assign, copy, and move for classes that do not support it 1f55c59, 4b808cb, c96d9b2, fba4a29, 3357130
+ - Deprecation: Deprecate `NanGetPointerSafe` and `NanSetPointerSafe` 81d4a2c
+ - Deprecation: Deprecate `NanBooleanOptionValue` and `NanUInt32OptionValue` 0ad254b
+
+### 1.8.4 Apr 26 2015
+
+ - Build: Repackage
+
+### 1.8.3 Apr 26 2015
+
+ - Bugfix: Include missing header 1af8648
+
+### 1.8.2 Apr 23 2015
+
+ - Build: Repackage
+
+### 1.8.1 Apr 23 2015
+
+ - Bugfix: NanObjectWrapHandle should take a pointer 155f1d3
+
+### 1.8.0 Apr 23 2015
+
+ - Feature: Allow primitives with NanReturnValue 2e4475e
+ - Feature: Added comparison operators to NanCallback 55b075e
+ - Feature: Backport thread local storage 15bb7fa
+ - Removal: Remove support for signatures with arguments 8a2069d
+ - Correcteness: Replaced NanObjectWrapHandle macro with function 0bc6d59
+
+### 1.7.0 Feb 28 2015
+
+ - Feature: Made NanCallback::Call accept optional target 8d54da7
+ - Feature: Support atom-shell 0.21 0b7f1bb
+
+### 1.6.2 Feb 6 2015
+
+ - Bugfix: NanEncode: fix argument type for node::Encode on io.js 2be8639
+
+### 1.6.1 Jan 23 2015
+
+ - Build: version bump
+
+### 1.5.3 Jan 23 2015
+
+ - Build: repackage
+
+### 1.6.0 Jan 23 2015
+
+ - Deprecated `NanNewContextHandle` in favor of `NanNew<Context>` 49259af
+ - Support utility functions moved in newer v8 versions (Node 0.11.15, io.js 1.0) a0aa179
+ - Added `NanEncode`, `NanDecodeBytes` and `NanDecodeWrite` 75e6fb9
+
+### 1.5.2 Jan 23 2015
+
+ - Bugfix: Fix non-inline definition build error with clang++ 21d96a1, 60fadd4
+ - Bugfix: Readded missing String constructors 18d828f
+ - Bugfix: Add overload handling NanNew<FunctionTemplate>(..) 5ef813b
+ - Bugfix: Fix uv_work_cb versioning 997e4ae
+ - Bugfix: Add function factory and test 4eca89c
+ - Bugfix: Add object template factory and test cdcb951
+ - Correctness: Lifted an io.js related typedef c9490be
+ - Correctness: Make explicit downcasts of String lengths 00074e6
+ - Windows: Limit the scope of disabled warning C4530 83d7deb
+
+### 1.5.1 Jan 15 2015
+
+ - Build: version bump
+
+### 1.4.3 Jan 15 2015
+
+ - Build: version bump
+
+### 1.4.2 Jan 15 2015
+
+ - Feature: Support io.js 0dbc5e8
+
+### 1.5.0 Jan 14 2015
+
+ - Feature: Support io.js b003843
+ - Correctness: Improved NanNew internals 9cd4f6a
+ - Feature: Implement progress to NanAsyncWorker 8d6a160
+
+### 1.4.1 Nov 8 2014
+
+ - Bugfix: Handle DEBUG definition correctly
+ - Bugfix: Accept int as Boolean
+
+### 1.4.0 Nov 1 2014
+
+ - Feature: Added NAN_GC_CALLBACK 6a5c245
+ - Performance: Removed unnecessary local handle creation 18a7243, 41fe2f8
+ - Correctness: Added constness to references in NanHasInstance 02c61cd
+ - Warnings: Fixed spurious warnings from -Wundef and -Wshadow, 541b122, 99d8cb6
+ - Windoze: Shut Visual Studio up when compiling 8d558c1
+ - License: Switch to plain MIT from custom hacked MIT license 11de983
+ - Build: Added test target to Makefile e232e46
+ - Performance: Removed superfluous scope in NanAsyncWorker f4b7821
+ - Sugar/Feature: Added NanReturnThis() and NanReturnHolder() shorthands 237a5ff, d697208
+ - Feature: Added suitable overload of NanNew for v8::Integer::NewFromUnsigned b27b450
+
+### 1.3.0 Aug 2 2014
+
+ - Added NanNew<v8::String, std::string>(std::string)
+ - Added NanNew<v8::String, std::string&>(std::string&)
+ - Added NanAsciiString helper class
+ - Added NanUtf8String helper class
+ - Added NanUcs2String helper class
+ - Deprecated NanRawString()
+ - Deprecated NanCString()
+ - Added NanGetIsolateData(v8::Isolate *isolate)
+ - Added NanMakeCallback(v8::Handle<v8::Object> target, v8::Handle<v8::Function> func, int argc, v8::Handle<v8::Value>* argv)
+ - Added NanMakeCallback(v8::Handle<v8::Object> target, v8::Handle<v8::String> symbol, int argc, v8::Handle<v8::Value>* argv)
+ - Added NanMakeCallback(v8::Handle<v8::Object> target, const char* method, int argc, v8::Handle<v8::Value>* argv)
+ - Added NanSetTemplate(v8::Handle<v8::Template> templ, v8::Handle<v8::String> name , v8::Handle<v8::Data> value, v8::PropertyAttribute attributes)
+ - Added NanSetPrototypeTemplate(v8::Local<v8::FunctionTemplate> templ, v8::Handle<v8::String> name, v8::Handle<v8::Data> value, v8::PropertyAttribute attributes)
+ - Added NanSetInstanceTemplate(v8::Local<v8::FunctionTemplate> templ, const char *name, v8::Handle<v8::Data> value)
+ - Added NanSetInstanceTemplate(v8::Local<v8::FunctionTemplate> templ, v8::Handle<v8::String> name, v8::Handle<v8::Data> value, v8::PropertyAttribute attributes)
+
+### 1.2.0 Jun 5 2014
+
+ - Add NanSetPrototypeTemplate
+ - Changed NAN_WEAK_CALLBACK internals, switched _NanWeakCallbackData to class,
+ introduced _NanWeakCallbackDispatcher
+ - Removed -Wno-unused-local-typedefs from test builds
+ - Made test builds Windows compatible ('Sleep()')
+
+### 1.1.2 May 28 2014
+
+ - Release to fix more stuff-ups in 1.1.1
+
+### 1.1.1 May 28 2014
+
+ - Release to fix version mismatch in nan.h and lack of changelog entry for 1.1.0
+
+### 1.1.0 May 25 2014
+
+ - Remove nan_isolate, use v8::Isolate::GetCurrent() internally instead
+ - Additional explicit overloads for NanNew(): (char*,int), (uint8_t*[,int]),
+ (uint16_t*[,int), double, int, unsigned int, bool, v8::String::ExternalStringResource*,
+ v8::String::ExternalAsciiStringResource*
+ - Deprecate NanSymbol()
+ - Added SetErrorMessage() and ErrorMessage() to NanAsyncWorker
+
+### 1.0.0 May 4 2014
+
+ - Heavy API changes for V8 3.25 / Node 0.11.13
+ - Use cpplint.py
+ - Removed NanInitPersistent
+ - Removed NanPersistentToLocal
+ - Removed NanFromV8String
+ - Removed NanMakeWeak
+ - Removed NanNewLocal
+ - Removed NAN_WEAK_CALLBACK_OBJECT
+ - Removed NAN_WEAK_CALLBACK_DATA
+ - Introduce NanNew, replaces NanNewLocal, NanPersistentToLocal, adds many overloaded typed versions
+ - Introduce NanUndefined, NanNull, NanTrue and NanFalse
+ - Introduce NanEscapableScope and NanEscapeScope
+ - Introduce NanMakeWeakPersistent (requires a special callback to work on both old and new node)
+ - Introduce NanMakeCallback for node::MakeCallback
+ - Introduce NanSetTemplate
+ - Introduce NanGetCurrentContext
+ - Introduce NanCompileScript and NanRunScript
+ - Introduce NanAdjustExternalMemory
+ - Introduce NanAddGCEpilogueCallback, NanAddGCPrologueCallback, NanRemoveGCEpilogueCallback, NanRemoveGCPrologueCallback
+ - Introduce NanGetHeapStatistics
+ - Rename NanAsyncWorker#SavePersistent() to SaveToPersistent()
+
+### 0.8.0 Jan 9 2014
+
+ - NanDispose -> NanDisposePersistent, deprecate NanDispose
+ - Extract _NAN_*_RETURN_TYPE, pull up NAN_*()
+
+### 0.7.1 Jan 9 2014
+
+ - Fixes to work against debug builds of Node
+ - Safer NanPersistentToLocal (avoid reinterpret_cast)
+ - Speed up common NanRawString case by only extracting flattened string when necessary
+
+### 0.7.0 Dec 17 2013
+
+ - New no-arg form of NanCallback() constructor.
+ - NanCallback#Call takes Handle rather than Local
+ - Removed deprecated NanCallback#Run method, use NanCallback#Call instead
+ - Split off _NAN_*_ARGS_TYPE from _NAN_*_ARGS
+ - Restore (unofficial) Node 0.6 compatibility at NanCallback#Call()
+ - Introduce NanRawString() for char* (or appropriate void*) from v8::String
+ (replacement for NanFromV8String)
+ - Introduce NanCString() for null-terminated char* from v8::String
+
+### 0.6.0 Nov 21 2013
+
+ - Introduce NanNewLocal<T>(v8::Handle<T> value) for use in place of
+ v8::Local<T>::New(...) since v8 started requiring isolate in Node 0.11.9
+
+### 0.5.2 Nov 16 2013
+
+ - Convert SavePersistent and GetFromPersistent in NanAsyncWorker from protected and public
+
+### 0.5.1 Nov 12 2013
+
+ - Use node::MakeCallback() instead of direct v8::Function::Call()
+
+### 0.5.0 Nov 11 2013
+
+ - Added @TooTallNate as collaborator
+ - New, much simpler, "include_dirs" for binding.gyp
+ - Added full range of NAN_INDEX_* macros to match NAN_PROPERTY_* macros
+
+### 0.4.4 Nov 2 2013
+
+ - Isolate argument from v8::Persistent::MakeWeak removed for 0.11.8+
+
+### 0.4.3 Nov 2 2013
+
+ - Include node_object_wrap.h, removed from node.h for Node 0.11.8.
+
+### 0.4.2 Nov 2 2013
+
+ - Handle deprecation of v8::Persistent::Dispose(v8::Isolate* isolate)) for
+ Node 0.11.8 release.
+
+### 0.4.1 Sep 16 2013
+
+ - Added explicit `#include <uv.h>` as it was removed from node.h for v0.11.8
+
+### 0.4.0 Sep 2 2013
+
+ - Added NAN_INLINE and NAN_DEPRECATED and made use of them
+ - Added NanError, NanTypeError and NanRangeError
+ - Cleaned up code
+
+### 0.3.2 Aug 30 2013
+
+ - Fix missing scope declaration in GetFromPersistent() and SaveToPersistent
+ in NanAsyncWorker
+
+### 0.3.1 Aug 20 2013
+
+ - fix "not all control paths return a value" compile warning on some platforms
+
+### 0.3.0 Aug 19 2013
+
+ - Made NAN work with NPM
+ - Lots of fixes to NanFromV8String, pulling in features from new Node core
+ - Changed node::encoding to Nan::Encoding in NanFromV8String to unify the API
+ - Added optional error number argument for NanThrowError()
+ - Added NanInitPersistent()
+ - Added NanReturnNull() and NanReturnEmptyString()
+ - Added NanLocker and NanUnlocker
+ - Added missing scopes
+ - Made sure to clear disposed Persistent handles
+ - Changed NanAsyncWorker to allocate error messages on the heap
+ - Changed NanThrowError(Local<Value>) to NanThrowError(Handle<Value>)
+ - Fixed leak in NanAsyncWorker when errmsg is used
+
+### 0.2.2 Aug 5 2013
+
+ - Fixed usage of undefined variable with node::BASE64 in NanFromV8String()
+
+### 0.2.1 Aug 5 2013
+
+ - Fixed 0.8 breakage, node::BUFFER encoding type not available in 0.8 for
+ NanFromV8String()
+
+### 0.2.0 Aug 5 2013
+
+ - Added NAN_PROPERTY_GETTER, NAN_PROPERTY_SETTER, NAN_PROPERTY_ENUMERATOR,
+ NAN_PROPERTY_DELETER, NAN_PROPERTY_QUERY
+ - Extracted _NAN_METHOD_ARGS, _NAN_GETTER_ARGS, _NAN_SETTER_ARGS,
+ _NAN_PROPERTY_GETTER_ARGS, _NAN_PROPERTY_SETTER_ARGS,
+ _NAN_PROPERTY_ENUMERATOR_ARGS, _NAN_PROPERTY_DELETER_ARGS,
+ _NAN_PROPERTY_QUERY_ARGS
+ - Added NanGetInternalFieldPointer, NanSetInternalFieldPointer
+ - Added NAN_WEAK_CALLBACK, NAN_WEAK_CALLBACK_OBJECT,
+ NAN_WEAK_CALLBACK_DATA, NanMakeWeak
+ - Renamed THROW_ERROR to _NAN_THROW_ERROR
+ - Added NanNewBufferHandle(char*, size_t, node::smalloc::FreeCallback, void*)
+ - Added NanBufferUse(char*, uint32_t)
+ - Added NanNewContextHandle(v8::ExtensionConfiguration*,
+ v8::Handle<v8::ObjectTemplate>, v8::Handle<v8::Value>)
+ - Fixed broken NanCallback#GetFunction()
+ - Added optional encoding and size arguments to NanFromV8String()
+ - Added NanGetPointerSafe() and NanSetPointerSafe()
+ - Added initial test suite (to be expanded)
+ - Allow NanUInt32OptionValue to convert any Number object
+
+### 0.1.0 Jul 21 2013
+
+ - Added `NAN_GETTER`, `NAN_SETTER`
+ - Added `NanThrowError` with single Local<Value> argument
+ - Added `NanNewBufferHandle` with single uint32_t argument
+ - Added `NanHasInstance(Persistent<FunctionTemplate>&, Handle<Value>)`
+ - Added `Local<Function> NanCallback#GetFunction()`
+ - Added `NanCallback#Call(int, Local<Value>[])`
+ - Deprecated `NanCallback#Run(int, Local<Value>[])` in favour of Call
--- /dev/null
+The MIT License (MIT)
+=====================
+
+Copyright (c) 2018 NAN contributors
+-----------------------------------
+
+*NAN contributors listed at <https://github.com/nodejs/nan#contributors>*
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+Native Abstractions for Node.js
+===============================
+
+**A header file filled with macro and utility goodness for making add-on development for Node.js easier across versions 0.8, 0.10, 0.12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 and 12.**
+
+***Current version: 2.14.0***
+
+*(See [CHANGELOG.md](https://github.com/nodejs/nan/blob/master/CHANGELOG.md) for complete ChangeLog)*
+
+[![NPM](https://nodei.co/npm/nan.png?downloads=true&downloadRank=true)](https://nodei.co/npm/nan/) [![NPM](https://nodei.co/npm-dl/nan.png?months=6&height=3)](https://nodei.co/npm/nan/)
+
+[![Build Status](https://api.travis-ci.org/nodejs/nan.svg?branch=master)](https://travis-ci.org/nodejs/nan)
+[![Build status](https://ci.appveyor.com/api/projects/status/kh73pbm9dsju7fgh)](https://ci.appveyor.com/project/RodVagg/nan)
+
+Thanks to the crazy changes in V8 (and some in Node core), keeping native addons compiling happily across versions, particularly 0.10 to 0.12 to 4.0, is a minor nightmare. The goal of this project is to store all logic necessary to develop native Node.js addons without having to inspect `NODE_MODULE_VERSION` and get yourself into a macro-tangle.
+
+This project also contains some helper utilities that make addon development a bit more pleasant.
+
+ * **[News & Updates](#news)**
+ * **[Usage](#usage)**
+ * **[Example](#example)**
+ * **[API](#api)**
+ * **[Tests](#tests)**
+ * **[Known issues](#issues)**
+ * **[Governance & Contributing](#governance)**
+
+<a name="news"></a>
+
+## News & Updates
+
+<a name="usage"></a>
+
+## Usage
+
+Simply add **NAN** as a dependency in the *package.json* of your Node addon:
+
+``` bash
+$ npm install --save nan
+```
+
+Pull in the path to **NAN** in your *binding.gyp* so that you can use `#include <nan.h>` in your *.cpp* files:
+
+``` python
+"include_dirs" : [
+ "<!(node -e \"require('nan')\")"
+]
+```
+
+This works like a `-I<path-to-NAN>` when compiling your addon.
+
+<a name="example"></a>
+
+## Example
+
+Just getting started with Nan? Take a look at the **[Node Add-on Examples](https://github.com/nodejs/node-addon-examples)**.
+
+Refer to a [quick-start **Nan** Boilerplate](https://github.com/fcanas/node-native-boilerplate) for a ready-to-go project that utilizes basic Nan functionality.
+
+For a simpler example, see the **[async pi estimation example](https://github.com/nodejs/nan/tree/master/examples/async_pi_estimate)** in the examples directory for full code and an explanation of what this Monte Carlo Pi estimation example does. Below are just some parts of the full example that illustrate the use of **NAN**.
+
+Yet another example is **[nan-example-eol](https://github.com/CodeCharmLtd/nan-example-eol)**. It shows newline detection implemented as a native addon.
+
+Also take a look at our comprehensive **[C++ test suite](https://github.com/nodejs/nan/tree/master/test/cpp)** which has a plethora of code snippets for your pasting pleasure.
+
+<a name="api"></a>
+
+## API
+
+Additional to the NAN documentation below, please consult:
+
+* [The V8 Getting Started * Guide](https://github.com/v8/v8/wiki/Getting%20Started%20with%20Embedding)
+* [The V8 Embedders * Guide](https://github.com/v8/v8/wiki/Embedder%27s%20Guide)
+* [V8 API Documentation](https://v8docs.nodesource.com/)
+* [Node Add-on Documentation](https://nodejs.org/api/addons.html)
+
+<!-- START API -->
+
+### JavaScript-accessible methods
+
+A _template_ is a blueprint for JavaScript functions and objects in a context. You can use a template to wrap C++ functions and data structures within JavaScript objects so that they can be manipulated from JavaScript. See the V8 Embedders Guide section on [Templates](https://github.com/v8/v8/wiki/Embedder%27s-Guide#templates) for further information.
+
+In order to expose functionality to JavaScript via a template, you must provide it to V8 in a form that it understands. Across the versions of V8 supported by NAN, JavaScript-accessible method signatures vary widely, NAN fully abstracts method declaration and provides you with an interface that is similar to the most recent V8 API but is backward-compatible with older versions that still use the now-deceased `v8::Argument` type.
+
+* **Method argument types**
+ - <a href="doc/methods.md#api_nan_function_callback_info"><b><code>Nan::FunctionCallbackInfo</code></b></a>
+ - <a href="doc/methods.md#api_nan_property_callback_info"><b><code>Nan::PropertyCallbackInfo</code></b></a>
+ - <a href="doc/methods.md#api_nan_return_value"><b><code>Nan::ReturnValue</code></b></a>
+* **Method declarations**
+ - <a href="doc/methods.md#api_nan_method"><b>Method declaration</b></a>
+ - <a href="doc/methods.md#api_nan_getter"><b>Getter declaration</b></a>
+ - <a href="doc/methods.md#api_nan_setter"><b>Setter declaration</b></a>
+ - <a href="doc/methods.md#api_nan_property_getter"><b>Property getter declaration</b></a>
+ - <a href="doc/methods.md#api_nan_property_setter"><b>Property setter declaration</b></a>
+ - <a href="doc/methods.md#api_nan_property_enumerator"><b>Property enumerator declaration</b></a>
+ - <a href="doc/methods.md#api_nan_property_deleter"><b>Property deleter declaration</b></a>
+ - <a href="doc/methods.md#api_nan_property_query"><b>Property query declaration</b></a>
+ - <a href="doc/methods.md#api_nan_index_getter"><b>Index getter declaration</b></a>
+ - <a href="doc/methods.md#api_nan_index_setter"><b>Index setter declaration</b></a>
+ - <a href="doc/methods.md#api_nan_index_enumerator"><b>Index enumerator declaration</b></a>
+ - <a href="doc/methods.md#api_nan_index_deleter"><b>Index deleter declaration</b></a>
+ - <a href="doc/methods.md#api_nan_index_query"><b>Index query declaration</b></a>
+* Method and template helpers
+ - <a href="doc/methods.md#api_nan_set_method"><b><code>Nan::SetMethod()</code></b></a>
+ - <a href="doc/methods.md#api_nan_set_prototype_method"><b><code>Nan::SetPrototypeMethod()</code></b></a>
+ - <a href="doc/methods.md#api_nan_set_accessor"><b><code>Nan::SetAccessor()</code></b></a>
+ - <a href="doc/methods.md#api_nan_set_named_property_handler"><b><code>Nan::SetNamedPropertyHandler()</code></b></a>
+ - <a href="doc/methods.md#api_nan_set_indexed_property_handler"><b><code>Nan::SetIndexedPropertyHandler()</code></b></a>
+ - <a href="doc/methods.md#api_nan_set_template"><b><code>Nan::SetTemplate()</code></b></a>
+ - <a href="doc/methods.md#api_nan_set_prototype_template"><b><code>Nan::SetPrototypeTemplate()</code></b></a>
+ - <a href="doc/methods.md#api_nan_set_instance_template"><b><code>Nan::SetInstanceTemplate()</code></b></a>
+ - <a href="doc/methods.md#api_nan_set_call_handler"><b><code>Nan::SetCallHandler()</code></b></a>
+ - <a href="doc/methods.md#api_nan_set_call_as_function_handler"><b><code>Nan::SetCallAsFunctionHandler()</code></b></a>
+
+### Scopes
+
+A _local handle_ is a pointer to an object. All V8 objects are accessed using handles, they are necessary because of the way the V8 garbage collector works.
+
+A handle scope can be thought of as a container for any number of handles. When you've finished with your handles, instead of deleting each one individually you can simply delete their scope.
+
+The creation of `HandleScope` objects is different across the supported versions of V8. Therefore, NAN provides its own implementations that can be used safely across these.
+
+ - <a href="doc/scopes.md#api_nan_handle_scope"><b><code>Nan::HandleScope</code></b></a>
+ - <a href="doc/scopes.md#api_nan_escapable_handle_scope"><b><code>Nan::EscapableHandleScope</code></b></a>
+
+Also see the V8 Embedders Guide section on [Handles and Garbage Collection](https://github.com/v8/v8/wiki/Embedder%27s%20Guide#handles-and-garbage-collection).
+
+### Persistent references
+
+An object reference that is independent of any `HandleScope` is a _persistent_ reference. Where a `Local` handle only lives as long as the `HandleScope` in which it was allocated, a `Persistent` handle remains valid until it is explicitly disposed.
+
+Due to the evolution of the V8 API, it is necessary for NAN to provide a wrapper implementation of the `Persistent` classes to supply compatibility across the V8 versions supported.
+
+ - <a href="doc/persistent.md#api_nan_persistent_base"><b><code>Nan::PersistentBase & v8::PersistentBase</code></b></a>
+ - <a href="doc/persistent.md#api_nan_non_copyable_persistent_traits"><b><code>Nan::NonCopyablePersistentTraits & v8::NonCopyablePersistentTraits</code></b></a>
+ - <a href="doc/persistent.md#api_nan_copyable_persistent_traits"><b><code>Nan::CopyablePersistentTraits & v8::CopyablePersistentTraits</code></b></a>
+ - <a href="doc/persistent.md#api_nan_persistent"><b><code>Nan::Persistent</code></b></a>
+ - <a href="doc/persistent.md#api_nan_global"><b><code>Nan::Global</code></b></a>
+ - <a href="doc/persistent.md#api_nan_weak_callback_info"><b><code>Nan::WeakCallbackInfo</code></b></a>
+ - <a href="doc/persistent.md#api_nan_weak_callback_type"><b><code>Nan::WeakCallbackType</code></b></a>
+
+Also see the V8 Embedders Guide section on [Handles and Garbage Collection](https://developers.google.com/v8/embed#handles).
+
+### New
+
+NAN provides a `Nan::New()` helper for the creation of new JavaScript objects in a way that's compatible across the supported versions of V8.
+
+ - <a href="doc/new.md#api_nan_new"><b><code>Nan::New()</code></b></a>
+ - <a href="doc/new.md#api_nan_undefined"><b><code>Nan::Undefined()</code></b></a>
+ - <a href="doc/new.md#api_nan_null"><b><code>Nan::Null()</code></b></a>
+ - <a href="doc/new.md#api_nan_true"><b><code>Nan::True()</code></b></a>
+ - <a href="doc/new.md#api_nan_false"><b><code>Nan::False()</code></b></a>
+ - <a href="doc/new.md#api_nan_empty_string"><b><code>Nan::EmptyString()</code></b></a>
+
+
+### Converters
+
+NAN contains functions that convert `v8::Value`s to other `v8::Value` types and native types. Since type conversion is not guaranteed to succeed, they return `Nan::Maybe` types. These converters can be used in place of `value->ToX()` and `value->XValue()` (where `X` is one of the types, e.g. `Boolean`) in a way that provides a consistent interface across V8 versions. Newer versions of V8 use the new `v8::Maybe` and `v8::MaybeLocal` types for these conversions, older versions don't have this functionality so it is provided by NAN.
+
+ - <a href="doc/converters.md#api_nan_to"><b><code>Nan::To()</code></b></a>
+
+### Maybe Types
+
+The `Nan::MaybeLocal` and `Nan::Maybe` types are monads that encapsulate `v8::Local` handles that _may be empty_.
+
+* **Maybe Types**
+ - <a href="doc/maybe_types.md#api_nan_maybe_local"><b><code>Nan::MaybeLocal</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_maybe"><b><code>Nan::Maybe</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_nothing"><b><code>Nan::Nothing</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_just"><b><code>Nan::Just</code></b></a>
+* **Maybe Helpers**
+ - <a href="doc/maybe_types.md#api_nan_call"><b><code>Nan::Call()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_to_detail_string"><b><code>Nan::ToDetailString()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_to_array_index"><b><code>Nan::ToArrayIndex()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_equals"><b><code>Nan::Equals()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_new_instance"><b><code>Nan::NewInstance()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_get_function"><b><code>Nan::GetFunction()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_set"><b><code>Nan::Set()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_define_own_property"><b><code>Nan::DefineOwnProperty()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_force_set"><del><b><code>Nan::ForceSet()</code></b></del></a>
+ - <a href="doc/maybe_types.md#api_nan_get"><b><code>Nan::Get()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_get_property_attribute"><b><code>Nan::GetPropertyAttributes()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_has"><b><code>Nan::Has()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_delete"><b><code>Nan::Delete()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_get_property_names"><b><code>Nan::GetPropertyNames()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_get_own_property_names"><b><code>Nan::GetOwnPropertyNames()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_set_prototype"><b><code>Nan::SetPrototype()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_object_proto_to_string"><b><code>Nan::ObjectProtoToString()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_has_own_property"><b><code>Nan::HasOwnProperty()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_has_real_named_property"><b><code>Nan::HasRealNamedProperty()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_has_real_indexed_property"><b><code>Nan::HasRealIndexedProperty()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_has_real_named_callback_property"><b><code>Nan::HasRealNamedCallbackProperty()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_get_real_named_property_in_prototype_chain"><b><code>Nan::GetRealNamedPropertyInPrototypeChain()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_get_real_named_property"><b><code>Nan::GetRealNamedProperty()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_call_as_function"><b><code>Nan::CallAsFunction()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_call_as_constructor"><b><code>Nan::CallAsConstructor()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_get_source_line"><b><code>Nan::GetSourceLine()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_get_line_number"><b><code>Nan::GetLineNumber()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_get_start_column"><b><code>Nan::GetStartColumn()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_get_end_column"><b><code>Nan::GetEndColumn()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_clone_element_at"><b><code>Nan::CloneElementAt()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_has_private"><b><code>Nan::HasPrivate()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_get_private"><b><code>Nan::GetPrivate()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_set_private"><b><code>Nan::SetPrivate()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_delete_private"><b><code>Nan::DeletePrivate()</code></b></a>
+ - <a href="doc/maybe_types.md#api_nan_make_maybe"><b><code>Nan::MakeMaybe()</code></b></a>
+
+### Script
+
+NAN provides a `v8::Script` helpers as the API has changed over the supported versions of V8.
+
+ - <a href="doc/script.md#api_nan_compile_script"><b><code>Nan::CompileScript()</code></b></a>
+ - <a href="doc/script.md#api_nan_run_script"><b><code>Nan::RunScript()</code></b></a>
+
+
+### JSON
+
+The _JSON_ object provides the c++ versions of the methods offered by the `JSON` object in javascript. V8 exposes these methods via the `v8::JSON` object.
+
+ - <a href="doc/json.md#api_nan_json_parse"><b><code>Nan::JSON.Parse</code></b></a>
+ - <a href="doc/json.md#api_nan_json_stringify"><b><code>Nan::JSON.Stringify</code></b></a>
+
+Refer to the V8 JSON object in the [V8 documentation](https://v8docs.nodesource.com/node-8.11/da/d6f/classv8_1_1_j_s_o_n.html) for more information about these methods and their arguments.
+
+### Errors
+
+NAN includes helpers for creating, throwing and catching Errors as much of this functionality varies across the supported versions of V8 and must be abstracted.
+
+Note that an Error object is simply a specialized form of `v8::Value`.
+
+Also consult the V8 Embedders Guide section on [Exceptions](https://developers.google.com/v8/embed#exceptions) for more information.
+
+ - <a href="doc/errors.md#api_nan_error"><b><code>Nan::Error()</code></b></a>
+ - <a href="doc/errors.md#api_nan_range_error"><b><code>Nan::RangeError()</code></b></a>
+ - <a href="doc/errors.md#api_nan_reference_error"><b><code>Nan::ReferenceError()</code></b></a>
+ - <a href="doc/errors.md#api_nan_syntax_error"><b><code>Nan::SyntaxError()</code></b></a>
+ - <a href="doc/errors.md#api_nan_type_error"><b><code>Nan::TypeError()</code></b></a>
+ - <a href="doc/errors.md#api_nan_throw_error"><b><code>Nan::ThrowError()</code></b></a>
+ - <a href="doc/errors.md#api_nan_throw_range_error"><b><code>Nan::ThrowRangeError()</code></b></a>
+ - <a href="doc/errors.md#api_nan_throw_reference_error"><b><code>Nan::ThrowReferenceError()</code></b></a>
+ - <a href="doc/errors.md#api_nan_throw_syntax_error"><b><code>Nan::ThrowSyntaxError()</code></b></a>
+ - <a href="doc/errors.md#api_nan_throw_type_error"><b><code>Nan::ThrowTypeError()</code></b></a>
+ - <a href="doc/errors.md#api_nan_fatal_exception"><b><code>Nan::FatalException()</code></b></a>
+ - <a href="doc/errors.md#api_nan_errno_exception"><b><code>Nan::ErrnoException()</code></b></a>
+ - <a href="doc/errors.md#api_nan_try_catch"><b><code>Nan::TryCatch</code></b></a>
+
+
+### Buffers
+
+NAN's `node::Buffer` helpers exist as the API has changed across supported Node versions. Use these methods to ensure compatibility.
+
+ - <a href="doc/buffers.md#api_nan_new_buffer"><b><code>Nan::NewBuffer()</code></b></a>
+ - <a href="doc/buffers.md#api_nan_copy_buffer"><b><code>Nan::CopyBuffer()</code></b></a>
+ - <a href="doc/buffers.md#api_nan_free_callback"><b><code>Nan::FreeCallback()</code></b></a>
+
+### Nan::Callback
+
+`Nan::Callback` makes it easier to use `v8::Function` handles as callbacks. A class that wraps a `v8::Function` handle, protecting it from garbage collection and making it particularly useful for storage and use across asynchronous execution.
+
+ - <a href="doc/callback.md#api_nan_callback"><b><code>Nan::Callback</code></b></a>
+
+### Asynchronous work helpers
+
+`Nan::AsyncWorker`, `Nan::AsyncProgressWorker` and `Nan::AsyncProgressQueueWorker` are helper classes that make working with asynchronous code easier.
+
+ - <a href="doc/asyncworker.md#api_nan_async_worker"><b><code>Nan::AsyncWorker</code></b></a>
+ - <a href="doc/asyncworker.md#api_nan_async_progress_worker"><b><code>Nan::AsyncProgressWorkerBase & Nan::AsyncProgressWorker</code></b></a>
+ - <a href="doc/asyncworker.md#api_nan_async_progress_queue_worker"><b><code>Nan::AsyncProgressQueueWorker</code></b></a>
+ - <a href="doc/asyncworker.md#api_nan_async_queue_worker"><b><code>Nan::AsyncQueueWorker</code></b></a>
+
+### Strings & Bytes
+
+Miscellaneous string & byte encoding and decoding functionality provided for compatibility across supported versions of V8 and Node. Implemented by NAN to ensure that all encoding types are supported, even for older versions of Node where they are missing.
+
+ - <a href="doc/string_bytes.md#api_nan_encoding"><b><code>Nan::Encoding</code></b></a>
+ - <a href="doc/string_bytes.md#api_nan_encode"><b><code>Nan::Encode()</code></b></a>
+ - <a href="doc/string_bytes.md#api_nan_decode_bytes"><b><code>Nan::DecodeBytes()</code></b></a>
+ - <a href="doc/string_bytes.md#api_nan_decode_write"><b><code>Nan::DecodeWrite()</code></b></a>
+
+
+### Object Wrappers
+
+The `ObjectWrap` class can be used to make wrapped C++ objects and a factory of wrapped objects.
+
+ - <a href="doc/object_wrappers.md#api_nan_object_wrap"><b><code>Nan::ObjectWrap</code></b></a>
+
+
+### V8 internals
+
+The hooks to access V8 internals—including GC and statistics—are different across the supported versions of V8, therefore NAN provides its own hooks that call the appropriate V8 methods.
+
+ - <a href="doc/v8_internals.md#api_nan_gc_callback"><b><code>NAN_GC_CALLBACK()</code></b></a>
+ - <a href="doc/v8_internals.md#api_nan_add_gc_epilogue_callback"><b><code>Nan::AddGCEpilogueCallback()</code></b></a>
+ - <a href="doc/v8_internals.md#api_nan_remove_gc_epilogue_callback"><b><code>Nan::RemoveGCEpilogueCallback()</code></b></a>
+ - <a href="doc/v8_internals.md#api_nan_add_gc_prologue_callback"><b><code>Nan::AddGCPrologueCallback()</code></b></a>
+ - <a href="doc/v8_internals.md#api_nan_remove_gc_prologue_callback"><b><code>Nan::RemoveGCPrologueCallback()</code></b></a>
+ - <a href="doc/v8_internals.md#api_nan_get_heap_statistics"><b><code>Nan::GetHeapStatistics()</code></b></a>
+ - <a href="doc/v8_internals.md#api_nan_set_counter_function"><b><code>Nan::SetCounterFunction()</code></b></a>
+ - <a href="doc/v8_internals.md#api_nan_set_create_histogram_function"><b><code>Nan::SetCreateHistogramFunction()</code></b></a>
+ - <a href="doc/v8_internals.md#api_nan_set_add_histogram_sample_function"><b><code>Nan::SetAddHistogramSampleFunction()</code></b></a>
+ - <a href="doc/v8_internals.md#api_nan_idle_notification"><b><code>Nan::IdleNotification()</code></b></a>
+ - <a href="doc/v8_internals.md#api_nan_low_memory_notification"><b><code>Nan::LowMemoryNotification()</code></b></a>
+ - <a href="doc/v8_internals.md#api_nan_context_disposed_notification"><b><code>Nan::ContextDisposedNotification()</code></b></a>
+ - <a href="doc/v8_internals.md#api_nan_get_internal_field_pointer"><b><code>Nan::GetInternalFieldPointer()</code></b></a>
+ - <a href="doc/v8_internals.md#api_nan_set_internal_field_pointer"><b><code>Nan::SetInternalFieldPointer()</code></b></a>
+ - <a href="doc/v8_internals.md#api_nan_adjust_external_memory"><b><code>Nan::AdjustExternalMemory()</code></b></a>
+
+
+### Miscellaneous V8 Helpers
+
+ - <a href="doc/v8_misc.md#api_nan_utf8_string"><b><code>Nan::Utf8String</code></b></a>
+ - <a href="doc/v8_misc.md#api_nan_get_current_context"><b><code>Nan::GetCurrentContext()</code></b></a>
+ - <a href="doc/v8_misc.md#api_nan_set_isolate_data"><b><code>Nan::SetIsolateData()</code></b></a>
+ - <a href="doc/v8_misc.md#api_nan_get_isolate_data"><b><code>Nan::GetIsolateData()</code></b></a>
+ - <a href="doc/v8_misc.md#api_nan_typedarray_contents"><b><code>Nan::TypedArrayContents</code></b></a>
+
+
+### Miscellaneous Node Helpers
+
+ - <a href="doc/node_misc.md#api_nan_asyncresource"><b><code>Nan::AsyncResource</code></b></a>
+ - <a href="doc/node_misc.md#api_nan_make_callback"><b><code>Nan::MakeCallback()</code></b></a>
+ - <a href="doc/node_misc.md#api_nan_module_init"><b><code>NAN_MODULE_INIT()</code></b></a>
+ - <a href="doc/node_misc.md#api_nan_export"><b><code>Nan::Export()</code></b></a>
+
+<!-- END API -->
+
+
+<a name="tests"></a>
+
+### Tests
+
+To run the NAN tests do:
+
+``` sh
+npm install
+npm run-script rebuild-tests
+npm test
+```
+
+Or just:
+
+``` sh
+npm install
+make test
+```
+
+<a name="issues"></a>
+
+## Known issues
+
+### Compiling against Node.js 0.12 on OSX
+
+With new enough compilers available on OSX, the versions of V8 headers corresponding to Node.js 0.12
+do not compile anymore. The error looks something like:
+
+```
+❯ CXX(target) Release/obj.target/accessors/cpp/accessors.o
+In file included from ../cpp/accessors.cpp:9:
+In file included from ../../nan.h:51:
+In file included from /Users/ofrobots/.node-gyp/0.12.18/include/node/node.h:61:
+/Users/ofrobots/.node-gyp/0.12.18/include/node/v8.h:5800:54: error: 'CreateHandle' is a protected member of 'v8::HandleScope'
+ return Handle<T>(reinterpret_cast<T*>(HandleScope::CreateHandle(
+ ~~~~~~~~~~~~~^~~~~~~~~~~~
+```
+
+This can be worked around by patching your local versions of v8.h corresponding to Node 0.12 to make
+`v8::Handle` a friend of `v8::HandleScope`. Since neither Node.js not V8 support this release line anymore
+this patch cannot be released by either project in an official release.
+
+For this reason, we do not test against Node.js 0.12 on OSX in this project's CI. If you need to support
+that configuration, you will need to either get an older compiler, or apply a source patch to the version
+of V8 headers as a workaround.
+
+<a name="governance"></a>
+
+## Governance & Contributing
+
+NAN is governed by the [Node.js Addon API Working Group](https://github.com/nodejs/CTC/blob/master/WORKING_GROUPS.md#addon-api)
+
+### Addon API Working Group (WG)
+
+The NAN project is jointly governed by a Working Group which is responsible for high-level guidance of the project.
+
+Members of the WG are also known as Collaborators, there is no distinction between the two, unlike other Node.js projects.
+
+The WG has final authority over this project including:
+
+* Technical direction
+* Project governance and process (including this policy)
+* Contribution policy
+* GitHub repository hosting
+* Maintaining the list of additional Collaborators
+
+For the current list of WG members, see the project [README.md](./README.md#collaborators).
+
+Individuals making significant and valuable contributions are made members of the WG and given commit-access to the project. These individuals are identified by the WG and their addition to the WG is discussed via GitHub and requires unanimous consensus amongst those WG members participating in the discussion with a quorum of 50% of WG members required for acceptance of the vote.
+
+_Note:_ If you make a significant contribution and are not considered for commit-access log an issue or contact a WG member directly.
+
+For the current list of WG members / Collaborators, see the project [README.md](./README.md#collaborators).
+
+### Consensus Seeking Process
+
+The WG follows a [Consensus Seeking](https://en.wikipedia.org/wiki/Consensus-seeking_decision-making) decision making model.
+
+Modifications of the contents of the NAN repository are made on a collaborative basis. Anybody with a GitHub account may propose a modification via pull request and it will be considered by the WG. All pull requests must be reviewed and accepted by a WG member with sufficient expertise who is able to take full responsibility for the change. In the case of pull requests proposed by an existing WG member, an additional WG member is required for sign-off. Consensus should be sought if additional WG members participate and there is disagreement around a particular modification.
+
+If a change proposal cannot reach a consensus, a WG member can call for a vote amongst the members of the WG. Simple majority wins.
+
+<a id="developers-certificate-of-origin"></a>
+
+## Developer's Certificate of Origin 1.1
+
+By making a contribution to this project, I certify that:
+
+* (a) The contribution was created in whole or in part by me and I
+ have the right to submit it under the open source license
+ indicated in the file; or
+
+* (b) The contribution is based upon previous work that, to the best
+ of my knowledge, is covered under an appropriate open source
+ license and I have the right under that license to submit that
+ work with modifications, whether created in whole or in part
+ by me, under the same open source license (unless I am
+ permitted to submit under a different license), as indicated
+ in the file; or
+
+* (c) The contribution was provided directly to me by some other
+ person who certified (a), (b) or (c) and I have not modified
+ it.
+
+* (d) I understand and agree that this project and the contribution
+ are public and that a record of the contribution (including all
+ personal information I submit with it, including my sign-off) is
+ maintained indefinitely and may be redistributed consistent with
+ this project or the open source license(s) involved.
+
+<a name="collaborators"></a>
+
+### WG Members / Collaborators
+
+<table><tbody>
+<tr><th align="left">Rod Vagg</th><td><a href="https://github.com/rvagg">GitHub/rvagg</a></td><td><a href="http://twitter.com/rvagg">Twitter/@rvagg</a></td></tr>
+<tr><th align="left">Benjamin Byholm</th><td><a href="https://github.com/kkoopa/">GitHub/kkoopa</a></td><td>-</td></tr>
+<tr><th align="left">Trevor Norris</th><td><a href="https://github.com/trevnorris">GitHub/trevnorris</a></td><td><a href="http://twitter.com/trevnorris">Twitter/@trevnorris</a></td></tr>
+<tr><th align="left">Nathan Rajlich</th><td><a href="https://github.com/TooTallNate">GitHub/TooTallNate</a></td><td><a href="http://twitter.com/TooTallNate">Twitter/@TooTallNate</a></td></tr>
+<tr><th align="left">Brett Lawson</th><td><a href="https://github.com/brett19">GitHub/brett19</a></td><td><a href="http://twitter.com/brett19x">Twitter/@brett19x</a></td></tr>
+<tr><th align="left">Ben Noordhuis</th><td><a href="https://github.com/bnoordhuis">GitHub/bnoordhuis</a></td><td><a href="http://twitter.com/bnoordhuis">Twitter/@bnoordhuis</a></td></tr>
+<tr><th align="left">David Siegel</th><td><a href="https://github.com/agnat">GitHub/agnat</a></td><td><a href="http://twitter.com/agnat">Twitter/@agnat</a></td></tr>
+<tr><th align="left">Michael Ira Krufky</th><td><a href="https://github.com/mkrufky">GitHub/mkrufky</a></td><td><a href="http://twitter.com/mkrufky">Twitter/@mkrufky</a></td></tr>
+</tbody></table>
+
+## Licence & copyright
+
+Copyright (c) 2018 NAN WG Members / Collaborators (listed above).
+
+Native Abstractions for Node.js is licensed under an MIT license. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details.
--- /dev/null
+## Asynchronous work helpers
+
+`Nan::AsyncWorker`, `Nan::AsyncProgressWorker` and `Nan::AsyncProgressQueueWorker` are helper classes that make working with asynchronous code easier.
+
+ - <a href="#api_nan_async_worker"><b><code>Nan::AsyncWorker</code></b></a>
+ - <a href="#api_nan_async_progress_worker"><b><code>Nan::AsyncProgressWorkerBase & Nan::AsyncProgressWorker</code></b></a>
+ - <a href="#api_nan_async_progress_queue_worker"><b><code>Nan::AsyncProgressQueueWorker</code></b></a>
+ - <a href="#api_nan_async_queue_worker"><b><code>Nan::AsyncQueueWorker</code></b></a>
+
+<a name="api_nan_async_worker"></a>
+### Nan::AsyncWorker
+
+`Nan::AsyncWorker` is an _abstract_ class that you can subclass to have much of the annoying asynchronous queuing and handling taken care of for you. It can even store arbitrary V8 objects for you and have them persist while the asynchronous work is in progress.
+
+This class internally handles the details of creating an [`AsyncResource`][AsyncResource], and running the callback in the
+correct async context. To be able to identify the async resources created by this class in async-hooks, provide a
+`resource_name` to the constructor. It is recommended that the module name be used as a prefix to the `resource_name` to avoid
+collisions in the names. For more details see [`AsyncResource`][AsyncResource] documentation. The `resource_name` needs to stay valid for the lifetime of the worker instance.
+
+Definition:
+
+```c++
+class AsyncWorker {
+ public:
+ explicit AsyncWorker(Callback *callback_, const char* resource_name = "nan:AsyncWorker");
+
+ virtual ~AsyncWorker();
+
+ virtual void WorkComplete();
+
+ void SaveToPersistent(const char *key, const v8::Local<v8::Value> &value);
+
+ void SaveToPersistent(const v8::Local<v8::String> &key,
+ const v8::Local<v8::Value> &value);
+
+ void SaveToPersistent(uint32_t index,
+ const v8::Local<v8::Value> &value);
+
+ v8::Local<v8::Value> GetFromPersistent(const char *key) const;
+
+ v8::Local<v8::Value> GetFromPersistent(const v8::Local<v8::String> &key) const;
+
+ v8::Local<v8::Value> GetFromPersistent(uint32_t index) const;
+
+ virtual void Execute() = 0;
+
+ uv_work_t request;
+
+ virtual void Destroy();
+
+ protected:
+ Persistent<v8::Object> persistentHandle;
+
+ Callback *callback;
+
+ virtual void HandleOKCallback();
+
+ virtual void HandleErrorCallback();
+
+ void SetErrorMessage(const char *msg);
+
+ const char* ErrorMessage();
+};
+```
+
+<a name="api_nan_async_progress_worker"></a>
+### Nan::AsyncProgressWorkerBase & Nan::AsyncProgressWorker
+
+`Nan::AsyncProgressWorkerBase` is an _abstract_ class template that extends `Nan::AsyncWorker` and adds additional progress reporting callbacks that can be used during the asynchronous work execution to provide progress data back to JavaScript.
+
+Previously the definition of `Nan::AsyncProgressWorker` only allowed sending `const char` data. Now extending `Nan::AsyncProgressWorker` will yield an instance of the implicit `Nan::AsyncProgressWorkerBase` template with type `<char>` for compatibility.
+
+`Nan::AsyncProgressWorkerBase` & `Nan::AsyncProgressWorker` is intended for best-effort delivery of nonessential progress messages, e.g. a progress bar. The last event sent before the main thread is woken will be delivered.
+
+Definition:
+
+```c++
+template<class T>
+class AsyncProgressWorkerBase<T> : public AsyncWorker {
+ public:
+ explicit AsyncProgressWorkerBase(Callback *callback_, const char* resource_name = ...);
+
+ virtual ~AsyncProgressWorkerBase();
+
+ void WorkProgress();
+
+ class ExecutionProgress {
+ public:
+ void Signal() const;
+ void Send(const T* data, size_t count) const;
+ };
+
+ virtual void Execute(const ExecutionProgress& progress) = 0;
+
+ virtual void HandleProgressCallback(const T *data, size_t count) = 0;
+
+ virtual void Destroy();
+};
+
+typedef AsyncProgressWorkerBase<T> AsyncProgressWorker;
+```
+
+<a name="api_nan_async_progress_queue_worker"></a>
+### Nan::AsyncProgressQueueWorker
+
+`Nan::AsyncProgressQueueWorker` is an _abstract_ class template that extends `Nan::AsyncWorker` and adds additional progress reporting callbacks that can be used during the asynchronous work execution to provide progress data back to JavaScript.
+
+`Nan::AsyncProgressQueueWorker` behaves exactly the same as `Nan::AsyncProgressWorker`, except all events are queued and delivered to the main thread.
+
+Definition:
+
+```c++
+template<class T>
+class AsyncProgressQueueWorker<T> : public AsyncWorker {
+ public:
+ explicit AsyncProgressQueueWorker(Callback *callback_, const char* resource_name = "nan:AsyncProgressQueueWorker");
+
+ virtual ~AsyncProgressQueueWorker();
+
+ void WorkProgress();
+
+ class ExecutionProgress {
+ public:
+ void Send(const T* data, size_t count) const;
+ };
+
+ virtual void Execute(const ExecutionProgress& progress) = 0;
+
+ virtual void HandleProgressCallback(const T *data, size_t count) = 0;
+
+ virtual void Destroy();
+};
+```
+
+<a name="api_nan_async_queue_worker"></a>
+### Nan::AsyncQueueWorker
+
+`Nan::AsyncQueueWorker` will run a `Nan::AsyncWorker` asynchronously via libuv. Both the `execute` and `after_work` steps are taken care of for you. Most of the logic for this is embedded in `Nan::AsyncWorker`.
+
+Definition:
+
+```c++
+void AsyncQueueWorker(AsyncWorker *);
+```
+
+[AsyncResource]: node_misc.md#api_nan_asyncresource
--- /dev/null
+## Buffers
+
+NAN's `node::Buffer` helpers exist as the API has changed across supported Node versions. Use these methods to ensure compatibility.
+
+ - <a href="#api_nan_new_buffer"><b><code>Nan::NewBuffer()</code></b></a>
+ - <a href="#api_nan_copy_buffer"><b><code>Nan::CopyBuffer()</code></b></a>
+ - <a href="#api_nan_free_callback"><b><code>Nan::FreeCallback()</code></b></a>
+
+<a name="api_nan_new_buffer"></a>
+### Nan::NewBuffer()
+
+Allocate a new `node::Buffer` object with the specified size and optional data. Calls `node::Buffer::New()`.
+
+Note that when creating a `Buffer` using `Nan::NewBuffer()` and an existing `char*`, it is assumed that the ownership of the pointer is being transferred to the new `Buffer` for management.
+When a `node::Buffer` instance is garbage collected and a `FreeCallback` has not been specified, `data` will be disposed of via a call to `free()`.
+You _must not_ free the memory space manually once you have created a `Buffer` in this way.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Object> Nan::NewBuffer(uint32_t size)
+Nan::MaybeLocal<v8::Object> Nan::NewBuffer(char* data, uint32_t size)
+Nan::MaybeLocal<v8::Object> Nan::NewBuffer(char *data,
+ size_t length,
+ Nan::FreeCallback callback,
+ void *hint)
+```
+
+
+<a name="api_nan_copy_buffer"></a>
+### Nan::CopyBuffer()
+
+Similar to [`Nan::NewBuffer()`](#api_nan_new_buffer) except that an implicit memcpy will occur within Node. Calls `node::Buffer::Copy()`.
+
+Management of the `char*` is left to the user, you should manually free the memory space if necessary as the new `Buffer` will have its own copy.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Object> Nan::CopyBuffer(const char *data, uint32_t size)
+```
+
+
+<a name="api_nan_free_callback"></a>
+### Nan::FreeCallback()
+
+A free callback that can be provided to [`Nan::NewBuffer()`](#api_nan_new_buffer).
+The supplied callback will be invoked when the `Buffer` undergoes garbage collection.
+
+Signature:
+
+```c++
+typedef void (*FreeCallback)(char *data, void *hint);
+```
--- /dev/null
+## Nan::Callback
+
+`Nan::Callback` makes it easier to use `v8::Function` handles as callbacks. A class that wraps a `v8::Function` handle, protecting it from garbage collection and making it particularly useful for storage and use across asynchronous execution.
+
+ - <a href="#api_nan_callback"><b><code>Nan::Callback</code></b></a>
+
+<a name="api_nan_callback"></a>
+### Nan::Callback
+
+```c++
+class Callback {
+ public:
+ Callback();
+
+ explicit Callback(const v8::Local<v8::Function> &fn);
+
+ ~Callback();
+
+ bool operator==(const Callback &other) const;
+
+ bool operator!=(const Callback &other) const;
+
+ v8::Local<v8::Function> operator*() const;
+
+ MaybeLocal<v8::Value> operator()(AsyncResource* async_resource,
+ v8::Local<v8::Object> target,
+ int argc = 0,
+ v8::Local<v8::Value> argv[] = 0) const;
+
+ MaybeLocal<v8::Value> operator()(AsyncResource* async_resource,
+ int argc = 0,
+ v8::Local<v8::Value> argv[] = 0) const;
+
+ void SetFunction(const v8::Local<v8::Function> &fn);
+
+ v8::Local<v8::Function> GetFunction() const;
+
+ bool IsEmpty() const;
+
+ void Reset(const v8::Local<v8::Function> &fn);
+
+ void Reset();
+
+ MaybeLocal<v8::Value> Call(v8::Local<v8::Object> target,
+ int argc,
+ v8::Local<v8::Value> argv[],
+ AsyncResource* async_resource) const;
+ MaybeLocal<v8::Value> Call(int argc,
+ v8::Local<v8::Value> argv[],
+ AsyncResource* async_resource) const;
+
+ // Deprecated versions. Use the versions that accept an async_resource instead
+ // as they run the callback in the correct async context as specified by the
+ // resource. If you want to call a synchronous JS function (i.e. on a
+ // non-empty JS stack), you can use Nan::Call instead.
+ v8::Local<v8::Value> operator()(v8::Local<v8::Object> target,
+ int argc = 0,
+ v8::Local<v8::Value> argv[] = 0) const;
+
+ v8::Local<v8::Value> operator()(int argc = 0,
+ v8::Local<v8::Value> argv[] = 0) const;
+ v8::Local<v8::Value> Call(v8::Local<v8::Object> target,
+ int argc,
+ v8::Local<v8::Value> argv[]) const;
+
+ v8::Local<v8::Value> Call(int argc, v8::Local<v8::Value> argv[]) const;
+};
+```
+
+Example usage:
+
+```c++
+v8::Local<v8::Function> function;
+Nan::Callback callback(function);
+callback.Call(0, 0);
+```
--- /dev/null
+## Converters
+
+NAN contains functions that convert `v8::Value`s to other `v8::Value` types and native types. Since type conversion is not guaranteed to succeed, they return `Nan::Maybe` types. These converters can be used in place of `value->ToX()` and `value->XValue()` (where `X` is one of the types, e.g. `Boolean`) in a way that provides a consistent interface across V8 versions. Newer versions of V8 use the new `v8::Maybe` and `v8::MaybeLocal` types for these conversions, older versions don't have this functionality so it is provided by NAN.
+
+ - <a href="#api_nan_to"><b><code>Nan::To()</code></b></a>
+
+<a name="api_nan_to"></a>
+### Nan::To()
+
+Converts a `v8::Local<v8::Value>` to a different subtype of `v8::Value` or to a native data type. Returns a `Nan::MaybeLocal<>` or a `Nan::Maybe<>` accordingly.
+
+See [maybe_types.md](./maybe_types.md) for more information on `Nan::Maybe` types.
+
+Signatures:
+
+```c++
+// V8 types
+Nan::MaybeLocal<v8::Boolean> Nan::To<v8::Boolean>(v8::Local<v8::Value> val);
+Nan::MaybeLocal<v8::Int32> Nan::To<v8::Int32>(v8::Local<v8::Value> val);
+Nan::MaybeLocal<v8::Integer> Nan::To<v8::Integer>(v8::Local<v8::Value> val);
+Nan::MaybeLocal<v8::Object> Nan::To<v8::Object>(v8::Local<v8::Value> val);
+Nan::MaybeLocal<v8::Number> Nan::To<v8::Number>(v8::Local<v8::Value> val);
+Nan::MaybeLocal<v8::String> Nan::To<v8::String>(v8::Local<v8::Value> val);
+Nan::MaybeLocal<v8::Uint32> Nan::To<v8::Uint32>(v8::Local<v8::Value> val);
+
+// Native types
+Nan::Maybe<bool> Nan::To<bool>(v8::Local<v8::Value> val);
+Nan::Maybe<double> Nan::To<double>(v8::Local<v8::Value> val);
+Nan::Maybe<int32_t> Nan::To<int32_t>(v8::Local<v8::Value> val);
+Nan::Maybe<int64_t> Nan::To<int64_t>(v8::Local<v8::Value> val);
+Nan::Maybe<uint32_t> Nan::To<uint32_t>(v8::Local<v8::Value> val);
+```
+
+### Example
+
+```c++
+v8::Local<v8::Value> val;
+Nan::MaybeLocal<v8::String> str = Nan::To<v8::String>(val);
+Nan::Maybe<double> d = Nan::To<double>(val);
+```
+
--- /dev/null
+## Errors
+
+NAN includes helpers for creating, throwing and catching Errors as much of this functionality varies across the supported versions of V8 and must be abstracted.
+
+Note that an Error object is simply a specialized form of `v8::Value`.
+
+Also consult the V8 Embedders Guide section on [Exceptions](https://developers.google.com/v8/embed#exceptions) for more information.
+
+ - <a href="#api_nan_error"><b><code>Nan::Error()</code></b></a>
+ - <a href="#api_nan_range_error"><b><code>Nan::RangeError()</code></b></a>
+ - <a href="#api_nan_reference_error"><b><code>Nan::ReferenceError()</code></b></a>
+ - <a href="#api_nan_syntax_error"><b><code>Nan::SyntaxError()</code></b></a>
+ - <a href="#api_nan_type_error"><b><code>Nan::TypeError()</code></b></a>
+ - <a href="#api_nan_throw_error"><b><code>Nan::ThrowError()</code></b></a>
+ - <a href="#api_nan_throw_range_error"><b><code>Nan::ThrowRangeError()</code></b></a>
+ - <a href="#api_nan_throw_reference_error"><b><code>Nan::ThrowReferenceError()</code></b></a>
+ - <a href="#api_nan_throw_syntax_error"><b><code>Nan::ThrowSyntaxError()</code></b></a>
+ - <a href="#api_nan_throw_type_error"><b><code>Nan::ThrowTypeError()</code></b></a>
+ - <a href="#api_nan_fatal_exception"><b><code>Nan::FatalException()</code></b></a>
+ - <a href="#api_nan_errno_exception"><b><code>Nan::ErrnoException()</code></b></a>
+ - <a href="#api_nan_try_catch"><b><code>Nan::TryCatch</code></b></a>
+
+
+<a name="api_nan_error"></a>
+### Nan::Error()
+
+Create a new Error object using the [v8::Exception](https://v8docs.nodesource.com/node-8.11/da/d6a/classv8_1_1_exception.html) class in a way that is compatible across the supported versions of V8.
+
+Note that an Error object is simply a specialized form of `v8::Value`.
+
+Signature:
+
+```c++
+v8::Local<v8::Value> Nan::Error(const char *msg);
+v8::Local<v8::Value> Nan::Error(v8::Local<v8::String> msg);
+```
+
+
+<a name="api_nan_range_error"></a>
+### Nan::RangeError()
+
+Create a new RangeError object using the [v8::Exception](https://v8docs.nodesource.com/node-8.11/da/d6a/classv8_1_1_exception.html) class in a way that is compatible across the supported versions of V8.
+
+Note that an RangeError object is simply a specialized form of `v8::Value`.
+
+Signature:
+
+```c++
+v8::Local<v8::Value> Nan::RangeError(const char *msg);
+v8::Local<v8::Value> Nan::RangeError(v8::Local<v8::String> msg);
+```
+
+
+<a name="api_nan_reference_error"></a>
+### Nan::ReferenceError()
+
+Create a new ReferenceError object using the [v8::Exception](https://v8docs.nodesource.com/node-8.11/da/d6a/classv8_1_1_exception.html) class in a way that is compatible across the supported versions of V8.
+
+Note that an ReferenceError object is simply a specialized form of `v8::Value`.
+
+Signature:
+
+```c++
+v8::Local<v8::Value> Nan::ReferenceError(const char *msg);
+v8::Local<v8::Value> Nan::ReferenceError(v8::Local<v8::String> msg);
+```
+
+
+<a name="api_nan_syntax_error"></a>
+### Nan::SyntaxError()
+
+Create a new SyntaxError object using the [v8::Exception](https://v8docs.nodesource.com/node-8.11/da/d6a/classv8_1_1_exception.html) class in a way that is compatible across the supported versions of V8.
+
+Note that an SyntaxError object is simply a specialized form of `v8::Value`.
+
+Signature:
+
+```c++
+v8::Local<v8::Value> Nan::SyntaxError(const char *msg);
+v8::Local<v8::Value> Nan::SyntaxError(v8::Local<v8::String> msg);
+```
+
+
+<a name="api_nan_type_error"></a>
+### Nan::TypeError()
+
+Create a new TypeError object using the [v8::Exception](https://v8docs.nodesource.com/node-8.11/da/d6a/classv8_1_1_exception.html) class in a way that is compatible across the supported versions of V8.
+
+Note that an TypeError object is simply a specialized form of `v8::Value`.
+
+Signature:
+
+```c++
+v8::Local<v8::Value> Nan::TypeError(const char *msg);
+v8::Local<v8::Value> Nan::TypeError(v8::Local<v8::String> msg);
+```
+
+
+<a name="api_nan_throw_error"></a>
+### Nan::ThrowError()
+
+Throw an Error object (a specialized `v8::Value` as above) in the current context. If a `msg` is provided, a new Error object will be created.
+
+Signature:
+
+```c++
+void Nan::ThrowError(const char *msg);
+void Nan::ThrowError(v8::Local<v8::String> msg);
+void Nan::ThrowError(v8::Local<v8::Value> error);
+```
+
+
+<a name="api_nan_throw_range_error"></a>
+### Nan::ThrowRangeError()
+
+Throw an RangeError object (a specialized `v8::Value` as above) in the current context. If a `msg` is provided, a new RangeError object will be created.
+
+Signature:
+
+```c++
+void Nan::ThrowRangeError(const char *msg);
+void Nan::ThrowRangeError(v8::Local<v8::String> msg);
+void Nan::ThrowRangeError(v8::Local<v8::Value> error);
+```
+
+
+<a name="api_nan_throw_reference_error"></a>
+### Nan::ThrowReferenceError()
+
+Throw an ReferenceError object (a specialized `v8::Value` as above) in the current context. If a `msg` is provided, a new ReferenceError object will be created.
+
+Signature:
+
+```c++
+void Nan::ThrowReferenceError(const char *msg);
+void Nan::ThrowReferenceError(v8::Local<v8::String> msg);
+void Nan::ThrowReferenceError(v8::Local<v8::Value> error);
+```
+
+
+<a name="api_nan_throw_syntax_error"></a>
+### Nan::ThrowSyntaxError()
+
+Throw an SyntaxError object (a specialized `v8::Value` as above) in the current context. If a `msg` is provided, a new SyntaxError object will be created.
+
+Signature:
+
+```c++
+void Nan::ThrowSyntaxError(const char *msg);
+void Nan::ThrowSyntaxError(v8::Local<v8::String> msg);
+void Nan::ThrowSyntaxError(v8::Local<v8::Value> error);
+```
+
+
+<a name="api_nan_throw_type_error"></a>
+### Nan::ThrowTypeError()
+
+Throw an TypeError object (a specialized `v8::Value` as above) in the current context. If a `msg` is provided, a new TypeError object will be created.
+
+Signature:
+
+```c++
+void Nan::ThrowTypeError(const char *msg);
+void Nan::ThrowTypeError(v8::Local<v8::String> msg);
+void Nan::ThrowTypeError(v8::Local<v8::Value> error);
+```
+
+<a name="api_nan_fatal_exception"></a>
+### Nan::FatalException()
+
+Replaces `node::FatalException()` which has a different API across supported versions of Node. For use with [`Nan::TryCatch`](#api_nan_try_catch).
+
+Signature:
+
+```c++
+void Nan::FatalException(const Nan::TryCatch& try_catch);
+```
+
+<a name="api_nan_errno_exception"></a>
+### Nan::ErrnoException()
+
+Replaces `node::ErrnoException()` which has a different API across supported versions of Node.
+
+Signature:
+
+```c++
+v8::Local<v8::Value> Nan::ErrnoException(int errorno,
+ const char* syscall = NULL,
+ const char* message = NULL,
+ const char* path = NULL);
+```
+
+
+<a name="api_nan_try_catch"></a>
+### Nan::TryCatch
+
+A simple wrapper around [`v8::TryCatch`](https://v8docs.nodesource.com/node-8.11/d4/dc6/classv8_1_1_try_catch.html) compatible with all supported versions of V8. Can be used as a direct replacement in most cases. See also [`Nan::FatalException()`](#api_nan_fatal_exception) for an internal use compatible with `node::FatalException`.
+
+Signature:
+
+```c++
+class Nan::TryCatch {
+ public:
+ Nan::TryCatch();
+
+ bool HasCaught() const;
+
+ bool CanContinue() const;
+
+ v8::Local<v8::Value> ReThrow();
+
+ v8::Local<v8::Value> Exception() const;
+
+ // Nan::MaybeLocal for older versions of V8
+ v8::MaybeLocal<v8::Value> StackTrace() const;
+
+ v8::Local<v8::Message> Message() const;
+
+ void Reset();
+
+ void SetVerbose(bool value);
+
+ void SetCaptureMessage(bool value);
+};
+```
+
--- /dev/null
+## JSON
+
+The _JSON_ object provides the c++ versions of the methods offered by the `JSON` object in javascript. V8 exposes these methods via the `v8::JSON` object.
+
+ - <a href="#api_nan_json_parse"><b><code>Nan::JSON.Parse</code></b></a>
+ - <a href="#api_nan_json_stringify"><b><code>Nan::JSON.Stringify</code></b></a>
+
+Refer to the V8 JSON object in the [V8 documentation](https://v8docs.nodesource.com/node-8.11/da/d6f/classv8_1_1_j_s_o_n.html) for more information about these methods and their arguments.
+
+<a name="api_nan_json_parse"></a>
+
+### Nan::JSON.Parse
+
+A simple wrapper around [`v8::JSON::Parse`](https://v8docs.nodesource.com/node-8.11/da/d6f/classv8_1_1_j_s_o_n.html#a936310d2540fb630ed37d3ee3ffe4504).
+
+Definition:
+
+```c++
+Nan::MaybeLocal<v8::Value> Nan::JSON::Parse(v8::Local<v8::String> json_string);
+```
+
+Use `JSON.Parse(json_string)` to parse a string into a `v8::Value`.
+
+Example:
+
+```c++
+v8::Local<v8::String> json_string = Nan::New("{ \"JSON\": \"object\" }").ToLocalChecked();
+
+Nan::JSON NanJSON;
+Nan::MaybeLocal<v8::Value> result = NanJSON.Parse(json_string);
+if (!result.IsEmpty()) {
+ v8::Local<v8::Value> val = result.ToLocalChecked();
+}
+```
+
+<a name="api_nan_json_stringify"></a>
+
+### Nan::JSON.Stringify
+
+A simple wrapper around [`v8::JSON::Stringify`](https://v8docs.nodesource.com/node-8.11/da/d6f/classv8_1_1_j_s_o_n.html#a44b255c3531489ce43f6110209138860).
+
+Definition:
+
+```c++
+Nan::MaybeLocal<v8::String> Nan::JSON::Stringify(v8::Local<v8::Object> json_object, v8::Local<v8::String> gap = v8::Local<v8::String>());
+```
+
+Use `JSON.Stringify(value)` to stringify a `v8::Object`.
+
+Example:
+
+```c++
+// using `v8::Local<v8::Value> val` from the `JSON::Parse` example
+v8::Local<v8::Object> obj = Nan::To<v8::Object>(val).ToLocalChecked();
+
+Nan::JSON NanJSON;
+Nan::MaybeLocal<v8::String> result = NanJSON.Stringify(obj);
+if (!result.IsEmpty()) {
+ v8::Local<v8::String> stringified = result.ToLocalChecked();
+}
+```
+
--- /dev/null
+## Maybe Types
+
+The `Nan::MaybeLocal` and `Nan::Maybe` types are monads that encapsulate `v8::Local` handles that _may be empty_.
+
+* **Maybe Types**
+ - <a href="#api_nan_maybe_local"><b><code>Nan::MaybeLocal</code></b></a>
+ - <a href="#api_nan_maybe"><b><code>Nan::Maybe</code></b></a>
+ - <a href="#api_nan_nothing"><b><code>Nan::Nothing</code></b></a>
+ - <a href="#api_nan_just"><b><code>Nan::Just</code></b></a>
+* **Maybe Helpers**
+ - <a href="#api_nan_call"><b><code>Nan::Call()</code></b></a>
+ - <a href="#api_nan_to_detail_string"><b><code>Nan::ToDetailString()</code></b></a>
+ - <a href="#api_nan_to_array_index"><b><code>Nan::ToArrayIndex()</code></b></a>
+ - <a href="#api_nan_equals"><b><code>Nan::Equals()</code></b></a>
+ - <a href="#api_nan_new_instance"><b><code>Nan::NewInstance()</code></b></a>
+ - <a href="#api_nan_get_function"><b><code>Nan::GetFunction()</code></b></a>
+ - <a href="#api_nan_set"><b><code>Nan::Set()</code></b></a>
+ - <a href="#api_nan_define_own_property"><b><code>Nan::DefineOwnProperty()</code></b></a>
+ - <a href="#api_nan_force_set"><del><b><code>Nan::ForceSet()</code></b></del></a>
+ - <a href="#api_nan_get"><b><code>Nan::Get()</code></b></a>
+ - <a href="#api_nan_get_property_attribute"><b><code>Nan::GetPropertyAttributes()</code></b></a>
+ - <a href="#api_nan_has"><b><code>Nan::Has()</code></b></a>
+ - <a href="#api_nan_delete"><b><code>Nan::Delete()</code></b></a>
+ - <a href="#api_nan_get_property_names"><b><code>Nan::GetPropertyNames()</code></b></a>
+ - <a href="#api_nan_get_own_property_names"><b><code>Nan::GetOwnPropertyNames()</code></b></a>
+ - <a href="#api_nan_set_prototype"><b><code>Nan::SetPrototype()</code></b></a>
+ - <a href="#api_nan_object_proto_to_string"><b><code>Nan::ObjectProtoToString()</code></b></a>
+ - <a href="#api_nan_has_own_property"><b><code>Nan::HasOwnProperty()</code></b></a>
+ - <a href="#api_nan_has_real_named_property"><b><code>Nan::HasRealNamedProperty()</code></b></a>
+ - <a href="#api_nan_has_real_indexed_property"><b><code>Nan::HasRealIndexedProperty()</code></b></a>
+ - <a href="#api_nan_has_real_named_callback_property"><b><code>Nan::HasRealNamedCallbackProperty()</code></b></a>
+ - <a href="#api_nan_get_real_named_property_in_prototype_chain"><b><code>Nan::GetRealNamedPropertyInPrototypeChain()</code></b></a>
+ - <a href="#api_nan_get_real_named_property"><b><code>Nan::GetRealNamedProperty()</code></b></a>
+ - <a href="#api_nan_call_as_function"><b><code>Nan::CallAsFunction()</code></b></a>
+ - <a href="#api_nan_call_as_constructor"><b><code>Nan::CallAsConstructor()</code></b></a>
+ - <a href="#api_nan_get_source_line"><b><code>Nan::GetSourceLine()</code></b></a>
+ - <a href="#api_nan_get_line_number"><b><code>Nan::GetLineNumber()</code></b></a>
+ - <a href="#api_nan_get_start_column"><b><code>Nan::GetStartColumn()</code></b></a>
+ - <a href="#api_nan_get_end_column"><b><code>Nan::GetEndColumn()</code></b></a>
+ - <a href="#api_nan_clone_element_at"><b><code>Nan::CloneElementAt()</code></b></a>
+ - <a href="#api_nan_has_private"><b><code>Nan::HasPrivate()</code></b></a>
+ - <a href="#api_nan_get_private"><b><code>Nan::GetPrivate()</code></b></a>
+ - <a href="#api_nan_set_private"><b><code>Nan::SetPrivate()</code></b></a>
+ - <a href="#api_nan_delete_private"><b><code>Nan::DeletePrivate()</code></b></a>
+ - <a href="#api_nan_make_maybe"><b><code>Nan::MakeMaybe()</code></b></a>
+
+<a name="api_nan_maybe_local"></a>
+### Nan::MaybeLocal
+
+A `Nan::MaybeLocal<T>` is a wrapper around [`v8::Local<T>`](https://v8docs.nodesource.com/node-8.11/de/deb/classv8_1_1_local.html) that enforces a check that determines whether the `v8::Local<T>` is empty before it can be used.
+
+If an API method returns a `Nan::MaybeLocal`, the API method can potentially fail either because an exception is thrown, or because an exception is pending, e.g. because a previous API call threw an exception that hasn't been caught yet, or because a `v8::TerminateExecution` exception was thrown. In that case, an empty `Nan::MaybeLocal` is returned.
+
+Definition:
+
+```c++
+template<typename T> class Nan::MaybeLocal {
+ public:
+ MaybeLocal();
+
+ template<typename S> MaybeLocal(v8::Local<S> that);
+
+ bool IsEmpty() const;
+
+ template<typename S> bool ToLocal(v8::Local<S> *out);
+
+ // Will crash if the MaybeLocal<> is empty.
+ v8::Local<T> ToLocalChecked();
+
+ template<typename S> v8::Local<S> FromMaybe(v8::Local<S> default_value) const;
+};
+```
+
+See the documentation for [`v8::MaybeLocal`](https://v8docs.nodesource.com/node-8.11/d8/d7d/classv8_1_1_maybe_local.html) for further details.
+
+<a name="api_nan_maybe"></a>
+### Nan::Maybe
+
+A simple `Nan::Maybe` type, representing an object which may or may not have a value, see https://hackage.haskell.org/package/base/docs/Data-Maybe.html.
+
+If an API method returns a `Nan::Maybe<>`, the API method can potentially fail either because an exception is thrown, or because an exception is pending, e.g. because a previous API call threw an exception that hasn't been caught yet, or because a `v8::TerminateExecution` exception was thrown. In that case, a "Nothing" value is returned.
+
+Definition:
+
+```c++
+template<typename T> class Nan::Maybe {
+ public:
+ bool IsNothing() const;
+ bool IsJust() const;
+
+ // Will crash if the Maybe<> is nothing.
+ T FromJust();
+
+ T FromMaybe(const T& default_value);
+
+ bool operator==(const Maybe &other);
+
+ bool operator!=(const Maybe &other);
+};
+```
+
+See the documentation for [`v8::Maybe`](https://v8docs.nodesource.com/node-8.11/d9/d4b/classv8_1_1_maybe.html) for further details.
+
+<a name="api_nan_nothing"></a>
+### Nan::Nothing
+
+Construct an empty `Nan::Maybe` type representing _nothing_.
+
+```c++
+template<typename T> Nan::Maybe<T> Nan::Nothing();
+```
+
+<a name="api_nan_just"></a>
+### Nan::Just
+
+Construct a `Nan::Maybe` type representing _just_ a value.
+
+```c++
+template<typename T> Nan::Maybe<T> Nan::Just(const T &t);
+```
+
+<a name="api_nan_call"></a>
+### Nan::Call()
+
+A helper method for calling a synchronous [`v8::Function#Call()`](https://v8docs.nodesource.com/node-8.11/d5/d54/classv8_1_1_function.html#a9c3d0e4e13ddd7721fce238aa5b94a11) in a way compatible across supported versions of V8.
+
+For asynchronous callbacks, use Nan::Callback::Call along with an AsyncResource.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Value> Nan::Call(v8::Local<v8::Function> fun, v8::Local<v8::Object> recv, int argc, v8::Local<v8::Value> argv[]);
+Nan::MaybeLocal<v8::Value> Nan::Call(const Nan::Callback& callback, v8::Local<v8::Object> recv,
+ int argc, v8::Local<v8::Value> argv[]);
+Nan::MaybeLocal<v8::Value> Nan::Call(const Nan::Callback& callback, int argc, v8::Local<v8::Value> argv[]);
+```
+
+
+<a name="api_nan_to_detail_string"></a>
+### Nan::ToDetailString()
+
+A helper method for calling [`v8::Value#ToDetailString()`](https://v8docs.nodesource.com/node-8.11/dc/d0a/classv8_1_1_value.html#a2f9770296dc2c8d274bc8cc0dca243e5) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::String> Nan::ToDetailString(v8::Local<v8::Value> val);
+```
+
+
+<a name="api_nan_to_array_index"></a>
+### Nan::ToArrayIndex()
+
+A helper method for calling [`v8::Value#ToArrayIndex()`](https://v8docs.nodesource.com/node-8.11/dc/d0a/classv8_1_1_value.html#acc5bbef3c805ec458470c0fcd6f13493) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Uint32> Nan::ToArrayIndex(v8::Local<v8::Value> val);
+```
+
+
+<a name="api_nan_equals"></a>
+### Nan::Equals()
+
+A helper method for calling [`v8::Value#Equals()`](https://v8docs.nodesource.com/node-8.11/dc/d0a/classv8_1_1_value.html#a08fba1d776a59bbf6864b25f9152c64b) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<bool> Nan::Equals(v8::Local<v8::Value> a, v8::Local<v8::Value>(b));
+```
+
+
+<a name="api_nan_new_instance"></a>
+### Nan::NewInstance()
+
+A helper method for calling [`v8::Function#NewInstance()`](https://v8docs.nodesource.com/node-8.11/d5/d54/classv8_1_1_function.html#ae477558b10c14b76ed00e8dbab44ce5b) and [`v8::ObjectTemplate#NewInstance()`](https://v8docs.nodesource.com/node-8.11/db/d5f/classv8_1_1_object_template.html#ad605a7543cfbc5dab54cdb0883d14ae4) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Object> Nan::NewInstance(v8::Local<v8::Function> h);
+Nan::MaybeLocal<v8::Object> Nan::NewInstance(v8::Local<v8::Function> h, int argc, v8::Local<v8::Value> argv[]);
+Nan::MaybeLocal<v8::Object> Nan::NewInstance(v8::Local<v8::ObjectTemplate> h);
+```
+
+
+<a name="api_nan_get_function"></a>
+### Nan::GetFunction()
+
+A helper method for calling [`v8::FunctionTemplate#GetFunction()`](https://v8docs.nodesource.com/node-8.11/d8/d83/classv8_1_1_function_template.html#a56d904662a86eca78da37d9bb0ed3705) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Function> Nan::GetFunction(v8::Local<v8::FunctionTemplate> t);
+```
+
+
+<a name="api_nan_set"></a>
+### Nan::Set()
+
+A helper method for calling [`v8::Object#Set()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#a67604ea3734f170c66026064ea808f20) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<bool> Nan::Set(v8::Local<v8::Object> obj,
+ v8::Local<v8::Value> key,
+ v8::Local<v8::Value> value)
+Nan::Maybe<bool> Nan::Set(v8::Local<v8::Object> obj,
+ uint32_t index,
+ v8::Local<v8::Value> value);
+```
+
+
+<a name="api_nan_define_own_property"></a>
+### Nan::DefineOwnProperty()
+
+A helper method for calling [`v8::Object#DefineOwnProperty()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#a6f76b2ed605cb8f9185b92de0033a820) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<bool> Nan::DefineOwnProperty(v8::Local<v8::Object> obj,
+ v8::Local<v8::String> key,
+ v8::Local<v8::Value> value,
+ v8::PropertyAttribute attribs = v8::None);
+```
+
+
+<a name="api_nan_force_set"></a>
+### <del>Nan::ForceSet()</del>
+
+Deprecated, use <a href="#api_nan_define_own_property"><code>Nan::DefineOwnProperty()</code></a>.
+
+<del>A helper method for calling [`v8::Object#ForceSet()`](https://v8docs.nodesource.com/node-0.12/db/d85/classv8_1_1_object.html#acfbdfd7427b516ebdb5c47c4df5ed96c) in a way compatible across supported versions of V8.</del>
+
+Signature:
+
+```c++
+NAN_DEPRECATED Nan::Maybe<bool> Nan::ForceSet(v8::Local<v8::Object> obj,
+ v8::Local<v8::Value> key,
+ v8::Local<v8::Value> value,
+ v8::PropertyAttribute attribs = v8::None);
+```
+
+
+<a name="api_nan_get"></a>
+### Nan::Get()
+
+A helper method for calling [`v8::Object#Get()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#a2565f03e736694f6b1e1cf22a0b4eac2) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Value> Nan::Get(v8::Local<v8::Object> obj,
+ v8::Local<v8::Value> key);
+Nan::MaybeLocal<v8::Value> Nan::Get(v8::Local<v8::Object> obj, uint32_t index);
+```
+
+
+<a name="api_nan_get_property_attribute"></a>
+### Nan::GetPropertyAttributes()
+
+A helper method for calling [`v8::Object#GetPropertyAttributes()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#a9b898894da3d1db2714fd9325a54fe57) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<v8::PropertyAttribute> Nan::GetPropertyAttributes(
+ v8::Local<v8::Object> obj,
+ v8::Local<v8::Value> key);
+```
+
+
+<a name="api_nan_has"></a>
+### Nan::Has()
+
+A helper method for calling [`v8::Object#Has()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#ab3c3d89ea7c2f9afd08965bd7299a41d) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<bool> Nan::Has(v8::Local<v8::Object> obj, v8::Local<v8::String> key);
+Nan::Maybe<bool> Nan::Has(v8::Local<v8::Object> obj, uint32_t index);
+```
+
+
+<a name="api_nan_delete"></a>
+### Nan::Delete()
+
+A helper method for calling [`v8::Object#Delete()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#a48e4a19b2cedff867eecc73ddb7d377f) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<bool> Nan::Delete(v8::Local<v8::Object> obj,
+ v8::Local<v8::String> key);
+Nan::Maybe<bool> Nan::Delete(v8::Local<v8::Object> obj, uint32_t index);
+```
+
+
+<a name="api_nan_get_property_names"></a>
+### Nan::GetPropertyNames()
+
+A helper method for calling [`v8::Object#GetPropertyNames()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#aced885270cfd2c956367b5eedc7fbfe8) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Array> Nan::GetPropertyNames(v8::Local<v8::Object> obj);
+```
+
+
+<a name="api_nan_get_own_property_names"></a>
+### Nan::GetOwnPropertyNames()
+
+A helper method for calling [`v8::Object#GetOwnPropertyNames()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#a79a6e4d66049b9aa648ed4dfdb23e6eb) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Array> Nan::GetOwnPropertyNames(v8::Local<v8::Object> obj);
+```
+
+
+<a name="api_nan_set_prototype"></a>
+### Nan::SetPrototype()
+
+A helper method for calling [`v8::Object#SetPrototype()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#a442706b22fceda6e6d1f632122a9a9f4) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<bool> Nan::SetPrototype(v8::Local<v8::Object> obj,
+ v8::Local<v8::Value> prototype);
+```
+
+
+<a name="api_nan_object_proto_to_string"></a>
+### Nan::ObjectProtoToString()
+
+A helper method for calling [`v8::Object#ObjectProtoToString()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#ab7a92b4dcf822bef72f6c0ac6fea1f0b) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::String> Nan::ObjectProtoToString(v8::Local<v8::Object> obj);
+```
+
+
+<a name="api_nan_has_own_property"></a>
+### Nan::HasOwnProperty()
+
+A helper method for calling [`v8::Object#HasOwnProperty()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#ab7b7245442ca6de1e1c145ea3fd653ff) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<bool> Nan::HasOwnProperty(v8::Local<v8::Object> obj,
+ v8::Local<v8::String> key);
+```
+
+
+<a name="api_nan_has_real_named_property"></a>
+### Nan::HasRealNamedProperty()
+
+A helper method for calling [`v8::Object#HasRealNamedProperty()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#ad8b80a59c9eb3c1e6c3cd6c84571f767) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<bool> Nan::HasRealNamedProperty(v8::Local<v8::Object> obj,
+ v8::Local<v8::String> key);
+```
+
+
+<a name="api_nan_has_real_indexed_property"></a>
+### Nan::HasRealIndexedProperty()
+
+A helper method for calling [`v8::Object#HasRealIndexedProperty()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#af94fc1135a5e74a2193fb72c3a1b9855) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<bool> Nan::HasRealIndexedProperty(v8::Local<v8::Object> obj,
+ uint32_t index);
+```
+
+
+<a name="api_nan_has_real_named_callback_property"></a>
+### Nan::HasRealNamedCallbackProperty()
+
+A helper method for calling [`v8::Object#HasRealNamedCallbackProperty()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#af743b7ea132b89f84d34d164d0668811) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<bool> Nan::HasRealNamedCallbackProperty(
+ v8::Local<v8::Object> obj,
+ v8::Local<v8::String> key);
+```
+
+
+<a name="api_nan_get_real_named_property_in_prototype_chain"></a>
+### Nan::GetRealNamedPropertyInPrototypeChain()
+
+A helper method for calling [`v8::Object#GetRealNamedPropertyInPrototypeChain()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#a8700b1862e6b4783716964ba4d5e6172) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Value> Nan::GetRealNamedPropertyInPrototypeChain(
+ v8::Local<v8::Object> obj,
+ v8::Local<v8::String> key);
+```
+
+
+<a name="api_nan_get_real_named_property"></a>
+### Nan::GetRealNamedProperty()
+
+A helper method for calling [`v8::Object#GetRealNamedProperty()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#a84471a824576a5994fdd0ffcbf99ccc0) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Value> Nan::GetRealNamedProperty(v8::Local<v8::Object> obj,
+ v8::Local<v8::String> key);
+```
+
+
+<a name="api_nan_call_as_function"></a>
+### Nan::CallAsFunction()
+
+A helper method for calling [`v8::Object#CallAsFunction()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#ad3ffc36f3dfc3592ce2a96bc047ee2cd) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Value> Nan::CallAsFunction(v8::Local<v8::Object> obj,
+ v8::Local<v8::Object> recv,
+ int argc,
+ v8::Local<v8::Value> argv[]);
+```
+
+
+<a name="api_nan_call_as_constructor"></a>
+### Nan::CallAsConstructor()
+
+A helper method for calling [`v8::Object#CallAsConstructor()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#a50d571de50d0b0dfb28795619d07a01b) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Value> Nan::CallAsConstructor(v8::Local<v8::Object> obj,
+ int argc,
+ v8::Local<v8::Value> argv[]);
+```
+
+
+<a name="api_nan_get_source_line"></a>
+### Nan::GetSourceLine()
+
+A helper method for calling [`v8::Message#GetSourceLine()`](https://v8docs.nodesource.com/node-8.11/d9/d28/classv8_1_1_message.html#a849f7a6c41549d83d8159825efccd23a) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::String> Nan::GetSourceLine(v8::Local<v8::Message> msg);
+```
+
+
+<a name="api_nan_get_line_number"></a>
+### Nan::GetLineNumber()
+
+A helper method for calling [`v8::Message#GetLineNumber()`](https://v8docs.nodesource.com/node-8.11/d9/d28/classv8_1_1_message.html#adbe46c10a88a6565f2732a2d2adf99b9) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<int> Nan::GetLineNumber(v8::Local<v8::Message> msg);
+```
+
+
+<a name="api_nan_get_start_column"></a>
+### Nan::GetStartColumn()
+
+A helper method for calling [`v8::Message#GetStartColumn()`](https://v8docs.nodesource.com/node-8.11/d9/d28/classv8_1_1_message.html#a60ede616ba3822d712e44c7a74487ba6) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<int> Nan::GetStartColumn(v8::Local<v8::Message> msg);
+```
+
+
+<a name="api_nan_get_end_column"></a>
+### Nan::GetEndColumn()
+
+A helper method for calling [`v8::Message#GetEndColumn()`](https://v8docs.nodesource.com/node-8.11/d9/d28/classv8_1_1_message.html#aaa004cf19e529da980bc19fcb76d93be) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<int> Nan::GetEndColumn(v8::Local<v8::Message> msg);
+```
+
+
+<a name="api_nan_clone_element_at"></a>
+### Nan::CloneElementAt()
+
+A helper method for calling [`v8::Array#CloneElementAt()`](https://v8docs.nodesource.com/node-4.8/d3/d32/classv8_1_1_array.html#a1d3a878d4c1c7cae974dd50a1639245e) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Object> Nan::CloneElementAt(v8::Local<v8::Array> array, uint32_t index);
+```
+
+<a name="api_nan_has_private"></a>
+### Nan::HasPrivate()
+
+A helper method for calling [`v8::Object#HasPrivate()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#af68a0b98066cfdeb8f943e98a40ba08d) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<bool> Nan::HasPrivate(v8::Local<v8::Object> object, v8::Local<v8::String> key);
+```
+
+<a name="api_nan_get_private"></a>
+### Nan::GetPrivate()
+
+A helper method for calling [`v8::Object#GetPrivate()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#a169f2da506acbec34deadd9149a1925a) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Value> Nan::GetPrivate(v8::Local<v8::Object> object, v8::Local<v8::String> key);
+```
+
+<a name="api_nan_set_private"></a>
+### Nan::SetPrivate()
+
+A helper method for calling [`v8::Object#SetPrivate()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#ace1769b0f3b86bfe9fda1010916360ee) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<bool> Nan::SetPrivate(v8::Local<v8::Object> object, v8::Local<v8::String> key, v8::Local<v8::Value> value);
+```
+
+<a name="api_nan_delete_private"></a>
+### Nan::DeletePrivate()
+
+A helper method for calling [`v8::Object#DeletePrivate()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#a138bb32a304f3982be02ad499693b8fd) in a way compatible across supported versions of V8.
+
+Signature:
+
+```c++
+Nan::Maybe<bool> Nan::DeletePrivate(v8::Local<v8::Object> object, v8::Local<v8::String> key);
+```
+
+<a name="api_nan_make_maybe"></a>
+### Nan::MakeMaybe()
+
+Wraps a `v8::Local<>` in a `Nan::MaybeLocal<>`. When called with a `Nan::MaybeLocal<>` it just returns its argument. This is useful in generic template code that builds on NAN.
+
+Synopsis:
+
+```c++
+ MaybeLocal<v8::Number> someNumber = MakeMaybe(New<v8::Number>(3.141592654));
+ MaybeLocal<v8::String> someString = MakeMaybe(New<v8::String>("probably"));
+```
+
+Signature:
+
+```c++
+template <typename T, template <typename> class MaybeMaybe>
+Nan::MaybeLocal<T> Nan::MakeMaybe(MaybeMaybe<T> v);
+```
--- /dev/null
+## JavaScript-accessible methods
+
+A _template_ is a blueprint for JavaScript functions and objects in a context. You can use a template to wrap C++ functions and data structures within JavaScript objects so that they can be manipulated from JavaScript. See the V8 Embedders Guide section on [Templates](https://github.com/v8/v8/wiki/Embedder%27s-Guide#templates) for further information.
+
+In order to expose functionality to JavaScript via a template, you must provide it to V8 in a form that it understands. Across the versions of V8 supported by NAN, JavaScript-accessible method signatures vary widely, NAN fully abstracts method declaration and provides you with an interface that is similar to the most recent V8 API but is backward-compatible with older versions that still use the now-deceased `v8::Argument` type.
+
+* **Method argument types**
+ - <a href="#api_nan_function_callback_info"><b><code>Nan::FunctionCallbackInfo</code></b></a>
+ - <a href="#api_nan_property_callback_info"><b><code>Nan::PropertyCallbackInfo</code></b></a>
+ - <a href="#api_nan_return_value"><b><code>Nan::ReturnValue</code></b></a>
+* **Method declarations**
+ - <a href="#api_nan_method"><b>Method declaration</b></a>
+ - <a href="#api_nan_getter"><b>Getter declaration</b></a>
+ - <a href="#api_nan_setter"><b>Setter declaration</b></a>
+ - <a href="#api_nan_property_getter"><b>Property getter declaration</b></a>
+ - <a href="#api_nan_property_setter"><b>Property setter declaration</b></a>
+ - <a href="#api_nan_property_enumerator"><b>Property enumerator declaration</b></a>
+ - <a href="#api_nan_property_deleter"><b>Property deleter declaration</b></a>
+ - <a href="#api_nan_property_query"><b>Property query declaration</b></a>
+ - <a href="#api_nan_index_getter"><b>Index getter declaration</b></a>
+ - <a href="#api_nan_index_setter"><b>Index setter declaration</b></a>
+ - <a href="#api_nan_index_enumerator"><b>Index enumerator declaration</b></a>
+ - <a href="#api_nan_index_deleter"><b>Index deleter declaration</b></a>
+ - <a href="#api_nan_index_query"><b>Index query declaration</b></a>
+* Method and template helpers
+ - <a href="#api_nan_set_method"><b><code>Nan::SetMethod()</code></b></a>
+ - <a href="#api_nan_set_prototype_method"><b><code>Nan::SetPrototypeMethod()</code></b></a>
+ - <a href="#api_nan_set_accessor"><b><code>Nan::SetAccessor()</code></b></a>
+ - <a href="#api_nan_set_named_property_handler"><b><code>Nan::SetNamedPropertyHandler()</code></b></a>
+ - <a href="#api_nan_set_indexed_property_handler"><b><code>Nan::SetIndexedPropertyHandler()</code></b></a>
+ - <a href="#api_nan_set_template"><b><code>Nan::SetTemplate()</code></b></a>
+ - <a href="#api_nan_set_prototype_template"><b><code>Nan::SetPrototypeTemplate()</code></b></a>
+ - <a href="#api_nan_set_instance_template"><b><code>Nan::SetInstanceTemplate()</code></b></a>
+ - <a href="#api_nan_set_call_handler"><b><code>Nan::SetCallHandler()</code></b></a>
+ - <a href="#api_nan_set_call_as_function_handler"><b><code>Nan::SetCallAsFunctionHandler()</code></b></a>
+
+<a name="api_nan_function_callback_info"></a>
+### Nan::FunctionCallbackInfo
+
+`Nan::FunctionCallbackInfo` should be used in place of [`v8::FunctionCallbackInfo`](https://v8docs.nodesource.com/node-8.11/dd/d0d/classv8_1_1_function_callback_info.html), even with older versions of Node where `v8::FunctionCallbackInfo` does not exist.
+
+Definition:
+
+```c++
+template<typename T> class FunctionCallbackInfo {
+ public:
+ ReturnValue<T> GetReturnValue() const;
+ v8::Local<v8::Function> Callee(); // NOTE: Not available in NodeJS >= 10.0.0
+ v8::Local<v8::Value> Data();
+ v8::Local<v8::Object> Holder();
+ bool IsConstructCall();
+ int Length() const;
+ v8::Local<v8::Value> operator[](int i) const;
+ v8::Local<v8::Object> This() const;
+ v8::Isolate *GetIsolate() const;
+};
+```
+
+See the [`v8::FunctionCallbackInfo`](https://v8docs.nodesource.com/node-8.11/dd/d0d/classv8_1_1_function_callback_info.html) documentation for usage details on these. See [`Nan::ReturnValue`](#api_nan_return_value) for further information on how to set a return value from methods.
+
+**Note:** `FunctionCallbackInfo::Callee` is removed in Node.js after `10.0.0` because it is was deprecated in V8. Consider using `info.Data()` to pass any information you need.
+
+<a name="api_nan_property_callback_info"></a>
+### Nan::PropertyCallbackInfo
+
+`Nan::PropertyCallbackInfo` should be used in place of [`v8::PropertyCallbackInfo`](https://v8docs.nodesource.com/node-8.11/d7/dc5/classv8_1_1_property_callback_info.html), even with older versions of Node where `v8::PropertyCallbackInfo` does not exist.
+
+Definition:
+
+```c++
+template<typename T> class PropertyCallbackInfo : public PropertyCallbackInfoBase<T> {
+ public:
+ ReturnValue<T> GetReturnValue() const;
+ v8::Isolate* GetIsolate() const;
+ v8::Local<v8::Value> Data() const;
+ v8::Local<v8::Object> This() const;
+ v8::Local<v8::Object> Holder() const;
+};
+```
+
+See the [`v8::PropertyCallbackInfo`](https://v8docs.nodesource.com/node-8.11/d7/dc5/classv8_1_1_property_callback_info.html) documentation for usage details on these. See [`Nan::ReturnValue`](#api_nan_return_value) for further information on how to set a return value from property accessor methods.
+
+<a name="api_nan_return_value"></a>
+### Nan::ReturnValue
+
+`Nan::ReturnValue` is used in place of [`v8::ReturnValue`](https://v8docs.nodesource.com/node-8.11/da/da7/classv8_1_1_return_value.html) on both [`Nan::FunctionCallbackInfo`](#api_nan_function_callback_info) and [`Nan::PropertyCallbackInfo`](#api_nan_property_callback_info) as the return type of `GetReturnValue()`.
+
+Example usage:
+
+```c++
+void EmptyArray(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ info.GetReturnValue().Set(Nan::New<v8::Array>());
+}
+```
+
+Definition:
+
+```c++
+template<typename T> class ReturnValue {
+ public:
+ // Handle setters
+ template <typename S> void Set(const v8::Local<S> &handle);
+ template <typename S> void Set(const Nan::Global<S> &handle);
+
+ // Fast primitive setters
+ void Set(bool value);
+ void Set(double i);
+ void Set(int32_t i);
+ void Set(uint32_t i);
+
+ // Fast JS primitive setters
+ void SetNull();
+ void SetUndefined();
+ void SetEmptyString();
+
+ // Convenience getter for isolate
+ v8::Isolate *GetIsolate() const;
+};
+```
+
+See the documentation on [`v8::ReturnValue`](https://v8docs.nodesource.com/node-8.11/da/da7/classv8_1_1_return_value.html) for further information on this.
+
+<a name="api_nan_method"></a>
+### Method declaration
+
+JavaScript-accessible methods should be declared with the following signature to form a `Nan::FunctionCallback`:
+
+```c++
+typedef void(*FunctionCallback)(const FunctionCallbackInfo<v8::Value>&);
+```
+
+Example:
+
+```c++
+void MethodName(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ ...
+}
+```
+
+You do not need to declare a new `HandleScope` within a method as one is implicitly created for you.
+
+**Example usage**
+
+```c++
+// .h:
+class Foo : public Nan::ObjectWrap {
+ ...
+
+ static void Bar(const Nan::FunctionCallbackInfo<v8::Value>& info);
+ static void Baz(const Nan::FunctionCallbackInfo<v8::Value>& info);
+}
+
+
+// .cc:
+void Foo::Bar(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ ...
+}
+
+void Foo::Baz(const Nan::FunctionCallbackInfo<v8::Value>& info) {
+ ...
+}
+```
+
+A helper macro `NAN_METHOD(methodname)` exists, compatible with NAN v1 method declarations.
+
+**Example usage with `NAN_METHOD(methodname)`**
+
+```c++
+// .h:
+class Foo : public Nan::ObjectWrap {
+ ...
+
+ static NAN_METHOD(Bar);
+ static NAN_METHOD(Baz);
+}
+
+
+// .cc:
+NAN_METHOD(Foo::Bar) {
+ ...
+}
+
+NAN_METHOD(Foo::Baz) {
+ ...
+}
+```
+
+Use [`Nan::SetPrototypeMethod`](#api_nan_set_prototype_method) to attach a method to a JavaScript function prototype or [`Nan::SetMethod`](#api_nan_set_method) to attach a method directly on a JavaScript object.
+
+<a name="api_nan_getter"></a>
+### Getter declaration
+
+JavaScript-accessible getters should be declared with the following signature to form a `Nan::GetterCallback`:
+
+```c++
+typedef void(*GetterCallback)(v8::Local<v8::String>,
+ const PropertyCallbackInfo<v8::Value>&);
+```
+
+Example:
+
+```c++
+void GetterName(v8::Local<v8::String> property,
+ const Nan::PropertyCallbackInfo<v8::Value>& info) {
+ ...
+}
+```
+
+You do not need to declare a new `HandleScope` within a getter as one is implicitly created for you.
+
+A helper macro `NAN_GETTER(methodname)` exists, compatible with NAN v1 method declarations.
+
+Also see the V8 Embedders Guide documentation on [Accessors](https://developers.google.com/v8/embed#accesssors).
+
+<a name="api_nan_setter"></a>
+### Setter declaration
+
+JavaScript-accessible setters should be declared with the following signature to form a <b><code>Nan::SetterCallback</code></b>:
+
+```c++
+typedef void(*SetterCallback)(v8::Local<v8::String>,
+ v8::Local<v8::Value>,
+ const PropertyCallbackInfo<void>&);
+```
+
+Example:
+
+```c++
+void SetterName(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const Nan::PropertyCallbackInfo<void>& info) {
+ ...
+}
+```
+
+You do not need to declare a new `HandleScope` within a setter as one is implicitly created for you.
+
+A helper macro `NAN_SETTER(methodname)` exists, compatible with NAN v1 method declarations.
+
+Also see the V8 Embedders Guide documentation on [Accessors](https://developers.google.com/v8/embed#accesssors).
+
+<a name="api_nan_property_getter"></a>
+### Property getter declaration
+
+JavaScript-accessible property getters should be declared with the following signature to form a <b><code>Nan::PropertyGetterCallback</code></b>:
+
+```c++
+typedef void(*PropertyGetterCallback)(v8::Local<v8::String>,
+ const PropertyCallbackInfo<v8::Value>&);
+```
+
+Example:
+
+```c++
+void PropertyGetterName(v8::Local<v8::String> property,
+ const Nan::PropertyCallbackInfo<v8::Value>& info) {
+ ...
+}
+```
+
+You do not need to declare a new `HandleScope` within a property getter as one is implicitly created for you.
+
+A helper macro `NAN_PROPERTY_GETTER(methodname)` exists, compatible with NAN v1 method declarations.
+
+Also see the V8 Embedders Guide documentation on named property [Interceptors](https://developers.google.com/v8/embed#interceptors).
+
+<a name="api_nan_property_setter"></a>
+### Property setter declaration
+
+JavaScript-accessible property setters should be declared with the following signature to form a <b><code>Nan::PropertySetterCallback</code></b>:
+
+```c++
+typedef void(*PropertySetterCallback)(v8::Local<v8::String>,
+ v8::Local<v8::Value>,
+ const PropertyCallbackInfo<v8::Value>&);
+```
+
+Example:
+
+```c++
+void PropertySetterName(v8::Local<v8::String> property,
+ v8::Local<v8::Value> value,
+ const Nan::PropertyCallbackInfo<v8::Value>& info);
+```
+
+You do not need to declare a new `HandleScope` within a property setter as one is implicitly created for you.
+
+A helper macro `NAN_PROPERTY_SETTER(methodname)` exists, compatible with NAN v1 method declarations.
+
+Also see the V8 Embedders Guide documentation on named property [Interceptors](https://developers.google.com/v8/embed#interceptors).
+
+<a name="api_nan_property_enumerator"></a>
+### Property enumerator declaration
+
+JavaScript-accessible property enumerators should be declared with the following signature to form a <b><code>Nan::PropertyEnumeratorCallback</code></b>:
+
+```c++
+typedef void(*PropertyEnumeratorCallback)(const PropertyCallbackInfo<v8::Array>&);
+```
+
+Example:
+
+```c++
+void PropertyEnumeratorName(const Nan::PropertyCallbackInfo<v8::Array>& info);
+```
+
+You do not need to declare a new `HandleScope` within a property enumerator as one is implicitly created for you.
+
+A helper macro `NAN_PROPERTY_ENUMERATOR(methodname)` exists, compatible with NAN v1 method declarations.
+
+Also see the V8 Embedders Guide documentation on named property [Interceptors](https://developers.google.com/v8/embed#interceptors).
+
+<a name="api_nan_property_deleter"></a>
+### Property deleter declaration
+
+JavaScript-accessible property deleters should be declared with the following signature to form a <b><code>Nan::PropertyDeleterCallback</code></b>:
+
+```c++
+typedef void(*PropertyDeleterCallback)(v8::Local<v8::String>,
+ const PropertyCallbackInfo<v8::Boolean>&);
+```
+
+Example:
+
+```c++
+void PropertyDeleterName(v8::Local<v8::String> property,
+ const Nan::PropertyCallbackInfo<v8::Boolean>& info);
+```
+
+You do not need to declare a new `HandleScope` within a property deleter as one is implicitly created for you.
+
+A helper macro `NAN_PROPERTY_DELETER(methodname)` exists, compatible with NAN v1 method declarations.
+
+Also see the V8 Embedders Guide documentation on named property [Interceptors](https://developers.google.com/v8/embed#interceptors).
+
+<a name="api_nan_property_query"></a>
+### Property query declaration
+
+JavaScript-accessible property query methods should be declared with the following signature to form a <b><code>Nan::PropertyQueryCallback</code></b>:
+
+```c++
+typedef void(*PropertyQueryCallback)(v8::Local<v8::String>,
+ const PropertyCallbackInfo<v8::Integer>&);
+```
+
+Example:
+
+```c++
+void PropertyQueryName(v8::Local<v8::String> property,
+ const Nan::PropertyCallbackInfo<v8::Integer>& info);
+```
+
+You do not need to declare a new `HandleScope` within a property query method as one is implicitly created for you.
+
+A helper macro `NAN_PROPERTY_QUERY(methodname)` exists, compatible with NAN v1 method declarations.
+
+Also see the V8 Embedders Guide documentation on named property [Interceptors](https://developers.google.com/v8/embed#interceptors).
+
+<a name="api_nan_index_getter"></a>
+### Index getter declaration
+
+JavaScript-accessible index getter methods should be declared with the following signature to form a <b><code>Nan::IndexGetterCallback</code></b>:
+
+```c++
+typedef void(*IndexGetterCallback)(uint32_t,
+ const PropertyCallbackInfo<v8::Value>&);
+```
+
+Example:
+
+```c++
+void IndexGetterName(uint32_t index, const PropertyCallbackInfo<v8::Value>& info);
+```
+
+You do not need to declare a new `HandleScope` within a index getter as one is implicitly created for you.
+
+A helper macro `NAN_INDEX_GETTER(methodname)` exists, compatible with NAN v1 method declarations.
+
+Also see the V8 Embedders Guide documentation on indexed property [Interceptors](https://developers.google.com/v8/embed#interceptors).
+
+<a name="api_nan_index_setter"></a>
+### Index setter declaration
+
+JavaScript-accessible index setter methods should be declared with the following signature to form a <b><code>Nan::IndexSetterCallback</code></b>:
+
+```c++
+typedef void(*IndexSetterCallback)(uint32_t,
+ v8::Local<v8::Value>,
+ const PropertyCallbackInfo<v8::Value>&);
+```
+
+Example:
+
+```c++
+void IndexSetterName(uint32_t index,
+ v8::Local<v8::Value> value,
+ const PropertyCallbackInfo<v8::Value>& info);
+```
+
+You do not need to declare a new `HandleScope` within a index setter as one is implicitly created for you.
+
+A helper macro `NAN_INDEX_SETTER(methodname)` exists, compatible with NAN v1 method declarations.
+
+Also see the V8 Embedders Guide documentation on indexed property [Interceptors](https://developers.google.com/v8/embed#interceptors).
+
+<a name="api_nan_index_enumerator"></a>
+### Index enumerator declaration
+
+JavaScript-accessible index enumerator methods should be declared with the following signature to form a <b><code>Nan::IndexEnumeratorCallback</code></b>:
+
+```c++
+typedef void(*IndexEnumeratorCallback)(const PropertyCallbackInfo<v8::Array>&);
+```
+
+Example:
+
+```c++
+void IndexEnumeratorName(const PropertyCallbackInfo<v8::Array>& info);
+```
+
+You do not need to declare a new `HandleScope` within a index enumerator as one is implicitly created for you.
+
+A helper macro `NAN_INDEX_ENUMERATOR(methodname)` exists, compatible with NAN v1 method declarations.
+
+Also see the V8 Embedders Guide documentation on indexed property [Interceptors](https://developers.google.com/v8/embed#interceptors).
+
+<a name="api_nan_index_deleter"></a>
+### Index deleter declaration
+
+JavaScript-accessible index deleter methods should be declared with the following signature to form a <b><code>Nan::IndexDeleterCallback</code></b>:
+
+```c++
+typedef void(*IndexDeleterCallback)(uint32_t,
+ const PropertyCallbackInfo<v8::Boolean>&);
+```
+
+Example:
+
+```c++
+void IndexDeleterName(uint32_t index, const PropertyCallbackInfo<v8::Boolean>& info);
+```
+
+You do not need to declare a new `HandleScope` within a index deleter as one is implicitly created for you.
+
+A helper macro `NAN_INDEX_DELETER(methodname)` exists, compatible with NAN v1 method declarations.
+
+Also see the V8 Embedders Guide documentation on indexed property [Interceptors](https://developers.google.com/v8/embed#interceptors).
+
+<a name="api_nan_index_query"></a>
+### Index query declaration
+
+JavaScript-accessible index query methods should be declared with the following signature to form a <b><code>Nan::IndexQueryCallback</code></b>:
+
+```c++
+typedef void(*IndexQueryCallback)(uint32_t,
+ const PropertyCallbackInfo<v8::Integer>&);
+```
+
+Example:
+
+```c++
+void IndexQueryName(uint32_t index, const PropertyCallbackInfo<v8::Integer>& info);
+```
+
+You do not need to declare a new `HandleScope` within a index query method as one is implicitly created for you.
+
+A helper macro `NAN_INDEX_QUERY(methodname)` exists, compatible with NAN v1 method declarations.
+
+Also see the V8 Embedders Guide documentation on indexed property [Interceptors](https://developers.google.com/v8/embed#interceptors).
+
+<a name="api_nan_set_method"></a>
+### Nan::SetMethod()
+
+Sets a method with a given name directly on a JavaScript object where the method has the `Nan::FunctionCallback` signature (see <a href="#api_nan_method">Method declaration</a>).
+
+Signature:
+
+```c++
+void Nan::SetMethod(v8::Local<v8::Object> recv,
+ const char *name,
+ Nan::FunctionCallback callback)
+void Nan::SetMethod(v8::Local<v8::Template> templ,
+ const char *name,
+ Nan::FunctionCallback callback)
+```
+
+<a name="api_nan_set_prototype_method"></a>
+### Nan::SetPrototypeMethod()
+
+Sets a method with a given name on a `FunctionTemplate`'s prototype where the method has the `Nan::FunctionCallback` signature (see <a href="#api_nan_method">Method declaration</a>).
+
+Signature:
+
+```c++
+void Nan::SetPrototypeMethod(v8::Local<v8::FunctionTemplate> recv,
+ const char* name,
+ Nan::FunctionCallback callback)
+```
+
+<a name="api_nan_set_accessor"></a>
+### Nan::SetAccessor()
+
+Sets getters and setters for a property with a given name on an `ObjectTemplate` or a plain `Object`. Accepts getters with the `Nan::GetterCallback` signature (see <a href="#api_nan_getter">Getter declaration</a>) and setters with the `Nan::SetterCallback` signature (see <a href="#api_nan_setter">Setter declaration</a>).
+
+Signature:
+
+```c++
+void SetAccessor(v8::Local<v8::ObjectTemplate> tpl,
+ v8::Local<v8::String> name,
+ Nan::GetterCallback getter,
+ Nan::SetterCallback setter = 0,
+ v8::Local<v8::Value> data = v8::Local<v8::Value>(),
+ v8::AccessControl settings = v8::DEFAULT,
+ v8::PropertyAttribute attribute = v8::None,
+ imp::Sig signature = imp::Sig());
+bool SetAccessor(v8::Local<v8::Object> obj,
+ v8::Local<v8::String> name,
+ Nan::GetterCallback getter,
+ Nan::SetterCallback setter = 0,
+ v8::Local<v8::Value> data = v8::Local<v8::Value>(),
+ v8::AccessControl settings = v8::DEFAULT,
+ v8::PropertyAttribute attribute = v8::None)
+```
+
+See the V8 [`ObjectTemplate#SetAccessor()`](https://v8docs.nodesource.com/node-8.11/db/d5f/classv8_1_1_object_template.html#aca0ed196f8a9adb1f68b1aadb6c9cd77) and [`Object#SetAccessor()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#ae91b3b56b357f285288c89fbddc46d1b) for further information about how to use `Nan::SetAccessor()`.
+
+<a name="api_nan_set_named_property_handler"></a>
+### Nan::SetNamedPropertyHandler()
+
+Sets named property getters, setters, query, deleter and enumerator methods on an `ObjectTemplate`. Accepts:
+
+* Property getters with the `Nan::PropertyGetterCallback` signature (see <a href="#api_nan_property_getter">Property getter declaration</a>)
+* Property setters with the `Nan::PropertySetterCallback` signature (see <a href="#api_nan_property_setter">Property setter declaration</a>)
+* Property query methods with the `Nan::PropertyQueryCallback` signature (see <a href="#api_nan_property_query">Property query declaration</a>)
+* Property deleters with the `Nan::PropertyDeleterCallback` signature (see <a href="#api_nan_property_deleter">Property deleter declaration</a>)
+* Property enumerators with the `Nan::PropertyEnumeratorCallback` signature (see <a href="#api_nan_property_enumerator">Property enumerator declaration</a>)
+
+Signature:
+
+```c++
+void SetNamedPropertyHandler(v8::Local<v8::ObjectTemplate> tpl,
+ Nan::PropertyGetterCallback getter,
+ Nan::PropertySetterCallback setter = 0,
+ Nan::PropertyQueryCallback query = 0,
+ Nan::PropertyDeleterCallback deleter = 0,
+ Nan::PropertyEnumeratorCallback enumerator = 0,
+ v8::Local<v8::Value> data = v8::Local<v8::Value>())
+```
+
+See the V8 [`ObjectTemplate#SetNamedPropertyHandler()`](https://v8docs.nodesource.com/node-8.11/db/d5f/classv8_1_1_object_template.html#a33b3ebd7de641f6cc6414b7de01fc1c7) for further information about how to use `Nan::SetNamedPropertyHandler()`.
+
+<a name="api_nan_set_indexed_property_handler"></a>
+### Nan::SetIndexedPropertyHandler()
+
+Sets indexed property getters, setters, query, deleter and enumerator methods on an `ObjectTemplate`. Accepts:
+
+* Indexed property getters with the `Nan::IndexGetterCallback` signature (see <a href="#api_nan_index_getter">Index getter declaration</a>)
+* Indexed property setters with the `Nan::IndexSetterCallback` signature (see <a href="#api_nan_index_setter">Index setter declaration</a>)
+* Indexed property query methods with the `Nan::IndexQueryCallback` signature (see <a href="#api_nan_index_query">Index query declaration</a>)
+* Indexed property deleters with the `Nan::IndexDeleterCallback` signature (see <a href="#api_nan_index_deleter">Index deleter declaration</a>)
+* Indexed property enumerators with the `Nan::IndexEnumeratorCallback` signature (see <a href="#api_nan_index_enumerator">Index enumerator declaration</a>)
+
+Signature:
+
+```c++
+void SetIndexedPropertyHandler(v8::Local<v8::ObjectTemplate> tpl,
+ Nan::IndexGetterCallback getter,
+ Nan::IndexSetterCallback setter = 0,
+ Nan::IndexQueryCallback query = 0,
+ Nan::IndexDeleterCallback deleter = 0,
+ Nan::IndexEnumeratorCallback enumerator = 0,
+ v8::Local<v8::Value> data = v8::Local<v8::Value>())
+```
+
+See the V8 [`ObjectTemplate#SetIndexedPropertyHandler()`](https://v8docs.nodesource.com/node-8.11/db/d5f/classv8_1_1_object_template.html#ac89f06d634add0e890452033f7d17ff1) for further information about how to use `Nan::SetIndexedPropertyHandler()`.
+
+<a name="api_nan_set_template"></a>
+### Nan::SetTemplate()
+
+Adds properties on an `Object`'s or `Function`'s template.
+
+Signature:
+
+```c++
+void Nan::SetTemplate(v8::Local<v8::Template> templ,
+ const char *name,
+ v8::Local<v8::Data> value);
+void Nan::SetTemplate(v8::Local<v8::Template> templ,
+ v8::Local<v8::String> name,
+ v8::Local<v8::Data> value,
+ v8::PropertyAttribute attributes)
+```
+
+Calls the `Template`'s [`Set()`](https://v8docs.nodesource.com/node-8.11/db/df7/classv8_1_1_template.html#ae3fbaff137557aa6a0233bc7e52214ac).
+
+<a name="api_nan_set_prototype_template"></a>
+### Nan::SetPrototypeTemplate()
+
+Adds properties on an `Object`'s or `Function`'s prototype template.
+
+Signature:
+
+```c++
+void Nan::SetPrototypeTemplate(v8::Local<v8::FunctionTemplate> templ,
+ const char *name,
+ v8::Local<v8::Data> value);
+void Nan::SetPrototypeTemplate(v8::Local<v8::FunctionTemplate> templ,
+ v8::Local<v8::String> name,
+ v8::Local<v8::Data> value,
+ v8::PropertyAttribute attributes)
+```
+
+Calls the `FunctionTemplate`'s _PrototypeTemplate's_ [`Set()`](https://v8docs.nodesource.com/node-8.11/db/df7/classv8_1_1_template.html#a2db6a56597bf23c59659c0659e564ddf).
+
+<a name="api_nan_set_instance_template"></a>
+### Nan::SetInstanceTemplate()
+
+Use to add instance properties on `FunctionTemplate`'s.
+
+Signature:
+
+```c++
+void Nan::SetInstanceTemplate(v8::Local<v8::FunctionTemplate> templ,
+ const char *name,
+ v8::Local<v8::Data> value);
+void Nan::SetInstanceTemplate(v8::Local<v8::FunctionTemplate> templ,
+ v8::Local<v8::String> name,
+ v8::Local<v8::Data> value,
+ v8::PropertyAttribute attributes)
+```
+
+Calls the `FunctionTemplate`'s _InstanceTemplate's_ [`Set()`](https://v8docs.nodesource.com/node-8.11/db/df7/classv8_1_1_template.html#a2db6a56597bf23c59659c0659e564ddf).
+
+<a name="api_nan_set_call_handler"></a>
+### Nan::SetCallHandler()
+
+Set the call-handler callback for a `v8::FunctionTemplate`.
+This callback is called whenever the function created from this FunctionTemplate is called.
+
+Signature:
+
+```c++
+void Nan::SetCallHandler(v8::Local<v8::FunctionTemplate> templ, Nan::FunctionCallback callback, v8::Local<v8::Value> data = v8::Local<v8::Value>())
+```
+
+Calls the `FunctionTemplate`'s [`SetCallHandler()`](https://v8docs.nodesource.com/node-8.11/d8/d83/classv8_1_1_function_template.html#ab7574b298db3c27fbc2ed465c08ea2f8).
+
+<a name="api_nan_set_call_as_function_handler"></a>
+### Nan::SetCallAsFunctionHandler()
+
+Sets the callback to be used when calling instances created from the `v8::ObjectTemplate` as a function.
+If no callback is set, instances behave like normal JavaScript objects that cannot be called as a function.
+
+Signature:
+
+```c++
+void Nan::SetCallAsFunctionHandler(v8::Local<v8::ObjectTemplate> templ, Nan::FunctionCallback callback, v8::Local<v8::Value> data = v8::Local<v8::Value>())
+```
+
+Calls the `ObjectTemplate`'s [`SetCallAsFunctionHandler()`](https://v8docs.nodesource.com/node-8.11/db/d5f/classv8_1_1_object_template.html#a5e9612fc80bf6db8f2da199b9b0bd04e).
+
--- /dev/null
+## New
+
+NAN provides a `Nan::New()` helper for the creation of new JavaScript objects in a way that's compatible across the supported versions of V8.
+
+ - <a href="#api_nan_new"><b><code>Nan::New()</code></b></a>
+ - <a href="#api_nan_undefined"><b><code>Nan::Undefined()</code></b></a>
+ - <a href="#api_nan_null"><b><code>Nan::Null()</code></b></a>
+ - <a href="#api_nan_true"><b><code>Nan::True()</code></b></a>
+ - <a href="#api_nan_false"><b><code>Nan::False()</code></b></a>
+ - <a href="#api_nan_empty_string"><b><code>Nan::EmptyString()</code></b></a>
+
+
+<a name="api_nan_new"></a>
+### Nan::New()
+
+`Nan::New()` should be used to instantiate new JavaScript objects.
+
+Refer to the specific V8 type in the [V8 documentation](https://v8docs.nodesource.com/node-8.11/d1/d83/classv8_1_1_data.html) for information on the types of arguments required for instantiation.
+
+Signatures:
+
+Return types are mostly omitted from the signatures for simplicity. In most cases the type will be contained within a `v8::Local<T>`. The following types will be contained within a `Nan::MaybeLocal<T>`: `v8::String`, `v8::Date`, `v8::RegExp`, `v8::Script`, `v8::UnboundScript`.
+
+Empty objects:
+
+```c++
+Nan::New<T>();
+```
+
+Generic single and multiple-argument:
+
+```c++
+Nan::New<T>(A0 arg0);
+Nan::New<T>(A0 arg0, A1 arg1);
+Nan::New<T>(A0 arg0, A1 arg1, A2 arg2);
+Nan::New<T>(A0 arg0, A1 arg1, A2 arg2, A3 arg3);
+```
+
+For creating `v8::FunctionTemplate` and `v8::Function` objects:
+
+_The definition of `Nan::FunctionCallback` can be found in the [Method declaration](./methods.md#api_nan_method) documentation._
+
+```c++
+Nan::New<T>(Nan::FunctionCallback callback,
+ v8::Local<v8::Value> data = v8::Local<v8::Value>());
+Nan::New<T>(Nan::FunctionCallback callback,
+ v8::Local<v8::Value> data = v8::Local<v8::Value>(),
+ A2 a2 = A2());
+```
+
+Native number types:
+
+```c++
+v8::Local<v8::Boolean> Nan::New<T>(bool value);
+v8::Local<v8::Int32> Nan::New<T>(int32_t value);
+v8::Local<v8::Uint32> Nan::New<T>(uint32_t value);
+v8::Local<v8::Number> Nan::New<T>(double value);
+```
+
+String types:
+
+```c++
+Nan::MaybeLocal<v8::String> Nan::New<T>(std::string const& value);
+Nan::MaybeLocal<v8::String> Nan::New<T>(const char * value, int length);
+Nan::MaybeLocal<v8::String> Nan::New<T>(const char * value);
+Nan::MaybeLocal<v8::String> Nan::New<T>(const uint16_t * value);
+Nan::MaybeLocal<v8::String> Nan::New<T>(const uint16_t * value, int length);
+```
+
+Specialized types:
+
+```c++
+v8::Local<v8::String> Nan::New<T>(v8::String::ExternalStringResource * value);
+v8::Local<v8::String> Nan::New<T>(Nan::ExternalOneByteStringResource * value);
+v8::Local<v8::RegExp> Nan::New<T>(v8::Local<v8::String> pattern, v8::RegExp::Flags flags);
+```
+
+Note that `Nan::ExternalOneByteStringResource` maps to [`v8::String::ExternalOneByteStringResource`](https://v8docs.nodesource.com/node-8.11/d9/db3/classv8_1_1_string_1_1_external_one_byte_string_resource.html), and `v8::String::ExternalAsciiStringResource` in older versions of V8.
+
+
+<a name="api_nan_undefined"></a>
+### Nan::Undefined()
+
+A helper method to reference the `v8::Undefined` object in a way that is compatible across all supported versions of V8.
+
+Signature:
+
+```c++
+v8::Local<v8::Primitive> Nan::Undefined()
+```
+
+<a name="api_nan_null"></a>
+### Nan::Null()
+
+A helper method to reference the `v8::Null` object in a way that is compatible across all supported versions of V8.
+
+Signature:
+
+```c++
+v8::Local<v8::Primitive> Nan::Null()
+```
+
+<a name="api_nan_true"></a>
+### Nan::True()
+
+A helper method to reference the `v8::Boolean` object representing the `true` value in a way that is compatible across all supported versions of V8.
+
+Signature:
+
+```c++
+v8::Local<v8::Boolean> Nan::True()
+```
+
+<a name="api_nan_false"></a>
+### Nan::False()
+
+A helper method to reference the `v8::Boolean` object representing the `false` value in a way that is compatible across all supported versions of V8.
+
+Signature:
+
+```c++
+v8::Local<v8::Boolean> Nan::False()
+```
+
+<a name="api_nan_empty_string"></a>
+### Nan::EmptyString()
+
+Call [`v8::String::Empty`](https://v8docs.nodesource.com/node-8.11/d2/db3/classv8_1_1_string.html#a7c1bc8886115d7ee46f1d571dd6ebc6d) to reference the empty string in a way that is compatible across all supported versions of V8.
+
+Signature:
+
+```c++
+v8::Local<v8::String> Nan::EmptyString()
+```
+
+
+<a name="api_nan_new_one_byte_string"></a>
+### Nan::NewOneByteString()
+
+An implementation of [`v8::String::NewFromOneByte()`](https://v8docs.nodesource.com/node-8.11/d2/db3/classv8_1_1_string.html#a5264d50b96d2c896ce525a734dc10f09) provided for consistent availability and API across supported versions of V8. Allocates a new string from Latin-1 data.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::String> Nan::NewOneByteString(const uint8_t * value,
+ int length = -1)
+```
--- /dev/null
+## Miscellaneous Node Helpers
+
+ - <a href="#api_nan_asyncresource"><b><code>Nan::AsyncResource</code></b></a>
+ - <a href="#api_nan_make_callback"><b><code>Nan::MakeCallback()</code></b></a>
+ - <a href="#api_nan_module_init"><b><code>NAN_MODULE_INIT()</code></b></a>
+ - <a href="#api_nan_export"><b><code>Nan::Export()</code></b></a>
+
+<a name="api_nan_asyncresource"></a>
+### Nan::AsyncResource
+
+This class is analogous to the `AsyncResource` JavaScript class exposed by Node's [async_hooks][] API.
+
+When calling back into JavaScript asynchronously, special care must be taken to ensure that the runtime can properly track
+async hops. `Nan::AsyncResource` is a class that provides an RAII wrapper around `node::EmitAsyncInit`, `node::EmitAsyncDestroy`,
+and `node::MakeCallback`. Using this mechanism to call back into JavaScript, as opposed to `Nan::MakeCallback` or
+`v8::Function::Call` ensures that the callback is executed in the correct async context. This ensures that async mechanisms
+such as domains and [async_hooks][] function correctly.
+
+Definition:
+
+```c++
+class AsyncResource {
+ public:
+ AsyncResource(v8::Local<v8::String> name,
+ v8::Local<v8::Object> resource = New<v8::Object>());
+ AsyncResource(const char* name,
+ v8::Local<v8::Object> resource = New<v8::Object>());
+ ~AsyncResource();
+
+ v8::MaybeLocal<v8::Value> runInAsyncScope(v8::Local<v8::Object> target,
+ v8::Local<v8::Function> func,
+ int argc,
+ v8::Local<v8::Value>* argv);
+ v8::MaybeLocal<v8::Value> runInAsyncScope(v8::Local<v8::Object> target,
+ v8::Local<v8::String> symbol,
+ int argc,
+ v8::Local<v8::Value>* argv);
+ v8::MaybeLocal<v8::Value> runInAsyncScope(v8::Local<v8::Object> target,
+ const char* method,
+ int argc,
+ v8::Local<v8::Value>* argv);
+};
+```
+
+* `name`: Identifier for the kind of resource that is being provided for diagnostics information exposed by the [async_hooks][]
+ API. This will be passed to the possible `init` hook as the `type`. To avoid name collisions with other modules we recommend
+ that the name include the name of the owning module as a prefix. For example `mysql` module could use something like
+ `mysql:batch-db-query-resource`.
+* `resource`: An optional object associated with the async work that will be passed to the possible [async_hooks][]
+ `init` hook. If this parameter is omitted, or an empty handle is provided, this object will be created automatically.
+* When calling JS on behalf of this resource, one can use `runInAsyncScope`. This will ensure that the callback runs in the
+ correct async execution context.
+* `AsyncDestroy` is automatically called when an AsyncResource object is destroyed.
+
+For more details, see the Node [async_hooks][] documentation. You might also want to take a look at the documentation for the
+[N-API counterpart][napi]. For example usage, see the `asyncresource.cpp` example in the `test/cpp` directory.
+
+<a name="api_nan_make_callback"></a>
+### Nan::MakeCallback()
+
+Deprecated wrappers around the legacy `node::MakeCallback()` APIs. Node.js 10+
+has deprecated these legacy APIs as they do not provide a mechanism to preserve
+async context.
+
+We recommend that you use the `AsyncResource` class and `AsyncResource::runInAsyncScope` instead of using `Nan::MakeCallback` or
+`v8::Function#Call()` directly. `AsyncResource` properly takes care of running the callback in the correct async execution
+context – something that is essential for functionality like domains, async_hooks and async debugging.
+
+Signatures:
+
+```c++
+NAN_DEPRECATED
+v8::Local<v8::Value> Nan::MakeCallback(v8::Local<v8::Object> target,
+ v8::Local<v8::Function> func,
+ int argc,
+ v8::Local<v8::Value>* argv);
+NAN_DEPRECATED
+v8::Local<v8::Value> Nan::MakeCallback(v8::Local<v8::Object> target,
+ v8::Local<v8::String> symbol,
+ int argc,
+ v8::Local<v8::Value>* argv);
+NAN_DEPRECATED
+v8::Local<v8::Value> Nan::MakeCallback(v8::Local<v8::Object> target,
+ const char* method,
+ int argc,
+ v8::Local<v8::Value>* argv);
+```
+
+
+<a name="api_nan_module_init"></a>
+### NAN_MODULE_INIT()
+
+Used to define the entry point function to a Node add-on. Creates a function with a given `name` that receives a `target` object representing the equivalent of the JavaScript `exports` object.
+
+See example below.
+
+<a name="api_nan_export"></a>
+### Nan::Export()
+
+A simple helper to register a `v8::FunctionTemplate` from a JavaScript-accessible method (see [Methods](./methods.md)) as a property on an object. Can be used in a way similar to assigning properties to `module.exports` in JavaScript.
+
+Signature:
+
+```c++
+void Export(v8::Local<v8::Object> target, const char *name, Nan::FunctionCallback f)
+```
+
+Also available as the shortcut `NAN_EXPORT` macro.
+
+Example:
+
+```c++
+NAN_METHOD(Foo) {
+ ...
+}
+
+NAN_MODULE_INIT(Init) {
+ NAN_EXPORT(target, Foo);
+}
+```
+
+[async_hooks]: https://nodejs.org/dist/latest-v9.x/docs/api/async_hooks.html
+[napi]: https://nodejs.org/dist/latest-v9.x/docs/api/n-api.html#n_api_custom_asynchronous_operations
--- /dev/null
+## Object Wrappers
+
+The `ObjectWrap` class can be used to make wrapped C++ objects and a factory of wrapped objects.
+
+ - <a href="#api_nan_object_wrap"><b><code>Nan::ObjectWrap</code></b></a>
+
+
+<a name="api_nan_object_wrap"></a>
+### Nan::ObjectWrap()
+
+A reimplementation of `node::ObjectWrap` that adds some API not present in older versions of Node. Should be preferred over `node::ObjectWrap` in all cases for consistency.
+
+Definition:
+
+```c++
+class ObjectWrap {
+ public:
+ ObjectWrap();
+
+ virtual ~ObjectWrap();
+
+ template <class T>
+ static inline T* Unwrap(v8::Local<v8::Object> handle);
+
+ inline v8::Local<v8::Object> handle();
+
+ inline Nan::Persistent<v8::Object>& persistent();
+
+ protected:
+ inline void Wrap(v8::Local<v8::Object> handle);
+
+ inline void MakeWeak();
+
+ /* Ref() marks the object as being attached to an event loop.
+ * Refed objects will not be garbage collected, even if
+ * all references are lost.
+ */
+ virtual void Ref();
+
+ /* Unref() marks an object as detached from the event loop. This is its
+ * default state. When an object with a "weak" reference changes from
+ * attached to detached state it will be freed. Be careful not to access
+ * the object after making this call as it might be gone!
+ * (A "weak reference" means an object that only has a
+ * persistant handle.)
+ *
+ * DO NOT CALL THIS FROM DESTRUCTOR
+ */
+ virtual void Unref();
+
+ int refs_; // ro
+};
+```
+
+See the Node documentation on [Wrapping C++ Objects](https://nodejs.org/api/addons.html#addons_wrapping_c_objects) for more details.
+
+### This vs. Holder
+
+When calling `Unwrap`, it is important that the argument is indeed some JavaScript object which got wrapped by a `Wrap` call for this class or any derived class.
+The `Signature` installed by [`Nan::SetPrototypeMethod()`](methods.md#api_nan_set_prototype_method) does ensure that `info.Holder()` is just such an instance.
+In Node 0.12 and later, `info.This()` will also be of such a type, since otherwise the invocation will get rejected.
+However, in Node 0.10 and before it was possible to invoke a method on a JavaScript object which just had the extension type in its prototype chain.
+In such a situation, calling `Unwrap` on `info.This()` will likely lead to a failed assertion causing a crash, but could lead to even more serious corruption.
+
+On the other hand, calling `Unwrap` in an [accessor](methods.md#api_nan_set_accessor) should not use `Holder()` if the accessor is defined on the prototype.
+So either define your accessors on the instance template,
+or use `This()` after verifying that it is indeed a valid object.
+
+### Examples
+
+#### Basic
+
+```c++
+class MyObject : public Nan::ObjectWrap {
+ public:
+ static NAN_MODULE_INIT(Init) {
+ v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
+ tpl->SetClassName(Nan::New("MyObject").ToLocalChecked());
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
+
+ Nan::SetPrototypeMethod(tpl, "getHandle", GetHandle);
+ Nan::SetPrototypeMethod(tpl, "getValue", GetValue);
+
+ constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
+ Nan::Set(target, Nan::New("MyObject").ToLocalChecked(),
+ Nan::GetFunction(tpl).ToLocalChecked());
+ }
+
+ private:
+ explicit MyObject(double value = 0) : value_(value) {}
+ ~MyObject() {}
+
+ static NAN_METHOD(New) {
+ if (info.IsConstructCall()) {
+ double value = info[0]->IsUndefined() ? 0 : Nan::To<double>(info[0]).FromJust();
+ MyObject *obj = new MyObject(value);
+ obj->Wrap(info.This());
+ info.GetReturnValue().Set(info.This());
+ } else {
+ const int argc = 1;
+ v8::Local<v8::Value> argv[argc] = {info[0]};
+ v8::Local<v8::Function> cons = Nan::New(constructor());
+ info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked());
+ }
+ }
+
+ static NAN_METHOD(GetHandle) {
+ MyObject* obj = Nan::ObjectWrap::Unwrap<MyObject>(info.Holder());
+ info.GetReturnValue().Set(obj->handle());
+ }
+
+ static NAN_METHOD(GetValue) {
+ MyObject* obj = Nan::ObjectWrap::Unwrap<MyObject>(info.Holder());
+ info.GetReturnValue().Set(obj->value_);
+ }
+
+ static inline Nan::Persistent<v8::Function> & constructor() {
+ static Nan::Persistent<v8::Function> my_constructor;
+ return my_constructor;
+ }
+
+ double value_;
+};
+
+NODE_MODULE(objectwrapper, MyObject::Init)
+```
+
+To use in Javascript:
+
+```Javascript
+var objectwrapper = require('bindings')('objectwrapper');
+
+var obj = new objectwrapper.MyObject(5);
+console.log('Should be 5: ' + obj.getValue());
+```
+
+#### Factory of wrapped objects
+
+```c++
+class MyFactoryObject : public Nan::ObjectWrap {
+ public:
+ static NAN_MODULE_INIT(Init) {
+ v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
+ tpl->InstanceTemplate()->SetInternalFieldCount(1);
+
+ Nan::SetPrototypeMethod(tpl, "getValue", GetValue);
+
+ constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
+ }
+
+ static NAN_METHOD(NewInstance) {
+ v8::Local<v8::Function> cons = Nan::New(constructor());
+ double value = info[0]->IsNumber() ? Nan::To<double>(info[0]).FromJust() : 0;
+ const int argc = 1;
+ v8::Local<v8::Value> argv[1] = {Nan::New(value)};
+ info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked());
+ }
+
+ // Needed for the next example:
+ inline double value() const {
+ return value_;
+ }
+
+ private:
+ explicit MyFactoryObject(double value = 0) : value_(value) {}
+ ~MyFactoryObject() {}
+
+ static NAN_METHOD(New) {
+ if (info.IsConstructCall()) {
+ double value = info[0]->IsNumber() ? Nan::To<double>(info[0]).FromJust() : 0;
+ MyFactoryObject * obj = new MyFactoryObject(value);
+ obj->Wrap(info.This());
+ info.GetReturnValue().Set(info.This());
+ } else {
+ const int argc = 1;
+ v8::Local<v8::Value> argv[argc] = {info[0]};
+ v8::Local<v8::Function> cons = Nan::New(constructor());
+ info.GetReturnValue().Set(Nan::NewInstance(cons, argc, argv).ToLocalChecked());
+ }
+ }
+
+ static NAN_METHOD(GetValue) {
+ MyFactoryObject* obj = ObjectWrap::Unwrap<MyFactoryObject>(info.Holder());
+ info.GetReturnValue().Set(obj->value_);
+ }
+
+ static inline Nan::Persistent<v8::Function> & constructor() {
+ static Nan::Persistent<v8::Function> my_constructor;
+ return my_constructor;
+ }
+
+ double value_;
+};
+
+NAN_MODULE_INIT(Init) {
+ MyFactoryObject::Init(target);
+ Nan::Set(target,
+ Nan::New<v8::String>("newFactoryObjectInstance").ToLocalChecked(),
+ Nan::GetFunction(
+ Nan::New<v8::FunctionTemplate>(MyFactoryObject::NewInstance)).ToLocalChecked()
+ );
+}
+
+NODE_MODULE(wrappedobjectfactory, Init)
+```
+
+To use in Javascript:
+
+```Javascript
+var wrappedobjectfactory = require('bindings')('wrappedobjectfactory');
+
+var obj = wrappedobjectfactory.newFactoryObjectInstance(10);
+console.log('Should be 10: ' + obj.getValue());
+```
+
+#### Passing wrapped objects around
+
+Use the `MyFactoryObject` class above along with the following:
+
+```c++
+static NAN_METHOD(Sum) {
+ Nan::MaybeLocal<v8::Object> maybe1 = Nan::To<v8::Object>(info[0]);
+ Nan::MaybeLocal<v8::Object> maybe2 = Nan::To<v8::Object>(info[1]);
+
+ // Quick check:
+ if (maybe1.IsEmpty() || maybe2.IsEmpty()) {
+ // return value is undefined by default
+ return;
+ }
+
+ MyFactoryObject* obj1 =
+ Nan::ObjectWrap::Unwrap<MyFactoryObject>(maybe1.ToLocalChecked());
+ MyFactoryObject* obj2 =
+ Nan::ObjectWrap::Unwrap<MyFactoryObject>(maybe2.ToLocalChecked());
+
+ info.GetReturnValue().Set(Nan::New<v8::Number>(obj1->value() + obj2->value()));
+}
+
+NAN_MODULE_INIT(Init) {
+ MyFactoryObject::Init(target);
+ Nan::Set(target,
+ Nan::New<v8::String>("newFactoryObjectInstance").ToLocalChecked(),
+ Nan::GetFunction(
+ Nan::New<v8::FunctionTemplate>(MyFactoryObject::NewInstance)).ToLocalChecked()
+ );
+ Nan::Set(target,
+ Nan::New<v8::String>("sum").ToLocalChecked(),
+ Nan::GetFunction(Nan::New<v8::FunctionTemplate>(Sum)).ToLocalChecked()
+ );
+}
+
+NODE_MODULE(myaddon, Init)
+```
+
+To use in Javascript:
+
+```Javascript
+var myaddon = require('bindings')('myaddon');
+
+var obj1 = myaddon.newFactoryObjectInstance(5);
+var obj2 = myaddon.newFactoryObjectInstance(10);
+console.log('sum of object values: ' + myaddon.sum(obj1, obj2));
+```
--- /dev/null
+## Persistent references
+
+An object reference that is independent of any `HandleScope` is a _persistent_ reference. Where a `Local` handle only lives as long as the `HandleScope` in which it was allocated, a `Persistent` handle remains valid until it is explicitly disposed.
+
+Due to the evolution of the V8 API, it is necessary for NAN to provide a wrapper implementation of the `Persistent` classes to supply compatibility across the V8 versions supported.
+
+ - <a href="#api_nan_persistent_base"><b><code>Nan::PersistentBase & v8::PersistentBase</code></b></a>
+ - <a href="#api_nan_non_copyable_persistent_traits"><b><code>Nan::NonCopyablePersistentTraits & v8::NonCopyablePersistentTraits</code></b></a>
+ - <a href="#api_nan_copyable_persistent_traits"><b><code>Nan::CopyablePersistentTraits & v8::CopyablePersistentTraits</code></b></a>
+ - <a href="#api_nan_persistent"><b><code>Nan::Persistent</code></b></a>
+ - <a href="#api_nan_global"><b><code>Nan::Global</code></b></a>
+ - <a href="#api_nan_weak_callback_info"><b><code>Nan::WeakCallbackInfo</code></b></a>
+ - <a href="#api_nan_weak_callback_type"><b><code>Nan::WeakCallbackType</code></b></a>
+
+Also see the V8 Embedders Guide section on [Handles and Garbage Collection](https://developers.google.com/v8/embed#handles).
+
+<a name="api_nan_persistent_base"></a>
+### Nan::PersistentBase & v8::PersistentBase
+
+A persistent handle contains a reference to a storage cell in V8 which holds an object value and which is updated by the garbage collector whenever the object is moved. A new storage cell can be created using the constructor or `Nan::PersistentBase::Reset()`. Existing handles can be disposed using an argument-less `Nan::PersistentBase::Reset()`.
+
+Definition:
+
+_(note: this is implemented as `Nan::PersistentBase` for older versions of V8 and the native `v8::PersistentBase` is used for newer versions of V8)_
+
+```c++
+template<typename T> class PersistentBase {
+ public:
+ /**
+ * If non-empty, destroy the underlying storage cell
+ */
+ void Reset();
+
+ /**
+ * If non-empty, destroy the underlying storage cell and create a new one with
+ * the contents of another if it is also non-empty
+ */
+ template<typename S> void Reset(const v8::Local<S> &other);
+
+ /**
+ * If non-empty, destroy the underlying storage cell and create a new one with
+ * the contents of another if it is also non-empty
+ */
+ template<typename S> void Reset(const PersistentBase<S> &other);
+
+ /** Returns true if the handle is empty. */
+ bool IsEmpty() const;
+
+ /**
+ * If non-empty, destroy the underlying storage cell
+ * IsEmpty() will return true after this call.
+ */
+ void Empty();
+
+ template<typename S> bool operator==(const PersistentBase<S> &that);
+
+ template<typename S> bool operator==(const v8::Local<S> &that);
+
+ template<typename S> bool operator!=(const PersistentBase<S> &that);
+
+ template<typename S> bool operator!=(const v8::Local<S> &that);
+
+ /**
+ * Install a finalization callback on this object.
+ * NOTE: There is no guarantee as to *when* or even *if* the callback is
+ * invoked. The invocation is performed solely on a best effort basis.
+ * As always, GC-based finalization should *not* be relied upon for any
+ * critical form of resource management! At the moment you can either
+ * specify a parameter for the callback or the location of two internal
+ * fields in the dying object.
+ */
+ template<typename P>
+ void SetWeak(P *parameter,
+ typename WeakCallbackInfo<P>::Callback callback,
+ WeakCallbackType type);
+
+ void ClearWeak();
+
+ /**
+ * Marks the reference to this object independent. Garbage collector is free
+ * to ignore any object groups containing this object. Weak callback for an
+ * independent handle should not assume that it will be preceded by a global
+ * GC prologue callback or followed by a global GC epilogue callback.
+ */
+ void MarkIndependent() const;
+
+ bool IsIndependent() const;
+
+ /** Checks if the handle holds the only reference to an object. */
+ bool IsNearDeath() const;
+
+ /** Returns true if the handle's reference is weak. */
+ bool IsWeak() const
+};
+```
+
+See the V8 documentation for [`PersistentBase`](https://v8docs.nodesource.com/node-8.11/d4/dca/classv8_1_1_persistent_base.html) for further information.
+
+**Tip:** To get a `v8::Local` reference to the original object back from a `PersistentBase` or `Persistent` object:
+
+```c++
+v8::Local<v8::Object> object = Nan::New(persistent);
+```
+
+<a name="api_nan_non_copyable_persistent_traits"></a>
+### Nan::NonCopyablePersistentTraits & v8::NonCopyablePersistentTraits
+
+Default traits for `Nan::Persistent`. This class does not allow use of the a copy constructor or assignment operator. At present `kResetInDestructor` is not set, but that will change in a future version.
+
+Definition:
+
+_(note: this is implemented as `Nan::NonCopyablePersistentTraits` for older versions of V8 and the native `v8::NonCopyablePersistentTraits` is used for newer versions of V8)_
+
+```c++
+template<typename T> class NonCopyablePersistentTraits {
+ public:
+ typedef Persistent<T, NonCopyablePersistentTraits<T> > NonCopyablePersistent;
+
+ static const bool kResetInDestructor = false;
+
+ template<typename S, typename M>
+ static void Copy(const Persistent<S, M> &source,
+ NonCopyablePersistent *dest);
+
+ template<typename O> static void Uncompilable();
+};
+```
+
+See the V8 documentation for [`NonCopyablePersistentTraits`](https://v8docs.nodesource.com/node-8.11/de/d73/classv8_1_1_non_copyable_persistent_traits.html) for further information.
+
+<a name="api_nan_copyable_persistent_traits"></a>
+### Nan::CopyablePersistentTraits & v8::CopyablePersistentTraits
+
+A helper class of traits to allow copying and assignment of `Persistent`. This will clone the contents of storage cell, but not any of the flags, etc..
+
+Definition:
+
+_(note: this is implemented as `Nan::CopyablePersistentTraits` for older versions of V8 and the native `v8::NonCopyablePersistentTraits` is used for newer versions of V8)_
+
+```c++
+template<typename T>
+class CopyablePersistentTraits {
+ public:
+ typedef Persistent<T, CopyablePersistentTraits<T> > CopyablePersistent;
+
+ static const bool kResetInDestructor = true;
+
+ template<typename S, typename M>
+ static void Copy(const Persistent<S, M> &source,
+ CopyablePersistent *dest);
+};
+```
+
+See the V8 documentation for [`CopyablePersistentTraits`](https://v8docs.nodesource.com/node-8.11/da/d5c/structv8_1_1_copyable_persistent_traits.html) for further information.
+
+<a name="api_nan_persistent"></a>
+### Nan::Persistent
+
+A type of `PersistentBase` which allows copy and assignment. Copy, assignment and destructor behavior is controlled by the traits class `M`.
+
+Definition:
+
+```c++
+template<typename T, typename M = NonCopyablePersistentTraits<T> >
+class Persistent;
+
+template<typename T, typename M> class Persistent : public PersistentBase<T> {
+ public:
+ /**
+ * A Persistent with no storage cell.
+ */
+ Persistent();
+
+ /**
+ * Construct a Persistent from a v8::Local. When the v8::Local is non-empty, a
+ * new storage cell is created pointing to the same object, and no flags are
+ * set.
+ */
+ template<typename S> Persistent(v8::Local<S> that);
+
+ /**
+ * Construct a Persistent from a Persistent. When the Persistent is non-empty,
+ * a new storage cell is created pointing to the same object, and no flags are
+ * set.
+ */
+ Persistent(const Persistent &that);
+
+ /**
+ * The copy constructors and assignment operator create a Persistent exactly
+ * as the Persistent constructor, but the Copy function from the traits class
+ * is called, allowing the setting of flags based on the copied Persistent.
+ */
+ Persistent &operator=(const Persistent &that);
+
+ template <typename S, typename M2>
+ Persistent &operator=(const Persistent<S, M2> &that);
+
+ /**
+ * The destructor will dispose the Persistent based on the kResetInDestructor
+ * flags in the traits class. Since not calling dispose can result in a
+ * memory leak, it is recommended to always set this flag.
+ */
+ ~Persistent();
+};
+```
+
+See the V8 documentation for [`Persistent`](https://v8docs.nodesource.com/node-8.11/d2/d78/classv8_1_1_persistent.html) for further information.
+
+<a name="api_nan_global"></a>
+### Nan::Global
+
+A type of `PersistentBase` which has move semantics.
+
+```c++
+template<typename T> class Global : public PersistentBase<T> {
+ public:
+ /**
+ * A Global with no storage cell.
+ */
+ Global();
+
+ /**
+ * Construct a Global from a v8::Local. When the v8::Local is non-empty, a new
+ * storage cell is created pointing to the same object, and no flags are set.
+ */
+ template<typename S> Global(v8::Local<S> that);
+ /**
+ * Construct a Global from a PersistentBase. When the Persistent is non-empty,
+ * a new storage cell is created pointing to the same object, and no flags are
+ * set.
+ */
+ template<typename S> Global(const PersistentBase<S> &that);
+
+ /**
+ * Pass allows returning globals from functions, etc.
+ */
+ Global Pass();
+};
+```
+
+See the V8 documentation for [`Global`](https://v8docs.nodesource.com/node-8.11/d5/d40/classv8_1_1_global.html) for further information.
+
+<a name="api_nan_weak_callback_info"></a>
+### Nan::WeakCallbackInfo
+
+`Nan::WeakCallbackInfo` is used as an argument when setting a persistent reference as weak. You may need to free any external resources attached to the object. It is a mirror of `v8:WeakCallbackInfo` as found in newer versions of V8.
+
+Definition:
+
+```c++
+template<typename T> class WeakCallbackInfo {
+ public:
+ typedef void (*Callback)(const WeakCallbackInfo<T>& data);
+
+ v8::Isolate *GetIsolate() const;
+
+ /**
+ * Get the parameter that was associated with the weak handle.
+ */
+ T *GetParameter() const;
+
+ /**
+ * Get pointer from internal field, index can be 0 or 1.
+ */
+ void *GetInternalField(int index) const;
+};
+```
+
+Example usage:
+
+```c++
+void weakCallback(const WeakCallbackInfo<int> &data) {
+ int *parameter = data.GetParameter();
+ delete parameter;
+}
+
+Persistent<v8::Object> obj;
+int *data = new int(0);
+obj.SetWeak(data, callback, WeakCallbackType::kParameter);
+```
+
+See the V8 documentation for [`WeakCallbackInfo`](https://v8docs.nodesource.com/node-8.11/d8/d06/classv8_1_1_weak_callback_info.html) for further information.
+
+<a name="api_nan_weak_callback_type"></a>
+### Nan::WeakCallbackType
+
+Represents the type of a weak callback.
+A weak callback of type `kParameter` makes the supplied parameter to `Nan::PersistentBase::SetWeak` available through `WeakCallbackInfo::GetParameter`.
+A weak callback of type `kInternalFields` uses up to two internal fields at indices 0 and 1 on the `Nan::PersistentBase<v8::Object>` being made weak.
+Note that only `v8::Object`s and derivatives can have internal fields.
+
+Definition:
+
+```c++
+enum class WeakCallbackType { kParameter, kInternalFields };
+```
--- /dev/null
+## Scopes
+
+A _local handle_ is a pointer to an object. All V8 objects are accessed using handles, they are necessary because of the way the V8 garbage collector works.
+
+A handle scope can be thought of as a container for any number of handles. When you've finished with your handles, instead of deleting each one individually you can simply delete their scope.
+
+The creation of `HandleScope` objects is different across the supported versions of V8. Therefore, NAN provides its own implementations that can be used safely across these.
+
+ - <a href="#api_nan_handle_scope"><b><code>Nan::HandleScope</code></b></a>
+ - <a href="#api_nan_escapable_handle_scope"><b><code>Nan::EscapableHandleScope</code></b></a>
+
+Also see the V8 Embedders Guide section on [Handles and Garbage Collection](https://github.com/v8/v8/wiki/Embedder%27s%20Guide#handles-and-garbage-collection).
+
+<a name="api_nan_handle_scope"></a>
+### Nan::HandleScope
+
+A simple wrapper around [`v8::HandleScope`](https://v8docs.nodesource.com/node-8.11/d3/d95/classv8_1_1_handle_scope.html).
+
+Definition:
+
+```c++
+class Nan::HandleScope {
+ public:
+ Nan::HandleScope();
+ static int NumberOfHandles();
+};
+```
+
+Allocate a new `Nan::HandleScope` whenever you are creating new V8 JavaScript objects. Note that an implicit `HandleScope` is created for you on JavaScript-accessible methods so you do not need to insert one yourself.
+
+Example:
+
+```c++
+// new object is created, it needs a new scope:
+void Pointless() {
+ Nan::HandleScope scope;
+ v8::Local<v8::Object> obj = Nan::New<v8::Object>();
+}
+
+// JavaScript-accessible method already has a HandleScope
+NAN_METHOD(Pointless2) {
+ v8::Local<v8::Object> obj = Nan::New<v8::Object>();
+}
+```
+
+<a name="api_nan_escapable_handle_scope"></a>
+### Nan::EscapableHandleScope
+
+Similar to [`Nan::HandleScope`](#api_nan_handle_scope) but should be used in cases where a function needs to return a V8 JavaScript type that has been created within it.
+
+Definition:
+
+```c++
+class Nan::EscapableHandleScope {
+ public:
+ Nan::EscapableHandleScope();
+ static int NumberOfHandles();
+ template<typename T> v8::Local<T> Escape(v8::Local<T> value);
+}
+```
+
+Use `Escape(value)` to return the object.
+
+Example:
+
+```c++
+v8::Local<v8::Object> EmptyObj() {
+ Nan::EscapableHandleScope scope;
+ v8::Local<v8::Object> obj = Nan::New<v8::Object>();
+ return scope.Escape(obj);
+}
+```
+
--- /dev/null
+## Script
+
+NAN provides a `v8::Script` helpers as the API has changed over the supported versions of V8.
+
+ - <a href="#api_nan_compile_script"><b><code>Nan::CompileScript()</code></b></a>
+ - <a href="#api_nan_run_script"><b><code>Nan::RunScript()</code></b></a>
+
+
+<a name="api_nan_compile_script"></a>
+### Nan::CompileScript()
+
+A wrapper around [`v8::ScriptCompiler::Compile()`](https://v8docs.nodesource.com/node-8.11/da/da5/classv8_1_1_script_compiler.html#a93f5072a0db55d881b969e9fc98e564b).
+
+Note that `Nan::BoundScript` is an alias for `v8::Script`.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<Nan::BoundScript> Nan::CompileScript(
+ v8::Local<v8::String> s,
+ const v8::ScriptOrigin& origin);
+Nan::MaybeLocal<Nan::BoundScript> Nan::CompileScript(v8::Local<v8::String> s);
+```
+
+
+<a name="api_nan_run_script"></a>
+### Nan::RunScript()
+
+Calls `script->Run()` or `script->BindToCurrentContext()->Run(Nan::GetCurrentContext())`.
+
+Note that `Nan::BoundScript` is an alias for `v8::Script` and `Nan::UnboundScript` is an alias for `v8::UnboundScript` where available and `v8::Script` on older versions of V8.
+
+Signature:
+
+```c++
+Nan::MaybeLocal<v8::Value> Nan::RunScript(v8::Local<Nan::UnboundScript> script)
+Nan::MaybeLocal<v8::Value> Nan::RunScript(v8::Local<Nan::BoundScript> script)
+```
--- /dev/null
+## Strings & Bytes
+
+Miscellaneous string & byte encoding and decoding functionality provided for compatibility across supported versions of V8 and Node. Implemented by NAN to ensure that all encoding types are supported, even for older versions of Node where they are missing.
+
+ - <a href="#api_nan_encoding"><b><code>Nan::Encoding</code></b></a>
+ - <a href="#api_nan_encode"><b><code>Nan::Encode()</code></b></a>
+ - <a href="#api_nan_decode_bytes"><b><code>Nan::DecodeBytes()</code></b></a>
+ - <a href="#api_nan_decode_write"><b><code>Nan::DecodeWrite()</code></b></a>
+
+
+<a name="api_nan_encoding"></a>
+### Nan::Encoding
+
+An enum representing the supported encoding types. A copy of `node::encoding` that is consistent across versions of Node.
+
+Definition:
+
+```c++
+enum Nan::Encoding { ASCII, UTF8, BASE64, UCS2, BINARY, HEX, BUFFER }
+```
+
+
+<a name="api_nan_encode"></a>
+### Nan::Encode()
+
+A wrapper around `node::Encode()` that provides a consistent implementation across supported versions of Node.
+
+Signature:
+
+```c++
+v8::Local<v8::Value> Nan::Encode(const void *buf,
+ size_t len,
+ enum Nan::Encoding encoding = BINARY);
+```
+
+
+<a name="api_nan_decode_bytes"></a>
+### Nan::DecodeBytes()
+
+A wrapper around `node::DecodeBytes()` that provides a consistent implementation across supported versions of Node.
+
+Signature:
+
+```c++
+ssize_t Nan::DecodeBytes(v8::Local<v8::Value> val,
+ enum Nan::Encoding encoding = BINARY);
+```
+
+
+<a name="api_nan_decode_write"></a>
+### Nan::DecodeWrite()
+
+A wrapper around `node::DecodeWrite()` that provides a consistent implementation across supported versions of Node.
+
+Signature:
+
+```c++
+ssize_t Nan::DecodeWrite(char *buf,
+ size_t len,
+ v8::Local<v8::Value> val,
+ enum Nan::Encoding encoding = BINARY);
+```
--- /dev/null
+## V8 internals
+
+The hooks to access V8 internals—including GC and statistics—are different across the supported versions of V8, therefore NAN provides its own hooks that call the appropriate V8 methods.
+
+ - <a href="#api_nan_gc_callback"><b><code>NAN_GC_CALLBACK()</code></b></a>
+ - <a href="#api_nan_add_gc_epilogue_callback"><b><code>Nan::AddGCEpilogueCallback()</code></b></a>
+ - <a href="#api_nan_remove_gc_epilogue_callback"><b><code>Nan::RemoveGCEpilogueCallback()</code></b></a>
+ - <a href="#api_nan_add_gc_prologue_callback"><b><code>Nan::AddGCPrologueCallback()</code></b></a>
+ - <a href="#api_nan_remove_gc_prologue_callback"><b><code>Nan::RemoveGCPrologueCallback()</code></b></a>
+ - <a href="#api_nan_get_heap_statistics"><b><code>Nan::GetHeapStatistics()</code></b></a>
+ - <a href="#api_nan_set_counter_function"><b><code>Nan::SetCounterFunction()</code></b></a>
+ - <a href="#api_nan_set_create_histogram_function"><b><code>Nan::SetCreateHistogramFunction()</code></b></a>
+ - <a href="#api_nan_set_add_histogram_sample_function"><b><code>Nan::SetAddHistogramSampleFunction()</code></b></a>
+ - <a href="#api_nan_idle_notification"><b><code>Nan::IdleNotification()</code></b></a>
+ - <a href="#api_nan_low_memory_notification"><b><code>Nan::LowMemoryNotification()</code></b></a>
+ - <a href="#api_nan_context_disposed_notification"><b><code>Nan::ContextDisposedNotification()</code></b></a>
+ - <a href="#api_nan_get_internal_field_pointer"><b><code>Nan::GetInternalFieldPointer()</code></b></a>
+ - <a href="#api_nan_set_internal_field_pointer"><b><code>Nan::SetInternalFieldPointer()</code></b></a>
+ - <a href="#api_nan_adjust_external_memory"><b><code>Nan::AdjustExternalMemory()</code></b></a>
+
+
+<a name="api_nan_gc_callback"></a>
+### NAN_GC_CALLBACK(callbackname)
+
+Use `NAN_GC_CALLBACK` to declare your callbacks for `Nan::AddGCPrologueCallback()` and `Nan::AddGCEpilogueCallback()`. Your new method receives the arguments `v8::GCType type` and `v8::GCCallbackFlags flags`.
+
+```c++
+static Nan::Persistent<Function> callback;
+
+NAN_GC_CALLBACK(gcPrologueCallback) {
+ v8::Local<Value> argv[] = { Nan::New("prologue").ToLocalChecked() };
+ Nan::MakeCallback(Nan::GetCurrentContext()->Global(), Nan::New(callback), 1, argv);
+}
+
+NAN_METHOD(Hook) {
+ callback.Reset(To<Function>(args[0]).ToLocalChecked());
+ Nan::AddGCPrologueCallback(gcPrologueCallback);
+ info.GetReturnValue().Set(info.Holder());
+}
+```
+
+<a name="api_nan_add_gc_epilogue_callback"></a>
+### Nan::AddGCEpilogueCallback()
+
+Signature:
+
+```c++
+void Nan::AddGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback, v8::GCType gc_type_filter = v8::kGCTypeAll)
+```
+
+Calls V8's [`AddGCEpilogueCallback()`](https://v8docs.nodesource.com/node-8.11/d5/dda/classv8_1_1_isolate.html#a580f976e4290cead62c2fc4dd396be3e).
+
+<a name="api_nan_remove_gc_epilogue_callback"></a>
+### Nan::RemoveGCEpilogueCallback()
+
+Signature:
+
+```c++
+void Nan::RemoveGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback)
+```
+
+Calls V8's [`RemoveGCEpilogueCallback()`](https://v8docs.nodesource.com/node-8.11/d5/dda/classv8_1_1_isolate.html#adca9294555a3908e9f23c7bb0f0f284c).
+
+<a name="api_nan_add_gc_prologue_callback"></a>
+### Nan::AddGCPrologueCallback()
+
+Signature:
+
+```c++
+void Nan::AddGCPrologueCallback(v8::Isolate::GCPrologueCallback, v8::GCType gc_type_filter callback)
+```
+
+Calls V8's [`AddGCPrologueCallback()`](https://v8docs.nodesource.com/node-8.11/d5/dda/classv8_1_1_isolate.html#a6dbef303603ebdb03da6998794ea05b8).
+
+<a name="api_nan_remove_gc_prologue_callback"></a>
+### Nan::RemoveGCPrologueCallback()
+
+Signature:
+
+```c++
+void Nan::RemoveGCPrologueCallback(v8::Isolate::GCPrologueCallback callback)
+```
+
+Calls V8's [`RemoveGCPrologueCallback()`](https://v8docs.nodesource.com/node-8.11/d5/dda/classv8_1_1_isolate.html#a5f72c7cda21415ce062bbe5c58abe09e).
+
+<a name="api_nan_get_heap_statistics"></a>
+### Nan::GetHeapStatistics()
+
+Signature:
+
+```c++
+void Nan::GetHeapStatistics(v8::HeapStatistics *heap_statistics)
+```
+
+Calls V8's [`GetHeapStatistics()`](https://v8docs.nodesource.com/node-8.11/d5/dda/classv8_1_1_isolate.html#a5593ac74687b713095c38987e5950b34).
+
+<a name="api_nan_set_counter_function"></a>
+### Nan::SetCounterFunction()
+
+Signature:
+
+```c++
+void Nan::SetCounterFunction(v8::CounterLookupCallback cb)
+```
+
+Calls V8's [`SetCounterFunction()`](https://v8docs.nodesource.com/node-8.11/d5/dda/classv8_1_1_isolate.html#a045d7754e62fa0ec72ae6c259b29af94).
+
+<a name="api_nan_set_create_histogram_function"></a>
+### Nan::SetCreateHistogramFunction()
+
+Signature:
+
+```c++
+void Nan::SetCreateHistogramFunction(v8::CreateHistogramCallback cb)
+```
+
+Calls V8's [`SetCreateHistogramFunction()`](https://v8docs.nodesource.com/node-8.11/d5/dda/classv8_1_1_isolate.html#a542d67e85089cb3f92aadf032f99e732).
+
+<a name="api_nan_set_add_histogram_sample_function"></a>
+### Nan::SetAddHistogramSampleFunction()
+
+Signature:
+
+```c++
+void Nan::SetAddHistogramSampleFunction(v8::AddHistogramSampleCallback cb)
+```
+
+Calls V8's [`SetAddHistogramSampleFunction()`](https://v8docs.nodesource.com/node-8.11/d5/dda/classv8_1_1_isolate.html#aeb420b690bc2c216882d6fdd00ddd3ea).
+
+<a name="api_nan_idle_notification"></a>
+### Nan::IdleNotification()
+
+Signature:
+
+```c++
+bool Nan::IdleNotification(int idle_time_in_ms)
+```
+
+Calls V8's [`IdleNotification()` or `IdleNotificationDeadline()`](https://v8docs.nodesource.com/node-8.11/d5/dda/classv8_1_1_isolate.html#ad6a2a02657f5425ad460060652a5a118) depending on V8 version.
+
+<a name="api_nan_low_memory_notification"></a>
+### Nan::LowMemoryNotification()
+
+Signature:
+
+```c++
+void Nan::LowMemoryNotification()
+```
+
+Calls V8's [`LowMemoryNotification()`](https://v8docs.nodesource.com/node-8.11/d5/dda/classv8_1_1_isolate.html#a24647f61d6b41f69668094bdcd6ea91f).
+
+<a name="api_nan_context_disposed_notification"></a>
+### Nan::ContextDisposedNotification()
+
+Signature:
+
+```c++
+void Nan::ContextDisposedNotification()
+```
+
+Calls V8's [`ContextDisposedNotification()`](https://v8docs.nodesource.com/node-8.11/d5/dda/classv8_1_1_isolate.html#ad7f5dc559866343fe6cd8db1f134d48b).
+
+<a name="api_nan_get_internal_field_pointer"></a>
+### Nan::GetInternalFieldPointer()
+
+Gets a pointer to the internal field with at `index` from a V8 `Object` handle.
+
+Signature:
+
+```c++
+void* Nan::GetInternalFieldPointer(v8::Local<v8::Object> object, int index)
+```
+
+Calls the Object's [`GetAlignedPointerFromInternalField()` or `GetPointerFromInternalField()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#a580ea84afb26c005d6762eeb9e3c308f) depending on the version of V8.
+
+<a name="api_nan_set_internal_field_pointer"></a>
+### Nan::SetInternalFieldPointer()
+
+Sets the value of the internal field at `index` on a V8 `Object` handle.
+
+Signature:
+
+```c++
+void Nan::SetInternalFieldPointer(v8::Local<v8::Object> object, int index, void* value)
+```
+
+Calls the Object's [`SetAlignedPointerInInternalField()` or `SetPointerInInternalField()`](https://v8docs.nodesource.com/node-8.11/db/d85/classv8_1_1_object.html#ab3c57184263cf29963ef0017bec82281) depending on the version of V8.
+
+<a name="api_nan_adjust_external_memory"></a>
+### Nan::AdjustExternalMemory()
+
+Signature:
+
+```c++
+int Nan::AdjustExternalMemory(int bytesChange)
+```
+
+Calls V8's [`AdjustAmountOfExternalAllocatedMemory()`](https://v8docs.nodesource.com/node-8.11/d5/dda/classv8_1_1_isolate.html#ae1a59cac60409d3922582c4af675473e).
+
--- /dev/null
+## Miscellaneous V8 Helpers
+
+ - <a href="#api_nan_utf8_string"><b><code>Nan::Utf8String</code></b></a>
+ - <a href="#api_nan_get_current_context"><b><code>Nan::GetCurrentContext()</code></b></a>
+ - <a href="#api_nan_set_isolate_data"><b><code>Nan::SetIsolateData()</code></b></a>
+ - <a href="#api_nan_get_isolate_data"><b><code>Nan::GetIsolateData()</code></b></a>
+ - <a href="#api_nan_typedarray_contents"><b><code>Nan::TypedArrayContents</code></b></a>
+
+
+<a name="api_nan_utf8_string"></a>
+### Nan::Utf8String
+
+Converts an object to a UTF-8-encoded character array. If conversion to a string fails (e.g. due to an exception in the toString() method of the object) then the length() method returns 0 and the * operator returns NULL. The underlying memory used for this object is managed by the object.
+
+An implementation of [`v8::String::Utf8Value`](https://v8docs.nodesource.com/node-8.11/d4/d1b/classv8_1_1_string_1_1_utf8_value.html) that is consistent across all supported versions of V8.
+
+Definition:
+
+```c++
+class Nan::Utf8String {
+ public:
+ Nan::Utf8String(v8::Local<v8::Value> from);
+
+ int length() const;
+
+ char* operator*();
+ const char* operator*() const;
+};
+```
+
+<a name="api_nan_get_current_context"></a>
+### Nan::GetCurrentContext()
+
+A call to [`v8::Isolate::GetCurrent()->GetCurrentContext()`](https://v8docs.nodesource.com/node-8.11/d5/dda/classv8_1_1_isolate.html#a81c7a1ed7001ae2a65e89107f75fd053) that works across all supported versions of V8.
+
+Signature:
+
+```c++
+v8::Local<v8::Context> Nan::GetCurrentContext()
+```
+
+<a name="api_nan_set_isolate_data"></a>
+### Nan::SetIsolateData()
+
+A helper to provide a consistent API to [`v8::Isolate#SetData()`](https://v8docs.nodesource.com/node-8.11/d5/dda/classv8_1_1_isolate.html#a7acadfe7965997e9c386a05f098fbe36).
+
+Signature:
+
+```c++
+void Nan::SetIsolateData(v8::Isolate *isolate, T *data)
+```
+
+
+<a name="api_nan_get_isolate_data"></a>
+### Nan::GetIsolateData()
+
+A helper to provide a consistent API to [`v8::Isolate#GetData()`](https://v8docs.nodesource.com/node-8.11/d5/dda/classv8_1_1_isolate.html#aabd223436bc1100a787dadaa024c6257).
+
+Signature:
+
+```c++
+T *Nan::GetIsolateData(v8::Isolate *isolate)
+```
+
+<a name="api_nan_typedarray_contents"></a>
+### Nan::TypedArrayContents<T>
+
+A helper class for accessing the contents of an ArrayBufferView (aka a typedarray) from C++. If the input array is not a valid typedarray, then the data pointer of TypedArrayContents will default to `NULL` and the length will be 0. If the data pointer is not compatible with the alignment requirements of type, an assertion error will fail.
+
+Note that you must store a reference to the `array` object while you are accessing its contents.
+
+Definition:
+
+```c++
+template<typename T>
+class Nan::TypedArrayContents {
+ public:
+ TypedArrayContents(v8::Local<Value> array);
+
+ size_t length() const;
+
+ T* const operator*();
+ const T* const operator*() const;
+};
+```
--- /dev/null
+console.log(require('path').relative('.', __dirname));
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors:
+ * - Rod Vagg <https://github.com/rvagg>
+ * - Benjamin Byholm <https://github.com/kkoopa>
+ * - Trevor Norris <https://github.com/trevnorris>
+ * - Nathan Rajlich <https://github.com/TooTallNate>
+ * - Brett Lawson <https://github.com/brett19>
+ * - Ben Noordhuis <https://github.com/bnoordhuis>
+ * - David Siegel <https://github.com/agnat>
+ * - Michael Ira Krufky <https://github.com/mkrufky>
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ *
+ * Version 2.14.0: current Node 12.2.0, Node 12: 0.12.18, Node 10: 0.10.48, iojs: 3.3.1
+ *
+ * See https://github.com/nodejs/nan for the latest update to this file
+ **********************************************************************************/
+
+#ifndef NAN_H_
+#define NAN_H_
+
+#include <node_version.h>
+
+#define NODE_0_10_MODULE_VERSION 11
+#define NODE_0_12_MODULE_VERSION 14
+#define ATOM_0_21_MODULE_VERSION 41
+#define IOJS_1_0_MODULE_VERSION 42
+#define IOJS_1_1_MODULE_VERSION 43
+#define IOJS_2_0_MODULE_VERSION 44
+#define IOJS_3_0_MODULE_VERSION 45
+#define NODE_4_0_MODULE_VERSION 46
+#define NODE_5_0_MODULE_VERSION 47
+#define NODE_6_0_MODULE_VERSION 48
+#define NODE_7_0_MODULE_VERSION 51
+#define NODE_8_0_MODULE_VERSION 57
+#define NODE_9_0_MODULE_VERSION 59
+#define NODE_10_0_MODULE_VERSION 64
+#define NODE_11_0_MODULE_VERSION 67
+#define NODE_12_0_MODULE_VERSION 72
+
+#ifdef _MSC_VER
+# define NAN_HAS_CPLUSPLUS_11 (_MSC_VER >= 1800)
+#else
+# define NAN_HAS_CPLUSPLUS_11 (__cplusplus >= 201103L)
+#endif
+
+#if NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION && !NAN_HAS_CPLUSPLUS_11
+# error This version of node/NAN/v8 requires a C++11 compiler
+#endif
+
+#include <uv.h>
+#include <node.h>
+#include <node_buffer.h>
+#include <node_object_wrap.h>
+#include <algorithm>
+#include <cstring>
+#include <climits>
+#include <cstdlib>
+#include <utility>
+#if defined(_MSC_VER)
+# pragma warning( push )
+# pragma warning( disable : 4530 )
+# include <queue>
+# include <string>
+# include <vector>
+# pragma warning( pop )
+#else
+# include <queue>
+# include <string>
+# include <vector>
+#endif
+
+// uv helpers
+#ifdef UV_VERSION_MAJOR
+# ifndef UV_VERSION_PATCH
+# define UV_VERSION_PATCH 0
+# endif
+# define NAUV_UVVERSION ((UV_VERSION_MAJOR << 16) | \
+ (UV_VERSION_MINOR << 8) | \
+ (UV_VERSION_PATCH))
+#else
+# define NAUV_UVVERSION 0x000b00
+#endif
+
+#if NAUV_UVVERSION < 0x000b0b
+# ifdef WIN32
+# include <windows.h>
+# else
+# include <pthread.h>
+# endif
+#endif
+
+namespace Nan {
+
+#define NAN_CONCAT(a, b) NAN_CONCAT_HELPER(a, b)
+#define NAN_CONCAT_HELPER(a, b) a##b
+
+#define NAN_INLINE inline // TODO(bnoordhuis) Remove in v3.0.0.
+
+#if defined(__GNUC__) && \
+ !(defined(V8_DISABLE_DEPRECATIONS) && V8_DISABLE_DEPRECATIONS)
+# define NAN_DEPRECATED __attribute__((deprecated))
+#elif defined(_MSC_VER) && \
+ !(defined(V8_DISABLE_DEPRECATIONS) && V8_DISABLE_DEPRECATIONS)
+# define NAN_DEPRECATED __declspec(deprecated)
+#else
+# define NAN_DEPRECATED
+#endif
+
+#if NAN_HAS_CPLUSPLUS_11
+# define NAN_DISALLOW_ASSIGN(CLASS) void operator=(const CLASS&) = delete;
+# define NAN_DISALLOW_COPY(CLASS) CLASS(const CLASS&) = delete;
+# define NAN_DISALLOW_MOVE(CLASS) \
+ CLASS(CLASS&&) = delete; /* NOLINT(build/c++11) */ \
+ void operator=(CLASS&&) = delete;
+#else
+# define NAN_DISALLOW_ASSIGN(CLASS) void operator=(const CLASS&);
+# define NAN_DISALLOW_COPY(CLASS) CLASS(const CLASS&);
+# define NAN_DISALLOW_MOVE(CLASS)
+#endif
+
+#define NAN_DISALLOW_ASSIGN_COPY(CLASS) \
+ NAN_DISALLOW_ASSIGN(CLASS) \
+ NAN_DISALLOW_COPY(CLASS)
+
+#define NAN_DISALLOW_ASSIGN_MOVE(CLASS) \
+ NAN_DISALLOW_ASSIGN(CLASS) \
+ NAN_DISALLOW_MOVE(CLASS)
+
+#define NAN_DISALLOW_COPY_MOVE(CLASS) \
+ NAN_DISALLOW_COPY(CLASS) \
+ NAN_DISALLOW_MOVE(CLASS)
+
+#define NAN_DISALLOW_ASSIGN_COPY_MOVE(CLASS) \
+ NAN_DISALLOW_ASSIGN(CLASS) \
+ NAN_DISALLOW_COPY(CLASS) \
+ NAN_DISALLOW_MOVE(CLASS)
+
+#define TYPE_CHECK(T, S) \
+ while (false) { \
+ *(static_cast<T *volatile *>(0)) = static_cast<S*>(0); \
+ }
+
+//=== RegistrationFunction =====================================================
+
+#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+ typedef v8::Handle<v8::Object> ADDON_REGISTER_FUNCTION_ARGS_TYPE;
+#else
+ typedef v8::Local<v8::Object> ADDON_REGISTER_FUNCTION_ARGS_TYPE;
+#endif
+
+#define NAN_MODULE_INIT(name) \
+ void name(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target)
+
+#if NODE_MAJOR_VERSION >= 10 || \
+ NODE_MAJOR_VERSION == 9 && NODE_MINOR_VERSION >= 3
+#define NAN_MODULE_WORKER_ENABLED(module_name, registration) \
+ extern "C" NODE_MODULE_EXPORT void \
+ NAN_CONCAT(node_register_module_v, NODE_MODULE_VERSION)( \
+ v8::Local<v8::Object> exports, v8::Local<v8::Value> module, \
+ v8::Local<v8::Context> context) \
+ { \
+ registration(exports); \
+ }
+#else
+#define NAN_MODULE_WORKER_ENABLED(module_name, registration) \
+ NODE_MODULE(module_name, registration)
+#endif
+
+//=== CallbackInfo =============================================================
+
+#include "nan_callbacks.h" // NOLINT(build/include)
+
+//==============================================================================
+
+#if (NODE_MODULE_VERSION < NODE_0_12_MODULE_VERSION)
+typedef v8::Script UnboundScript;
+typedef v8::Script BoundScript;
+#else
+typedef v8::UnboundScript UnboundScript;
+typedef v8::Script BoundScript;
+#endif
+
+#if (NODE_MODULE_VERSION < ATOM_0_21_MODULE_VERSION)
+typedef v8::String::ExternalAsciiStringResource
+ ExternalOneByteStringResource;
+#else
+typedef v8::String::ExternalOneByteStringResource
+ ExternalOneByteStringResource;
+#endif
+
+#if (NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION)
+template<typename T>
+class NonCopyablePersistentTraits :
+ public v8::NonCopyablePersistentTraits<T> {};
+template<typename T>
+class CopyablePersistentTraits :
+ public v8::CopyablePersistentTraits<T> {};
+
+template<typename T>
+class PersistentBase :
+ public v8::PersistentBase<T> {};
+
+template<typename T, typename M = v8::NonCopyablePersistentTraits<T> >
+class Persistent;
+#else
+template<typename T> class NonCopyablePersistentTraits;
+template<typename T> class PersistentBase;
+template<typename T, typename P> class WeakCallbackData;
+template<typename T, typename M = NonCopyablePersistentTraits<T> >
+class Persistent;
+#endif // NODE_MODULE_VERSION
+
+template<typename T>
+class Maybe {
+ public:
+ inline bool IsNothing() const { return !has_value_; }
+ inline bool IsJust() const { return has_value_; }
+
+ inline T ToChecked() const { return FromJust(); }
+ inline void Check() const { FromJust(); }
+
+ inline bool To(T* out) const {
+ if (IsJust()) *out = value_;
+ return IsJust();
+ }
+
+ inline T FromJust() const {
+#if defined(V8_ENABLE_CHECKS)
+ assert(IsJust() && "FromJust is Nothing");
+#endif // V8_ENABLE_CHECKS
+ return value_;
+ }
+
+ inline T FromMaybe(const T& default_value) const {
+ return has_value_ ? value_ : default_value;
+ }
+
+ inline bool operator==(const Maybe &other) const {
+ return (IsJust() == other.IsJust()) &&
+ (!IsJust() || FromJust() == other.FromJust());
+ }
+
+ inline bool operator!=(const Maybe &other) const {
+ return !operator==(other);
+ }
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+ // Allow implicit conversions from v8::Maybe<T> to Nan::Maybe<T>.
+ Maybe(const v8::Maybe<T>& that) // NOLINT(runtime/explicit)
+ : has_value_(that.IsJust())
+ , value_(that.FromMaybe(T())) {}
+#endif
+
+ private:
+ Maybe() : has_value_(false) {}
+ explicit Maybe(const T& t) : has_value_(true), value_(t) {}
+ bool has_value_;
+ T value_;
+
+ template<typename U>
+ friend Maybe<U> Nothing();
+ template<typename U>
+ friend Maybe<U> Just(const U& u);
+};
+
+template<typename T>
+inline Maybe<T> Nothing() {
+ return Maybe<T>();
+}
+
+template<typename T>
+inline Maybe<T> Just(const T& t) {
+ return Maybe<T>(t);
+}
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+# include "nan_maybe_43_inl.h" // NOLINT(build/include)
+#else
+# include "nan_maybe_pre_43_inl.h" // NOLINT(build/include)
+#endif
+
+#include "nan_converters.h" // NOLINT(build/include)
+#include "nan_new.h" // NOLINT(build/include)
+
+#if NAUV_UVVERSION < 0x000b17
+#define NAUV_WORK_CB(func) \
+ void func(uv_async_t *async, int)
+#else
+#define NAUV_WORK_CB(func) \
+ void func(uv_async_t *async)
+#endif
+
+#if NAUV_UVVERSION >= 0x000b0b
+
+typedef uv_key_t nauv_key_t;
+
+inline int nauv_key_create(nauv_key_t *key) {
+ return uv_key_create(key);
+}
+
+inline void nauv_key_delete(nauv_key_t *key) {
+ uv_key_delete(key);
+}
+
+inline void* nauv_key_get(nauv_key_t *key) {
+ return uv_key_get(key);
+}
+
+inline void nauv_key_set(nauv_key_t *key, void *value) {
+ uv_key_set(key, value);
+}
+
+#else
+
+/* Implement thread local storage for older versions of libuv.
+ * This is essentially a backport of libuv commit 5d2434bf
+ * written by Ben Noordhuis, adjusted for names and inline.
+ */
+
+#ifndef WIN32
+
+typedef pthread_key_t nauv_key_t;
+
+inline int nauv_key_create(nauv_key_t* key) {
+ return -pthread_key_create(key, NULL);
+}
+
+inline void nauv_key_delete(nauv_key_t* key) {
+ if (pthread_key_delete(*key))
+ abort();
+}
+
+inline void* nauv_key_get(nauv_key_t* key) {
+ return pthread_getspecific(*key);
+}
+
+inline void nauv_key_set(nauv_key_t* key, void* value) {
+ if (pthread_setspecific(*key, value))
+ abort();
+}
+
+#else
+
+typedef struct {
+ DWORD tls_index;
+} nauv_key_t;
+
+inline int nauv_key_create(nauv_key_t* key) {
+ key->tls_index = TlsAlloc();
+ if (key->tls_index == TLS_OUT_OF_INDEXES)
+ return UV_ENOMEM;
+ return 0;
+}
+
+inline void nauv_key_delete(nauv_key_t* key) {
+ if (TlsFree(key->tls_index) == FALSE)
+ abort();
+ key->tls_index = TLS_OUT_OF_INDEXES;
+}
+
+inline void* nauv_key_get(nauv_key_t* key) {
+ void* value = TlsGetValue(key->tls_index);
+ if (value == NULL)
+ if (GetLastError() != ERROR_SUCCESS)
+ abort();
+ return value;
+}
+
+inline void nauv_key_set(nauv_key_t* key, void* value) {
+ if (TlsSetValue(key->tls_index, value) == FALSE)
+ abort();
+}
+
+#endif
+#endif
+
+#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+template<typename T>
+v8::Local<T> New(v8::Handle<T>);
+#endif
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+ typedef v8::WeakCallbackType WeakCallbackType;
+#else
+struct WeakCallbackType {
+ enum E {kParameter, kInternalFields};
+ E type;
+ WeakCallbackType(E other) : type(other) {} // NOLINT(runtime/explicit)
+ inline bool operator==(E other) { return other == this->type; }
+ inline bool operator!=(E other) { return !operator==(other); }
+};
+#endif
+
+template<typename P> class WeakCallbackInfo;
+
+#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+# include "nan_persistent_12_inl.h" // NOLINT(build/include)
+#else
+# include "nan_persistent_pre_12_inl.h" // NOLINT(build/include)
+#endif
+
+namespace imp {
+ static const size_t kMaxLength = 0x3fffffff;
+ // v8::String::REPLACE_INVALID_UTF8 was introduced
+ // in node.js v0.10.29 and v0.8.27.
+#if NODE_MAJOR_VERSION > 0 || \
+ NODE_MINOR_VERSION > 10 || \
+ NODE_MINOR_VERSION == 10 && NODE_PATCH_VERSION >= 29 || \
+ NODE_MINOR_VERSION == 8 && NODE_PATCH_VERSION >= 27
+ static const unsigned kReplaceInvalidUtf8 = v8::String::REPLACE_INVALID_UTF8;
+#else
+ static const unsigned kReplaceInvalidUtf8 = 0;
+#endif
+} // end of namespace imp
+
+//=== HandleScope ==============================================================
+
+class HandleScope {
+ v8::HandleScope scope;
+
+ public:
+#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+ inline HandleScope() : scope(v8::Isolate::GetCurrent()) {}
+ inline static int NumberOfHandles() {
+ return v8::HandleScope::NumberOfHandles(v8::Isolate::GetCurrent());
+ }
+#else
+ inline HandleScope() : scope() {}
+ inline static int NumberOfHandles() {
+ return v8::HandleScope::NumberOfHandles();
+ }
+#endif
+
+ private:
+ // Make it hard to create heap-allocated or illegal handle scopes by
+ // disallowing certain operations.
+ HandleScope(const HandleScope &);
+ void operator=(const HandleScope &);
+ void *operator new(size_t size);
+ void operator delete(void *, size_t) {
+ abort();
+ }
+};
+
+class EscapableHandleScope {
+ public:
+#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+ inline EscapableHandleScope() : scope(v8::Isolate::GetCurrent()) {}
+
+ inline static int NumberOfHandles() {
+ return v8::EscapableHandleScope::NumberOfHandles(v8::Isolate::GetCurrent());
+ }
+
+ template<typename T>
+ inline v8::Local<T> Escape(v8::Local<T> value) {
+ return scope.Escape(value);
+ }
+
+ private:
+ v8::EscapableHandleScope scope;
+#else
+ inline EscapableHandleScope() : scope() {}
+
+ inline static int NumberOfHandles() {
+ return v8::HandleScope::NumberOfHandles();
+ }
+
+ template<typename T>
+ inline v8::Local<T> Escape(v8::Local<T> value) {
+ return scope.Close(value);
+ }
+
+ private:
+ v8::HandleScope scope;
+#endif
+
+ private:
+ // Make it hard to create heap-allocated or illegal handle scopes by
+ // disallowing certain operations.
+ EscapableHandleScope(const EscapableHandleScope &);
+ void operator=(const EscapableHandleScope &);
+ void *operator new(size_t size);
+ void operator delete(void *, size_t) {
+ abort();
+ }
+};
+
+//=== TryCatch =================================================================
+
+class TryCatch {
+ v8::TryCatch try_catch_;
+ friend void FatalException(const TryCatch&);
+
+ public:
+#if NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION
+ TryCatch() : try_catch_(v8::Isolate::GetCurrent()) {}
+#endif
+
+ inline bool HasCaught() const { return try_catch_.HasCaught(); }
+
+ inline bool CanContinue() const { return try_catch_.CanContinue(); }
+
+ inline v8::Local<v8::Value> ReThrow() {
+#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+ return New(try_catch_.ReThrow());
+#else
+ return try_catch_.ReThrow();
+#endif
+ }
+
+ inline v8::Local<v8::Value> Exception() const {
+ return try_catch_.Exception();
+ }
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+ inline v8::MaybeLocal<v8::Value> StackTrace() const {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(try_catch_.StackTrace(isolate->GetCurrentContext())
+ .FromMaybe(v8::Local<v8::Value>()));
+ }
+#else
+ inline MaybeLocal<v8::Value> StackTrace() const {
+ return try_catch_.StackTrace();
+ }
+#endif
+
+ inline v8::Local<v8::Message> Message() const {
+ return try_catch_.Message();
+ }
+
+ inline void Reset() { try_catch_.Reset(); }
+
+ inline void SetVerbose(bool value) { try_catch_.SetVerbose(value); }
+
+ inline void SetCaptureMessage(bool value) {
+ try_catch_.SetCaptureMessage(value);
+ }
+};
+
+v8::Local<v8::Value> MakeCallback(v8::Local<v8::Object> target,
+ v8::Local<v8::Function> func,
+ int argc,
+ v8::Local<v8::Value>* argv);
+v8::Local<v8::Value> MakeCallback(v8::Local<v8::Object> target,
+ v8::Local<v8::String> symbol,
+ int argc,
+ v8::Local<v8::Value>* argv);
+v8::Local<v8::Value> MakeCallback(v8::Local<v8::Object> target,
+ const char* method,
+ int argc,
+ v8::Local<v8::Value>* argv);
+
+// === AsyncResource ===========================================================
+
+class AsyncResource {
+ public:
+ AsyncResource(
+ v8::Local<v8::String> name
+ , v8::Local<v8::Object> resource = New<v8::Object>()) {
+#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+
+ if (resource.IsEmpty()) {
+ resource = New<v8::Object>();
+ }
+
+ context = node::EmitAsyncInit(isolate, resource, name);
+#endif
+ }
+
+ AsyncResource(
+ const char* name
+ , v8::Local<v8::Object> resource = New<v8::Object>()) {
+#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+
+ if (resource.IsEmpty()) {
+ resource = New<v8::Object>();
+ }
+
+ v8::Local<v8::String> name_string =
+ New<v8::String>(name).ToLocalChecked();
+ context = node::EmitAsyncInit(isolate, resource, name_string);
+#endif
+ }
+
+ ~AsyncResource() {
+#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ node::EmitAsyncDestroy(isolate, context);
+#endif
+ }
+
+ inline MaybeLocal<v8::Value> runInAsyncScope(
+ v8::Local<v8::Object> target
+ , v8::Local<v8::Function> func
+ , int argc
+ , v8::Local<v8::Value>* argv) {
+#if NODE_MODULE_VERSION < NODE_9_0_MODULE_VERSION
+ return MakeCallback(target, func, argc, argv);
+#else
+ return node::MakeCallback(
+ v8::Isolate::GetCurrent(), target, func, argc, argv, context);
+#endif
+ }
+
+ inline MaybeLocal<v8::Value> runInAsyncScope(
+ v8::Local<v8::Object> target
+ , v8::Local<v8::String> symbol
+ , int argc
+ , v8::Local<v8::Value>* argv) {
+#if NODE_MODULE_VERSION < NODE_9_0_MODULE_VERSION
+ return MakeCallback(target, symbol, argc, argv);
+#else
+ return node::MakeCallback(
+ v8::Isolate::GetCurrent(), target, symbol, argc, argv, context);
+#endif
+ }
+
+ inline MaybeLocal<v8::Value> runInAsyncScope(
+ v8::Local<v8::Object> target
+ , const char* method
+ , int argc
+ , v8::Local<v8::Value>* argv) {
+#if NODE_MODULE_VERSION < NODE_9_0_MODULE_VERSION
+ return MakeCallback(target, method, argc, argv);
+#else
+ return node::MakeCallback(
+ v8::Isolate::GetCurrent(), target, method, argc, argv, context);
+#endif
+ }
+
+ private:
+ NAN_DISALLOW_ASSIGN_COPY_MOVE(AsyncResource)
+#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+ node::async_context context;
+#endif
+};
+
+inline uv_loop_t* GetCurrentEventLoop() {
+#if NODE_MAJOR_VERSION >= 10 || \
+ NODE_MAJOR_VERSION == 9 && NODE_MINOR_VERSION >= 3 || \
+ NODE_MAJOR_VERSION == 8 && NODE_MINOR_VERSION >= 10
+ return node::GetCurrentEventLoop(v8::Isolate::GetCurrent());
+#else
+ return uv_default_loop();
+#endif
+}
+
+//============ =================================================================
+
+/* node 0.12 */
+#if NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION
+ inline
+ void SetCounterFunction(v8::CounterLookupCallback cb) {
+ v8::Isolate::GetCurrent()->SetCounterFunction(cb);
+ }
+
+ inline
+ void SetCreateHistogramFunction(v8::CreateHistogramCallback cb) {
+ v8::Isolate::GetCurrent()->SetCreateHistogramFunction(cb);
+ }
+
+ inline
+ void SetAddHistogramSampleFunction(v8::AddHistogramSampleCallback cb) {
+ v8::Isolate::GetCurrent()->SetAddHistogramSampleFunction(cb);
+ }
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+ inline bool IdleNotification(int idle_time_in_ms) {
+ return v8::Isolate::GetCurrent()->IdleNotificationDeadline(
+ idle_time_in_ms * 0.001);
+ }
+# else
+ inline bool IdleNotification(int idle_time_in_ms) {
+ return v8::Isolate::GetCurrent()->IdleNotification(idle_time_in_ms);
+ }
+#endif
+
+ inline void LowMemoryNotification() {
+ v8::Isolate::GetCurrent()->LowMemoryNotification();
+ }
+
+ inline void ContextDisposedNotification() {
+ v8::Isolate::GetCurrent()->ContextDisposedNotification();
+ }
+#else
+ inline
+ void SetCounterFunction(v8::CounterLookupCallback cb) {
+ v8::V8::SetCounterFunction(cb);
+ }
+
+ inline
+ void SetCreateHistogramFunction(v8::CreateHistogramCallback cb) {
+ v8::V8::SetCreateHistogramFunction(cb);
+ }
+
+ inline
+ void SetAddHistogramSampleFunction(v8::AddHistogramSampleCallback cb) {
+ v8::V8::SetAddHistogramSampleFunction(cb);
+ }
+
+ inline bool IdleNotification(int idle_time_in_ms) {
+ return v8::V8::IdleNotification(idle_time_in_ms);
+ }
+
+ inline void LowMemoryNotification() {
+ v8::V8::LowMemoryNotification();
+ }
+
+ inline void ContextDisposedNotification() {
+ v8::V8::ContextDisposedNotification();
+ }
+#endif
+
+#if (NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION) // Node 0.12
+ inline v8::Local<v8::Primitive> Undefined() {
+# if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+ EscapableHandleScope scope;
+ return scope.Escape(New(v8::Undefined(v8::Isolate::GetCurrent())));
+# else
+ return v8::Undefined(v8::Isolate::GetCurrent());
+# endif
+ }
+
+ inline v8::Local<v8::Primitive> Null() {
+# if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+ EscapableHandleScope scope;
+ return scope.Escape(New(v8::Null(v8::Isolate::GetCurrent())));
+# else
+ return v8::Null(v8::Isolate::GetCurrent());
+# endif
+ }
+
+ inline v8::Local<v8::Boolean> True() {
+# if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+ EscapableHandleScope scope;
+ return scope.Escape(New(v8::True(v8::Isolate::GetCurrent())));
+# else
+ return v8::True(v8::Isolate::GetCurrent());
+# endif
+ }
+
+ inline v8::Local<v8::Boolean> False() {
+# if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+ EscapableHandleScope scope;
+ return scope.Escape(New(v8::False(v8::Isolate::GetCurrent())));
+# else
+ return v8::False(v8::Isolate::GetCurrent());
+# endif
+ }
+
+ inline v8::Local<v8::String> EmptyString() {
+ return v8::String::Empty(v8::Isolate::GetCurrent());
+ }
+
+ inline int AdjustExternalMemory(int bc) {
+ return static_cast<int>(
+ v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(bc));
+ }
+
+ inline void SetTemplate(
+ v8::Local<v8::Template> templ
+ , const char *name
+ , v8::Local<v8::Data> value) {
+ templ->Set(v8::Isolate::GetCurrent(), name, value);
+ }
+
+ inline void SetTemplate(
+ v8::Local<v8::Template> templ
+ , v8::Local<v8::String> name
+ , v8::Local<v8::Data> value
+ , v8::PropertyAttribute attributes) {
+ templ->Set(name, value, attributes);
+ }
+
+ inline v8::Local<v8::Context> GetCurrentContext() {
+ return v8::Isolate::GetCurrent()->GetCurrentContext();
+ }
+
+ inline void* GetInternalFieldPointer(
+ v8::Local<v8::Object> object
+ , int index) {
+ return object->GetAlignedPointerFromInternalField(index);
+ }
+
+ inline void SetInternalFieldPointer(
+ v8::Local<v8::Object> object
+ , int index
+ , void* value) {
+ object->SetAlignedPointerInInternalField(index, value);
+ }
+
+# define NAN_GC_CALLBACK(name) \
+ void name(v8::Isolate *isolate, v8::GCType type, v8::GCCallbackFlags flags)
+
+#if NODE_MODULE_VERSION <= NODE_4_0_MODULE_VERSION
+ typedef v8::Isolate::GCEpilogueCallback GCEpilogueCallback;
+ typedef v8::Isolate::GCPrologueCallback GCPrologueCallback;
+#else
+ typedef v8::Isolate::GCCallback GCEpilogueCallback;
+ typedef v8::Isolate::GCCallback GCPrologueCallback;
+#endif
+
+ inline void AddGCEpilogueCallback(
+ GCEpilogueCallback callback
+ , v8::GCType gc_type_filter = v8::kGCTypeAll) {
+ v8::Isolate::GetCurrent()->AddGCEpilogueCallback(callback, gc_type_filter);
+ }
+
+ inline void RemoveGCEpilogueCallback(
+ GCEpilogueCallback callback) {
+ v8::Isolate::GetCurrent()->RemoveGCEpilogueCallback(callback);
+ }
+
+ inline void AddGCPrologueCallback(
+ GCPrologueCallback callback
+ , v8::GCType gc_type_filter = v8::kGCTypeAll) {
+ v8::Isolate::GetCurrent()->AddGCPrologueCallback(callback, gc_type_filter);
+ }
+
+ inline void RemoveGCPrologueCallback(
+ GCPrologueCallback callback) {
+ v8::Isolate::GetCurrent()->RemoveGCPrologueCallback(callback);
+ }
+
+ inline void GetHeapStatistics(
+ v8::HeapStatistics *heap_statistics) {
+ v8::Isolate::GetCurrent()->GetHeapStatistics(heap_statistics);
+ }
+
+# define X(NAME) \
+ inline v8::Local<v8::Value> NAME(const char *msg) { \
+ EscapableHandleScope scope; \
+ return scope.Escape(v8::Exception::NAME(New(msg).ToLocalChecked())); \
+ } \
+ \
+ inline \
+ v8::Local<v8::Value> NAME(v8::Local<v8::String> msg) { \
+ return v8::Exception::NAME(msg); \
+ } \
+ \
+ inline void Throw ## NAME(const char *msg) { \
+ HandleScope scope; \
+ v8::Isolate::GetCurrent()->ThrowException( \
+ v8::Exception::NAME(New(msg).ToLocalChecked())); \
+ } \
+ \
+ inline void Throw ## NAME(v8::Local<v8::String> msg) { \
+ HandleScope scope; \
+ v8::Isolate::GetCurrent()->ThrowException( \
+ v8::Exception::NAME(msg)); \
+ }
+
+ X(Error)
+ X(RangeError)
+ X(ReferenceError)
+ X(SyntaxError)
+ X(TypeError)
+
+# undef X
+
+ inline void ThrowError(v8::Local<v8::Value> error) {
+ v8::Isolate::GetCurrent()->ThrowException(error);
+ }
+
+ inline MaybeLocal<v8::Object> NewBuffer(
+ char *data
+ , size_t length
+#if NODE_MODULE_VERSION > IOJS_2_0_MODULE_VERSION
+ , node::Buffer::FreeCallback callback
+#else
+ , node::smalloc::FreeCallback callback
+#endif
+ , void *hint
+ ) {
+ // arbitrary buffer lengths requires
+ // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION
+ assert(length <= imp::kMaxLength && "too large buffer");
+#if NODE_MODULE_VERSION > IOJS_2_0_MODULE_VERSION
+ return node::Buffer::New(
+ v8::Isolate::GetCurrent(), data, length, callback, hint);
+#else
+ return node::Buffer::New(v8::Isolate::GetCurrent(), data, length, callback,
+ hint);
+#endif
+ }
+
+ inline MaybeLocal<v8::Object> CopyBuffer(
+ const char *data
+ , uint32_t size
+ ) {
+ // arbitrary buffer lengths requires
+ // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION
+ assert(size <= imp::kMaxLength && "too large buffer");
+#if NODE_MODULE_VERSION > IOJS_2_0_MODULE_VERSION
+ return node::Buffer::Copy(
+ v8::Isolate::GetCurrent(), data, size);
+#else
+ return node::Buffer::New(v8::Isolate::GetCurrent(), data, size);
+#endif
+ }
+
+ inline MaybeLocal<v8::Object> NewBuffer(uint32_t size) {
+ // arbitrary buffer lengths requires
+ // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION
+ assert(size <= imp::kMaxLength && "too large buffer");
+#if NODE_MODULE_VERSION > IOJS_2_0_MODULE_VERSION
+ return node::Buffer::New(
+ v8::Isolate::GetCurrent(), size);
+#else
+ return node::Buffer::New(v8::Isolate::GetCurrent(), size);
+#endif
+ }
+
+ inline MaybeLocal<v8::Object> NewBuffer(
+ char* data
+ , uint32_t size
+ ) {
+ // arbitrary buffer lengths requires
+ // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION
+ assert(size <= imp::kMaxLength && "too large buffer");
+#if NODE_MODULE_VERSION > IOJS_2_0_MODULE_VERSION
+ return node::Buffer::New(v8::Isolate::GetCurrent(), data, size);
+#else
+ return node::Buffer::Use(v8::Isolate::GetCurrent(), data, size);
+#endif
+ }
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+ inline MaybeLocal<v8::String>
+ NewOneByteString(const uint8_t * value, int length = -1) {
+ return v8::String::NewFromOneByte(v8::Isolate::GetCurrent(), value,
+ v8::NewStringType::kNormal, length);
+ }
+
+ inline MaybeLocal<BoundScript> CompileScript(
+ v8::Local<v8::String> s
+ , const v8::ScriptOrigin& origin
+ ) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ v8::ScriptCompiler::Source source(s, origin);
+ return scope.Escape(
+ v8::ScriptCompiler::Compile(isolate->GetCurrentContext(), &source)
+ .FromMaybe(v8::Local<BoundScript>()));
+ }
+
+ inline MaybeLocal<BoundScript> CompileScript(
+ v8::Local<v8::String> s
+ ) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ v8::ScriptCompiler::Source source(s);
+ return scope.Escape(
+ v8::ScriptCompiler::Compile(isolate->GetCurrentContext(), &source)
+ .FromMaybe(v8::Local<BoundScript>()));
+ }
+
+ inline MaybeLocal<v8::Value> RunScript(
+ v8::Local<UnboundScript> script
+ ) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(script->BindToCurrentContext()
+ ->Run(isolate->GetCurrentContext())
+ .FromMaybe(v8::Local<v8::Value>()));
+ }
+
+ inline MaybeLocal<v8::Value> RunScript(
+ v8::Local<BoundScript> script
+ ) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(script->Run(isolate->GetCurrentContext())
+ .FromMaybe(v8::Local<v8::Value>()));
+ }
+#else
+ inline MaybeLocal<v8::String>
+ NewOneByteString(const uint8_t * value, int length = -1) {
+ return v8::String::NewFromOneByte(v8::Isolate::GetCurrent(), value,
+ v8::String::kNormalString, length);
+ }
+
+ inline MaybeLocal<BoundScript> CompileScript(
+ v8::Local<v8::String> s
+ , const v8::ScriptOrigin& origin
+ ) {
+ v8::ScriptCompiler::Source source(s, origin);
+ return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &source);
+ }
+
+ inline MaybeLocal<BoundScript> CompileScript(
+ v8::Local<v8::String> s
+ ) {
+ v8::ScriptCompiler::Source source(s);
+ return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &source);
+ }
+
+ inline MaybeLocal<v8::Value> RunScript(
+ v8::Local<UnboundScript> script
+ ) {
+ EscapableHandleScope scope;
+ return scope.Escape(script->BindToCurrentContext()->Run());
+ }
+
+ inline MaybeLocal<v8::Value> RunScript(
+ v8::Local<BoundScript> script
+ ) {
+ return script->Run();
+ }
+#endif
+
+ NAN_DEPRECATED inline v8::Local<v8::Value> MakeCallback(
+ v8::Local<v8::Object> target
+ , v8::Local<v8::Function> func
+ , int argc
+ , v8::Local<v8::Value>* argv) {
+#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+ EscapableHandleScope scope;
+ return scope.Escape(New(node::MakeCallback(
+ v8::Isolate::GetCurrent(), target, func, argc, argv)));
+#else
+# if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+ AsyncResource res("nan:makeCallback");
+ return res.runInAsyncScope(target, func, argc, argv)
+ .FromMaybe(v8::Local<v8::Value>());
+# else
+ return node::MakeCallback(
+ v8::Isolate::GetCurrent(), target, func, argc, argv);
+# endif // NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+#endif // NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+ }
+
+ NAN_DEPRECATED inline v8::Local<v8::Value> MakeCallback(
+ v8::Local<v8::Object> target
+ , v8::Local<v8::String> symbol
+ , int argc
+ , v8::Local<v8::Value>* argv) {
+#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+ EscapableHandleScope scope;
+ return scope.Escape(New(node::MakeCallback(
+ v8::Isolate::GetCurrent(), target, symbol, argc, argv)));
+#else
+# if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+ AsyncResource res("nan:makeCallback");
+ return res.runInAsyncScope(target, symbol, argc, argv)
+ .FromMaybe(v8::Local<v8::Value>());
+# else
+ return node::MakeCallback(
+ v8::Isolate::GetCurrent(), target, symbol, argc, argv);
+# endif // NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+#endif // NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+ }
+
+ NAN_DEPRECATED inline v8::Local<v8::Value> MakeCallback(
+ v8::Local<v8::Object> target
+ , const char* method
+ , int argc
+ , v8::Local<v8::Value>* argv) {
+#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+ EscapableHandleScope scope;
+ return scope.Escape(New(node::MakeCallback(
+ v8::Isolate::GetCurrent(), target, method, argc, argv)));
+#else
+# if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+ AsyncResource res("nan:makeCallback");
+ return res.runInAsyncScope(target, method, argc, argv)
+ .FromMaybe(v8::Local<v8::Value>());
+# else
+ return node::MakeCallback(
+ v8::Isolate::GetCurrent(), target, method, argc, argv);
+# endif // NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+#endif // NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+ }
+
+ inline void FatalException(const TryCatch& try_catch) {
+ node::FatalException(v8::Isolate::GetCurrent(), try_catch.try_catch_);
+ }
+
+ inline v8::Local<v8::Value> ErrnoException(
+ int errorno
+ , const char* syscall = NULL
+ , const char* message = NULL
+ , const char* path = NULL) {
+ return node::ErrnoException(v8::Isolate::GetCurrent(), errorno, syscall,
+ message, path);
+ }
+
+ NAN_DEPRECATED inline v8::Local<v8::Value> NanErrnoException(
+ int errorno
+ , const char* syscall = NULL
+ , const char* message = NULL
+ , const char* path = NULL) {
+ return ErrnoException(errorno, syscall, message, path);
+ }
+
+ template<typename T>
+ inline void SetIsolateData(
+ v8::Isolate *isolate
+ , T *data
+ ) {
+ isolate->SetData(0, data);
+ }
+
+ template<typename T>
+ inline T *GetIsolateData(
+ v8::Isolate *isolate
+ ) {
+ return static_cast<T*>(isolate->GetData(0));
+ }
+
+class Utf8String {
+ public:
+ inline explicit Utf8String(v8::Local<v8::Value> from) :
+ length_(0), str_(str_st_) {
+ HandleScope scope;
+ if (!from.IsEmpty()) {
+#if NODE_MAJOR_VERSION >= 10
+ v8::Local<v8::Context> context = GetCurrentContext();
+ v8::Local<v8::String> string =
+ from->ToString(context).FromMaybe(v8::Local<v8::String>());
+#else
+ v8::Local<v8::String> string = from->ToString();
+#endif
+ if (!string.IsEmpty()) {
+ size_t len = 3 * string->Length() + 1;
+ assert(len <= INT_MAX);
+ if (len > sizeof (str_st_)) {
+ str_ = static_cast<char*>(malloc(len));
+ assert(str_ != 0);
+ }
+ const int flags =
+ v8::String::NO_NULL_TERMINATION | imp::kReplaceInvalidUtf8;
+#if NODE_MAJOR_VERSION >= 11
+ length_ = string->WriteUtf8(v8::Isolate::GetCurrent(), str_,
+ static_cast<int>(len), 0, flags);
+#else
+ // See https://github.com/nodejs/nan/issues/832.
+ // Disable the warning as there is no way around it.
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4996)
+#endif
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+ length_ = string->WriteUtf8(str_, static_cast<int>(len), 0, flags);
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+#endif // NODE_MAJOR_VERSION < 11
+ str_[length_] = '\0';
+ }
+ }
+ }
+
+ inline int length() const {
+ return length_;
+ }
+
+ inline char* operator*() { return str_; }
+ inline const char* operator*() const { return str_; }
+
+ inline ~Utf8String() {
+ if (str_ != str_st_) {
+ free(str_);
+ }
+ }
+
+ private:
+ NAN_DISALLOW_ASSIGN_COPY_MOVE(Utf8String)
+
+ int length_;
+ char *str_;
+ char str_st_[1024];
+};
+
+#else // Node 0.8 and 0.10
+ inline v8::Local<v8::Primitive> Undefined() {
+ EscapableHandleScope scope;
+ return scope.Escape(New(v8::Undefined()));
+ }
+
+ inline v8::Local<v8::Primitive> Null() {
+ EscapableHandleScope scope;
+ return scope.Escape(New(v8::Null()));
+ }
+
+ inline v8::Local<v8::Boolean> True() {
+ EscapableHandleScope scope;
+ return scope.Escape(New(v8::True()));
+ }
+
+ inline v8::Local<v8::Boolean> False() {
+ EscapableHandleScope scope;
+ return scope.Escape(New(v8::False()));
+ }
+
+ inline v8::Local<v8::String> EmptyString() {
+ return v8::String::Empty();
+ }
+
+ inline int AdjustExternalMemory(int bc) {
+ return static_cast<int>(v8::V8::AdjustAmountOfExternalAllocatedMemory(bc));
+ }
+
+ inline void SetTemplate(
+ v8::Local<v8::Template> templ
+ , const char *name
+ , v8::Local<v8::Data> value) {
+ templ->Set(name, value);
+ }
+
+ inline void SetTemplate(
+ v8::Local<v8::Template> templ
+ , v8::Local<v8::String> name
+ , v8::Local<v8::Data> value
+ , v8::PropertyAttribute attributes) {
+ templ->Set(name, value, attributes);
+ }
+
+ inline v8::Local<v8::Context> GetCurrentContext() {
+ return v8::Context::GetCurrent();
+ }
+
+ inline void* GetInternalFieldPointer(
+ v8::Local<v8::Object> object
+ , int index) {
+ return object->GetPointerFromInternalField(index);
+ }
+
+ inline void SetInternalFieldPointer(
+ v8::Local<v8::Object> object
+ , int index
+ , void* value) {
+ object->SetPointerInInternalField(index, value);
+ }
+
+# define NAN_GC_CALLBACK(name) \
+ void name(v8::GCType type, v8::GCCallbackFlags flags)
+
+ inline void AddGCEpilogueCallback(
+ v8::GCEpilogueCallback callback
+ , v8::GCType gc_type_filter = v8::kGCTypeAll) {
+ v8::V8::AddGCEpilogueCallback(callback, gc_type_filter);
+ }
+ inline void RemoveGCEpilogueCallback(
+ v8::GCEpilogueCallback callback) {
+ v8::V8::RemoveGCEpilogueCallback(callback);
+ }
+ inline void AddGCPrologueCallback(
+ v8::GCPrologueCallback callback
+ , v8::GCType gc_type_filter = v8::kGCTypeAll) {
+ v8::V8::AddGCPrologueCallback(callback, gc_type_filter);
+ }
+ inline void RemoveGCPrologueCallback(
+ v8::GCPrologueCallback callback) {
+ v8::V8::RemoveGCPrologueCallback(callback);
+ }
+ inline void GetHeapStatistics(
+ v8::HeapStatistics *heap_statistics) {
+ v8::V8::GetHeapStatistics(heap_statistics);
+ }
+
+# define X(NAME) \
+ inline v8::Local<v8::Value> NAME(const char *msg) { \
+ EscapableHandleScope scope; \
+ return scope.Escape(v8::Exception::NAME(New(msg).ToLocalChecked())); \
+ } \
+ \
+ inline \
+ v8::Local<v8::Value> NAME(v8::Local<v8::String> msg) { \
+ return v8::Exception::NAME(msg); \
+ } \
+ \
+ inline void Throw ## NAME(const char *msg) { \
+ HandleScope scope; \
+ v8::ThrowException(v8::Exception::NAME(New(msg).ToLocalChecked())); \
+ } \
+ \
+ inline \
+ void Throw ## NAME(v8::Local<v8::String> errmsg) { \
+ HandleScope scope; \
+ v8::ThrowException(v8::Exception::NAME(errmsg)); \
+ }
+
+ X(Error)
+ X(RangeError)
+ X(ReferenceError)
+ X(SyntaxError)
+ X(TypeError)
+
+# undef X
+
+ inline void ThrowError(v8::Local<v8::Value> error) {
+ v8::ThrowException(error);
+ }
+
+ inline MaybeLocal<v8::Object> NewBuffer(
+ char *data
+ , size_t length
+ , node::Buffer::free_callback callback
+ , void *hint
+ ) {
+ EscapableHandleScope scope;
+ // arbitrary buffer lengths requires
+ // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION
+ assert(length <= imp::kMaxLength && "too large buffer");
+ return scope.Escape(
+ New(node::Buffer::New(data, length, callback, hint)->handle_));
+ }
+
+ inline MaybeLocal<v8::Object> CopyBuffer(
+ const char *data
+ , uint32_t size
+ ) {
+ EscapableHandleScope scope;
+ // arbitrary buffer lengths requires
+ // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION
+ assert(size <= imp::kMaxLength && "too large buffer");
+#if NODE_MODULE_VERSION >= NODE_0_10_MODULE_VERSION
+ return scope.Escape(New(node::Buffer::New(data, size)->handle_));
+#else
+ return scope.Escape(
+ New(node::Buffer::New(const_cast<char *>(data), size)->handle_));
+#endif
+ }
+
+ inline MaybeLocal<v8::Object> NewBuffer(uint32_t size) {
+ // arbitrary buffer lengths requires
+ // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION
+ EscapableHandleScope scope;
+ assert(size <= imp::kMaxLength && "too large buffer");
+ return scope.Escape(New(node::Buffer::New(size)->handle_));
+ }
+
+ inline void FreeData(char *data, void *hint) {
+ (void) hint; // unused
+ delete[] data;
+ }
+
+ inline MaybeLocal<v8::Object> NewBuffer(
+ char* data
+ , uint32_t size
+ ) {
+ EscapableHandleScope scope;
+ // arbitrary buffer lengths requires
+ // NODE_MODULE_VERSION >= IOJS_3_0_MODULE_VERSION
+ assert(size <= imp::kMaxLength && "too large buffer");
+ return scope.Escape(
+ New(node::Buffer::New(data, size, FreeData, NULL)->handle_));
+ }
+
+namespace imp {
+inline void
+widenString(std::vector<uint16_t> *ws, const uint8_t *s, int l) {
+ size_t len = static_cast<size_t>(l);
+ if (l < 0) {
+ len = strlen(reinterpret_cast<const char*>(s));
+ }
+ assert(len <= INT_MAX && "string too long");
+ ws->resize(len);
+ std::copy(s, s + len, ws->begin()); // NOLINT(build/include_what_you_use)
+}
+} // end of namespace imp
+
+ inline MaybeLocal<v8::String>
+ NewOneByteString(const uint8_t * value, int length = -1) {
+ std::vector<uint16_t> wideString; // NOLINT(build/include_what_you_use)
+ imp::widenString(&wideString, value, length);
+ return v8::String::New(wideString.data(),
+ static_cast<int>(wideString.size()));
+ }
+
+ inline MaybeLocal<BoundScript> CompileScript(
+ v8::Local<v8::String> s
+ , const v8::ScriptOrigin& origin
+ ) {
+ return v8::Script::Compile(s, const_cast<v8::ScriptOrigin *>(&origin));
+ }
+
+ inline MaybeLocal<BoundScript> CompileScript(
+ v8::Local<v8::String> s
+ ) {
+ return v8::Script::Compile(s);
+ }
+
+ inline
+ MaybeLocal<v8::Value> RunScript(v8::Local<v8::Script> script) {
+ return script->Run();
+ }
+
+ inline v8::Local<v8::Value> MakeCallback(
+ v8::Local<v8::Object> target
+ , v8::Local<v8::Function> func
+ , int argc
+ , v8::Local<v8::Value>* argv) {
+ v8::HandleScope scope;
+ return scope.Close(New(node::MakeCallback(target, func, argc, argv)));
+ }
+
+ inline v8::Local<v8::Value> MakeCallback(
+ v8::Local<v8::Object> target
+ , v8::Local<v8::String> symbol
+ , int argc
+ , v8::Local<v8::Value>* argv) {
+ v8::HandleScope scope;
+ return scope.Close(New(node::MakeCallback(target, symbol, argc, argv)));
+ }
+
+ inline v8::Local<v8::Value> MakeCallback(
+ v8::Local<v8::Object> target
+ , const char* method
+ , int argc
+ , v8::Local<v8::Value>* argv) {
+ v8::HandleScope scope;
+ return scope.Close(New(node::MakeCallback(target, method, argc, argv)));
+ }
+
+ inline void FatalException(const TryCatch& try_catch) {
+ node::FatalException(const_cast<v8::TryCatch &>(try_catch.try_catch_));
+ }
+
+ inline v8::Local<v8::Value> ErrnoException(
+ int errorno
+ , const char* syscall = NULL
+ , const char* message = NULL
+ , const char* path = NULL) {
+ return node::ErrnoException(errorno, syscall, message, path);
+ }
+
+ NAN_DEPRECATED inline v8::Local<v8::Value> NanErrnoException(
+ int errorno
+ , const char* syscall = NULL
+ , const char* message = NULL
+ , const char* path = NULL) {
+ return ErrnoException(errorno, syscall, message, path);
+ }
+
+
+ template<typename T>
+ inline void SetIsolateData(
+ v8::Isolate *isolate
+ , T *data
+ ) {
+ isolate->SetData(data);
+ }
+
+ template<typename T>
+ inline T *GetIsolateData(
+ v8::Isolate *isolate
+ ) {
+ return static_cast<T*>(isolate->GetData());
+ }
+
+class Utf8String {
+ public:
+ inline explicit Utf8String(v8::Local<v8::Value> from) :
+ length_(0), str_(str_st_) {
+ v8::HandleScope scope;
+ if (!from.IsEmpty()) {
+ v8::Local<v8::String> string = from->ToString();
+ if (!string.IsEmpty()) {
+ size_t len = 3 * string->Length() + 1;
+ assert(len <= INT_MAX);
+ if (len > sizeof (str_st_)) {
+ str_ = static_cast<char*>(malloc(len));
+ assert(str_ != 0);
+ }
+ const int flags =
+ v8::String::NO_NULL_TERMINATION | imp::kReplaceInvalidUtf8;
+ length_ = string->WriteUtf8(str_, static_cast<int>(len), 0, flags);
+ str_[length_] = '\0';
+ }
+ }
+ }
+
+ inline int length() const {
+ return length_;
+ }
+
+ inline char* operator*() { return str_; }
+ inline const char* operator*() const { return str_; }
+
+ inline ~Utf8String() {
+ if (str_ != str_st_) {
+ free(str_);
+ }
+ }
+
+ private:
+ NAN_DISALLOW_ASSIGN_COPY_MOVE(Utf8String)
+
+ int length_;
+ char *str_;
+ char str_st_[1024];
+};
+
+#endif // NODE_MODULE_VERSION
+
+typedef void (*FreeCallback)(char *data, void *hint);
+
+typedef const FunctionCallbackInfo<v8::Value>& NAN_METHOD_ARGS_TYPE;
+typedef void NAN_METHOD_RETURN_TYPE;
+
+typedef const PropertyCallbackInfo<v8::Value>& NAN_GETTER_ARGS_TYPE;
+typedef void NAN_GETTER_RETURN_TYPE;
+
+typedef const PropertyCallbackInfo<void>& NAN_SETTER_ARGS_TYPE;
+typedef void NAN_SETTER_RETURN_TYPE;
+
+typedef const PropertyCallbackInfo<v8::Value>&
+ NAN_PROPERTY_GETTER_ARGS_TYPE;
+typedef void NAN_PROPERTY_GETTER_RETURN_TYPE;
+
+typedef const PropertyCallbackInfo<v8::Value>&
+ NAN_PROPERTY_SETTER_ARGS_TYPE;
+typedef void NAN_PROPERTY_SETTER_RETURN_TYPE;
+
+typedef const PropertyCallbackInfo<v8::Array>&
+ NAN_PROPERTY_ENUMERATOR_ARGS_TYPE;
+typedef void NAN_PROPERTY_ENUMERATOR_RETURN_TYPE;
+
+typedef const PropertyCallbackInfo<v8::Boolean>&
+ NAN_PROPERTY_DELETER_ARGS_TYPE;
+typedef void NAN_PROPERTY_DELETER_RETURN_TYPE;
+
+typedef const PropertyCallbackInfo<v8::Integer>&
+ NAN_PROPERTY_QUERY_ARGS_TYPE;
+typedef void NAN_PROPERTY_QUERY_RETURN_TYPE;
+
+typedef const PropertyCallbackInfo<v8::Value>& NAN_INDEX_GETTER_ARGS_TYPE;
+typedef void NAN_INDEX_GETTER_RETURN_TYPE;
+
+typedef const PropertyCallbackInfo<v8::Value>& NAN_INDEX_SETTER_ARGS_TYPE;
+typedef void NAN_INDEX_SETTER_RETURN_TYPE;
+
+typedef const PropertyCallbackInfo<v8::Array>&
+ NAN_INDEX_ENUMERATOR_ARGS_TYPE;
+typedef void NAN_INDEX_ENUMERATOR_RETURN_TYPE;
+
+typedef const PropertyCallbackInfo<v8::Boolean>&
+ NAN_INDEX_DELETER_ARGS_TYPE;
+typedef void NAN_INDEX_DELETER_RETURN_TYPE;
+
+typedef const PropertyCallbackInfo<v8::Integer>&
+ NAN_INDEX_QUERY_ARGS_TYPE;
+typedef void NAN_INDEX_QUERY_RETURN_TYPE;
+
+#define NAN_METHOD(name) \
+ Nan::NAN_METHOD_RETURN_TYPE name(Nan::NAN_METHOD_ARGS_TYPE info)
+#define NAN_GETTER(name) \
+ Nan::NAN_GETTER_RETURN_TYPE name( \
+ v8::Local<v8::String> property \
+ , Nan::NAN_GETTER_ARGS_TYPE info)
+#define NAN_SETTER(name) \
+ Nan::NAN_SETTER_RETURN_TYPE name( \
+ v8::Local<v8::String> property \
+ , v8::Local<v8::Value> value \
+ , Nan::NAN_SETTER_ARGS_TYPE info)
+#define NAN_PROPERTY_GETTER(name) \
+ Nan::NAN_PROPERTY_GETTER_RETURN_TYPE name( \
+ v8::Local<v8::String> property \
+ , Nan::NAN_PROPERTY_GETTER_ARGS_TYPE info)
+#define NAN_PROPERTY_SETTER(name) \
+ Nan::NAN_PROPERTY_SETTER_RETURN_TYPE name( \
+ v8::Local<v8::String> property \
+ , v8::Local<v8::Value> value \
+ , Nan::NAN_PROPERTY_SETTER_ARGS_TYPE info)
+#define NAN_PROPERTY_ENUMERATOR(name) \
+ Nan::NAN_PROPERTY_ENUMERATOR_RETURN_TYPE name( \
+ Nan::NAN_PROPERTY_ENUMERATOR_ARGS_TYPE info)
+#define NAN_PROPERTY_DELETER(name) \
+ Nan::NAN_PROPERTY_DELETER_RETURN_TYPE name( \
+ v8::Local<v8::String> property \
+ , Nan::NAN_PROPERTY_DELETER_ARGS_TYPE info)
+#define NAN_PROPERTY_QUERY(name) \
+ Nan::NAN_PROPERTY_QUERY_RETURN_TYPE name( \
+ v8::Local<v8::String> property \
+ , Nan::NAN_PROPERTY_QUERY_ARGS_TYPE info)
+# define NAN_INDEX_GETTER(name) \
+ Nan::NAN_INDEX_GETTER_RETURN_TYPE name( \
+ uint32_t index \
+ , Nan::NAN_INDEX_GETTER_ARGS_TYPE info)
+#define NAN_INDEX_SETTER(name) \
+ Nan::NAN_INDEX_SETTER_RETURN_TYPE name( \
+ uint32_t index \
+ , v8::Local<v8::Value> value \
+ , Nan::NAN_INDEX_SETTER_ARGS_TYPE info)
+#define NAN_INDEX_ENUMERATOR(name) \
+ Nan::NAN_INDEX_ENUMERATOR_RETURN_TYPE \
+ name(Nan::NAN_INDEX_ENUMERATOR_ARGS_TYPE info)
+#define NAN_INDEX_DELETER(name) \
+ Nan::NAN_INDEX_DELETER_RETURN_TYPE name( \
+ uint32_t index \
+ , Nan::NAN_INDEX_DELETER_ARGS_TYPE info)
+#define NAN_INDEX_QUERY(name) \
+ Nan::NAN_INDEX_QUERY_RETURN_TYPE name( \
+ uint32_t index \
+ , Nan::NAN_INDEX_QUERY_ARGS_TYPE info)
+
+class Callback {
+ public:
+ Callback() {}
+
+ explicit Callback(const v8::Local<v8::Function> &fn) : handle_(fn) {}
+
+ ~Callback() {
+ handle_.Reset();
+ }
+
+ bool operator==(const Callback &other) const {
+ return handle_ == other.handle_;
+ }
+
+ bool operator!=(const Callback &other) const {
+ return !operator==(other);
+ }
+
+ inline
+ v8::Local<v8::Function> operator*() const { return GetFunction(); }
+
+ NAN_DEPRECATED inline v8::Local<v8::Value> operator()(
+ v8::Local<v8::Object> target
+ , int argc = 0
+ , v8::Local<v8::Value> argv[] = 0) const {
+#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+# if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+ AsyncResource async("nan:Callback:operator()");
+ return Call_(isolate, target, argc, argv, &async)
+ .FromMaybe(v8::Local<v8::Value>());
+# else
+ return Call_(isolate, target, argc, argv);
+# endif // NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+#else
+ return Call_(target, argc, argv);
+#endif // NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+ }
+
+ NAN_DEPRECATED inline v8::Local<v8::Value> operator()(
+ int argc = 0
+ , v8::Local<v8::Value> argv[] = 0) const {
+#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+# if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+ AsyncResource async("nan:Callback:operator()");
+ return scope.Escape(Call_(isolate, isolate->GetCurrentContext()->Global(),
+ argc, argv, &async)
+ .FromMaybe(v8::Local<v8::Value>()));
+# else
+ return scope.Escape(
+ Call_(isolate, isolate->GetCurrentContext()->Global(), argc, argv));
+# endif // NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+#else
+ v8::HandleScope scope;
+ return scope.Close(Call_(v8::Context::GetCurrent()->Global(), argc, argv));
+#endif // NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+ }
+
+ inline MaybeLocal<v8::Value> operator()(
+ AsyncResource* resource
+ , int argc = 0
+ , v8::Local<v8::Value> argv[] = 0) const {
+ return this->Call(argc, argv, resource);
+ }
+
+ inline MaybeLocal<v8::Value> operator()(
+ AsyncResource* resource
+ , v8::Local<v8::Object> target
+ , int argc = 0
+ , v8::Local<v8::Value> argv[] = 0) const {
+ return this->Call(target, argc, argv, resource);
+ }
+
+ // TODO(kkoopa): remove
+ inline void SetFunction(const v8::Local<v8::Function> &fn) {
+ Reset(fn);
+ }
+
+ inline void Reset(const v8::Local<v8::Function> &fn) {
+ handle_.Reset(fn);
+ }
+
+ inline void Reset() {
+ handle_.Reset();
+ }
+
+ inline v8::Local<v8::Function> GetFunction() const {
+ return New(handle_);
+ }
+
+ inline bool IsEmpty() const {
+ return handle_.IsEmpty();
+ }
+
+ // Deprecated: For async callbacks Use the versions that accept an
+ // AsyncResource. If this callback does not correspond to an async resource,
+ // that is, it is a synchronous function call on a non-empty JS stack, you
+ // should Nan::Call instead.
+ NAN_DEPRECATED inline v8::Local<v8::Value>
+ Call(v8::Local<v8::Object> target
+ , int argc
+ , v8::Local<v8::Value> argv[]) const {
+#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+# if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+ AsyncResource async("nan:Callback:Call");
+ return Call_(isolate, target, argc, argv, &async)
+ .FromMaybe(v8::Local<v8::Value>());
+# else
+ return Call_(isolate, target, argc, argv);
+# endif // NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+#else
+ return Call_(target, argc, argv);
+#endif
+ }
+
+ // Deprecated: For async callbacks Use the versions that accept an
+ // AsyncResource. If this callback does not correspond to an async resource,
+ // that is, it is a synchronous function call on a non-empty JS stack, you
+ // should Nan::Call instead.
+ NAN_DEPRECATED inline v8::Local<v8::Value>
+ Call(int argc, v8::Local<v8::Value> argv[]) const {
+#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+# if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+ AsyncResource async("nan:Callback:Call");
+ return scope.Escape(Call_(isolate, isolate->GetCurrentContext()->Global(),
+ argc, argv, &async)
+ .FromMaybe(v8::Local<v8::Value>()));
+# else
+ return scope.Escape(
+ Call_(isolate, isolate->GetCurrentContext()->Global(), argc, argv));
+# endif // NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+#else
+ v8::HandleScope scope;
+ return scope.Close(Call_(v8::Context::GetCurrent()->Global(), argc, argv));
+#endif
+ }
+
+ inline MaybeLocal<v8::Value>
+ Call(v8::Local<v8::Object> target
+ , int argc
+ , v8::Local<v8::Value> argv[]
+ , AsyncResource* resource) const {
+#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ return Call_(isolate, target, argc, argv, resource);
+#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ return Call_(isolate, target, argc, argv);
+#else
+ return Call_(target, argc, argv);
+#endif
+ }
+
+ inline MaybeLocal<v8::Value>
+ Call(int argc, v8::Local<v8::Value> argv[], AsyncResource* resource) const {
+#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ return Call(isolate->GetCurrentContext()->Global(), argc, argv, resource);
+#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(
+ Call_(isolate, isolate->GetCurrentContext()->Global(), argc, argv));
+#else
+ v8::HandleScope scope;
+ return scope.Close(Call_(v8::Context::GetCurrent()->Global(), argc, argv));
+#endif
+ }
+
+ private:
+ NAN_DISALLOW_ASSIGN_COPY_MOVE(Callback)
+ Persistent<v8::Function> handle_;
+
+#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+ MaybeLocal<v8::Value> Call_(v8::Isolate *isolate
+ , v8::Local<v8::Object> target
+ , int argc
+ , v8::Local<v8::Value> argv[]
+ , AsyncResource* resource) const {
+ EscapableHandleScope scope;
+ v8::Local<v8::Function> func = New(handle_);
+ auto maybe = resource->runInAsyncScope(target, func, argc, argv);
+ v8::Local<v8::Value> local;
+ if (!maybe.ToLocal(&local)) return MaybeLocal<v8::Value>();
+ return scope.Escape(local);
+ }
+#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+ v8::Local<v8::Value> Call_(v8::Isolate *isolate
+ , v8::Local<v8::Object> target
+ , int argc
+ , v8::Local<v8::Value> argv[]) const {
+ EscapableHandleScope scope;
+
+ v8::Local<v8::Function> callback = New(handle_);
+# if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+ return scope.Escape(New(node::MakeCallback(
+ isolate
+ , target
+ , callback
+ , argc
+ , argv
+ )));
+# else
+ return scope.Escape(node::MakeCallback(
+ isolate
+ , target
+ , callback
+ , argc
+ , argv
+ ));
+# endif
+ }
+#else
+ v8::Local<v8::Value> Call_(v8::Local<v8::Object> target
+ , int argc
+ , v8::Local<v8::Value> argv[]) const {
+ EscapableHandleScope scope;
+
+ v8::Local<v8::Function> callback = New(handle_);
+ return scope.Escape(New(node::MakeCallback(
+ target
+ , callback
+ , argc
+ , argv
+ )));
+ }
+#endif
+};
+
+inline MaybeLocal<v8::Value> Call(
+ const Nan::Callback& callback
+ , v8::Local<v8::Object> recv
+ , int argc
+ , v8::Local<v8::Value> argv[]) {
+ return Call(*callback, recv, argc, argv);
+}
+
+inline MaybeLocal<v8::Value> Call(
+ const Nan::Callback& callback
+ , int argc
+ , v8::Local<v8::Value> argv[]) {
+#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(
+ Call(*callback, isolate->GetCurrentContext()->Global(), argc, argv)
+ .FromMaybe(v8::Local<v8::Value>()));
+#else
+ EscapableHandleScope scope;
+ return scope.Escape(
+ Call(*callback, v8::Context::GetCurrent()->Global(), argc, argv)
+ .FromMaybe(v8::Local<v8::Value>()));
+#endif
+}
+
+inline MaybeLocal<v8::Value> Call(
+ v8::Local<v8::String> symbol
+ , v8::Local<v8::Object> recv
+ , int argc
+ , v8::Local<v8::Value> argv[]) {
+ EscapableHandleScope scope;
+ v8::Local<v8::Value> fn_v =
+ Get(recv, symbol).FromMaybe(v8::Local<v8::Value>());
+ if (fn_v.IsEmpty() || !fn_v->IsFunction()) return v8::Local<v8::Value>();
+ v8::Local<v8::Function> fn = fn_v.As<v8::Function>();
+ return scope.Escape(
+ Call(fn, recv, argc, argv).FromMaybe(v8::Local<v8::Value>()));
+}
+
+inline MaybeLocal<v8::Value> Call(
+ const char* method
+ , v8::Local<v8::Object> recv
+ , int argc
+ , v8::Local<v8::Value> argv[]) {
+ EscapableHandleScope scope;
+ v8::Local<v8::String> method_string =
+ New<v8::String>(method).ToLocalChecked();
+ return scope.Escape(
+ Call(method_string, recv, argc, argv).FromMaybe(v8::Local<v8::Value>()));
+}
+
+/* abstract */ class AsyncWorker {
+ public:
+ explicit AsyncWorker(Callback *callback_,
+ const char* resource_name = "nan:AsyncWorker")
+ : callback(callback_), errmsg_(NULL) {
+ request.data = this;
+
+ HandleScope scope;
+ v8::Local<v8::Object> obj = New<v8::Object>();
+ persistentHandle.Reset(obj);
+ async_resource = new AsyncResource(resource_name, obj);
+ }
+
+ virtual ~AsyncWorker() {
+ HandleScope scope;
+
+ if (!persistentHandle.IsEmpty())
+ persistentHandle.Reset();
+ delete callback;
+ delete[] errmsg_;
+ delete async_resource;
+ }
+
+ virtual void WorkComplete() {
+ HandleScope scope;
+
+ if (errmsg_ == NULL)
+ HandleOKCallback();
+ else
+ HandleErrorCallback();
+ delete callback;
+ callback = NULL;
+ }
+
+ inline void SaveToPersistent(
+ const char *key, const v8::Local<v8::Value> &value) {
+ HandleScope scope;
+ Set(New(persistentHandle), New(key).ToLocalChecked(), value).FromJust();
+ }
+
+ inline void SaveToPersistent(
+ const v8::Local<v8::String> &key, const v8::Local<v8::Value> &value) {
+ HandleScope scope;
+ Set(New(persistentHandle), key, value).FromJust();
+ }
+
+ inline void SaveToPersistent(
+ uint32_t index, const v8::Local<v8::Value> &value) {
+ HandleScope scope;
+ Set(New(persistentHandle), index, value).FromJust();
+ }
+
+ inline v8::Local<v8::Value> GetFromPersistent(const char *key) const {
+ EscapableHandleScope scope;
+ return scope.Escape(
+ Get(New(persistentHandle), New(key).ToLocalChecked())
+ .FromMaybe(v8::Local<v8::Value>()));
+ }
+
+ inline v8::Local<v8::Value>
+ GetFromPersistent(const v8::Local<v8::String> &key) const {
+ EscapableHandleScope scope;
+ return scope.Escape(
+ Get(New(persistentHandle), key)
+ .FromMaybe(v8::Local<v8::Value>()));
+ }
+
+ inline v8::Local<v8::Value> GetFromPersistent(uint32_t index) const {
+ EscapableHandleScope scope;
+ return scope.Escape(
+ Get(New(persistentHandle), index)
+ .FromMaybe(v8::Local<v8::Value>()));
+ }
+
+ virtual void Execute() = 0;
+
+ uv_work_t request;
+
+ virtual void Destroy() {
+ delete this;
+ }
+
+ protected:
+ Persistent<v8::Object> persistentHandle;
+ Callback *callback;
+ AsyncResource *async_resource;
+
+ virtual void HandleOKCallback() {
+ HandleScope scope;
+
+ callback->Call(0, NULL, async_resource);
+ }
+
+ virtual void HandleErrorCallback() {
+ HandleScope scope;
+
+ v8::Local<v8::Value> argv[] = {
+ v8::Exception::Error(New<v8::String>(ErrorMessage()).ToLocalChecked())
+ };
+ callback->Call(1, argv, async_resource);
+ }
+
+ void SetErrorMessage(const char *msg) {
+ delete[] errmsg_;
+
+ size_t size = strlen(msg) + 1;
+ errmsg_ = new char[size];
+ memcpy(errmsg_, msg, size);
+ }
+
+ const char* ErrorMessage() const {
+ return errmsg_;
+ }
+
+ private:
+ NAN_DISALLOW_ASSIGN_COPY_MOVE(AsyncWorker)
+ char *errmsg_;
+};
+
+/* abstract */ class AsyncBareProgressWorkerBase : public AsyncWorker {
+ public:
+ explicit AsyncBareProgressWorkerBase(
+ Callback *callback_,
+ const char* resource_name = "nan:AsyncBareProgressWorkerBase")
+ : AsyncWorker(callback_, resource_name) {
+ uv_async_init(
+ GetCurrentEventLoop()
+ , &async
+ , AsyncProgress_
+ );
+ async.data = this;
+ }
+
+ virtual ~AsyncBareProgressWorkerBase() {
+ }
+
+ virtual void WorkProgress() = 0;
+
+ virtual void Destroy() {
+ uv_close(reinterpret_cast<uv_handle_t*>(&async), AsyncClose_);
+ }
+
+ private:
+ inline static NAUV_WORK_CB(AsyncProgress_) {
+ AsyncBareProgressWorkerBase *worker =
+ static_cast<AsyncBareProgressWorkerBase*>(async->data);
+ worker->WorkProgress();
+ }
+
+ inline static void AsyncClose_(uv_handle_t* handle) {
+ AsyncBareProgressWorkerBase *worker =
+ static_cast<AsyncBareProgressWorkerBase*>(handle->data);
+ delete worker;
+ }
+
+ protected:
+ uv_async_t async;
+};
+
+template<class T>
+/* abstract */
+class AsyncBareProgressWorker : public AsyncBareProgressWorkerBase {
+ public:
+ explicit AsyncBareProgressWorker(
+ Callback *callback_,
+ const char* resource_name = "nan:AsyncBareProgressWorker")
+ : AsyncBareProgressWorkerBase(callback_, resource_name) {
+ uv_mutex_init(&async_lock);
+ }
+
+ virtual ~AsyncBareProgressWorker() {
+ uv_mutex_destroy(&async_lock);
+ }
+
+ class ExecutionProgress {
+ friend class AsyncBareProgressWorker;
+ public:
+ void Signal() const {
+ uv_mutex_lock(&that_->async_lock);
+ uv_async_send(&that_->async);
+ uv_mutex_unlock(&that_->async_lock);
+ }
+
+ void Send(const T* data, size_t count) const {
+ that_->SendProgress_(data, count);
+ }
+
+ private:
+ explicit ExecutionProgress(AsyncBareProgressWorker *that) : that_(that) {}
+ NAN_DISALLOW_ASSIGN_COPY_MOVE(ExecutionProgress)
+ AsyncBareProgressWorker* const that_;
+ };
+
+ virtual void Execute(const ExecutionProgress& progress) = 0;
+ virtual void HandleProgressCallback(const T *data, size_t size) = 0;
+
+ protected:
+ uv_mutex_t async_lock;
+
+ private:
+ void Execute() /*final override*/ {
+ ExecutionProgress progress(this);
+ Execute(progress);
+ }
+
+ virtual void SendProgress_(const T *data, size_t count) = 0;
+};
+
+template<class T>
+/* abstract */
+class AsyncProgressWorkerBase : public AsyncBareProgressWorker<T> {
+ public:
+ explicit AsyncProgressWorkerBase(
+ Callback *callback_,
+ const char* resource_name = "nan:AsyncProgressWorkerBase")
+ : AsyncBareProgressWorker<T>(callback_, resource_name), asyncdata_(NULL),
+ asyncsize_(0) {
+ }
+
+ virtual ~AsyncProgressWorkerBase() {
+ delete[] asyncdata_;
+ }
+
+ void WorkProgress() {
+ uv_mutex_lock(&this->async_lock);
+ T *data = asyncdata_;
+ size_t size = asyncsize_;
+ asyncdata_ = NULL;
+ asyncsize_ = 0;
+ uv_mutex_unlock(&this->async_lock);
+
+ // Don't send progress events after we've already completed.
+ if (this->callback) {
+ this->HandleProgressCallback(data, size);
+ }
+ delete[] data;
+ }
+
+ private:
+ void SendProgress_(const T *data, size_t count) {
+ T *new_data = new T[count];
+ {
+ T *it = new_data;
+ std::copy(data, data + count, it);
+ }
+
+ uv_mutex_lock(&this->async_lock);
+ T *old_data = asyncdata_;
+ asyncdata_ = new_data;
+ asyncsize_ = count;
+ uv_async_send(&this->async);
+ uv_mutex_unlock(&this->async_lock);
+
+ delete[] old_data;
+ }
+
+ T *asyncdata_;
+ size_t asyncsize_;
+};
+
+// This ensures compatibility to the previous un-templated AsyncProgressWorker
+// class definition.
+typedef AsyncProgressWorkerBase<char> AsyncProgressWorker;
+
+template<class T>
+/* abstract */
+class AsyncBareProgressQueueWorker : public AsyncBareProgressWorkerBase {
+ public:
+ explicit AsyncBareProgressQueueWorker(
+ Callback *callback_,
+ const char* resource_name = "nan:AsyncBareProgressQueueWorker")
+ : AsyncBareProgressWorkerBase(callback_, resource_name) {
+ }
+
+ virtual ~AsyncBareProgressQueueWorker() {
+ }
+
+ class ExecutionProgress {
+ friend class AsyncBareProgressQueueWorker;
+ public:
+ void Send(const T* data, size_t count) const {
+ that_->SendProgress_(data, count);
+ }
+
+ private:
+ explicit ExecutionProgress(AsyncBareProgressQueueWorker *that)
+ : that_(that) {}
+ NAN_DISALLOW_ASSIGN_COPY_MOVE(ExecutionProgress)
+ AsyncBareProgressQueueWorker* const that_;
+ };
+
+ virtual void Execute(const ExecutionProgress& progress) = 0;
+ virtual void HandleProgressCallback(const T *data, size_t size) = 0;
+
+ private:
+ void Execute() /*final override*/ {
+ ExecutionProgress progress(this);
+ Execute(progress);
+ }
+
+ virtual void SendProgress_(const T *data, size_t count) = 0;
+};
+
+template<class T>
+/* abstract */
+class AsyncProgressQueueWorker : public AsyncBareProgressQueueWorker<T> {
+ public:
+ explicit AsyncProgressQueueWorker(
+ Callback *callback_,
+ const char* resource_name = "nan:AsyncProgressQueueWorker")
+ : AsyncBareProgressQueueWorker<T>(callback_) {
+ uv_mutex_init(&async_lock);
+ }
+
+ virtual ~AsyncProgressQueueWorker() {
+ uv_mutex_lock(&async_lock);
+
+ while (!asyncdata_.empty()) {
+ std::pair<T*, size_t> &datapair = asyncdata_.front();
+ T *data = datapair.first;
+
+ asyncdata_.pop();
+
+ delete[] data;
+ }
+
+ uv_mutex_unlock(&async_lock);
+ uv_mutex_destroy(&async_lock);
+ }
+
+ void WorkComplete() {
+ WorkProgress();
+ AsyncWorker::WorkComplete();
+ }
+
+ void WorkProgress() {
+ uv_mutex_lock(&async_lock);
+
+ while (!asyncdata_.empty()) {
+ std::pair<T*, size_t> &datapair = asyncdata_.front();
+
+ T *data = datapair.first;
+ size_t size = datapair.second;
+
+ asyncdata_.pop();
+ uv_mutex_unlock(&async_lock);
+
+ // Don't send progress events after we've already completed.
+ if (this->callback) {
+ this->HandleProgressCallback(data, size);
+ }
+
+ delete[] data;
+
+ uv_mutex_lock(&async_lock);
+ }
+
+ uv_mutex_unlock(&async_lock);
+ }
+
+ private:
+ void SendProgress_(const T *data, size_t count) {
+ T *new_data = new T[count];
+ {
+ T *it = new_data;
+ std::copy(data, data + count, it);
+ }
+
+ uv_mutex_lock(&async_lock);
+ asyncdata_.push(std::pair<T*, size_t>(new_data, count));
+ uv_mutex_unlock(&async_lock);
+
+ uv_async_send(&this->async);
+ }
+
+ uv_mutex_t async_lock;
+ std::queue<std::pair<T*, size_t> > asyncdata_;
+};
+
+inline void AsyncExecute (uv_work_t* req) {
+ AsyncWorker *worker = static_cast<AsyncWorker*>(req->data);
+ worker->Execute();
+}
+
+inline void AsyncExecuteComplete (uv_work_t* req) {
+ AsyncWorker* worker = static_cast<AsyncWorker*>(req->data);
+ worker->WorkComplete();
+ worker->Destroy();
+}
+
+inline void AsyncQueueWorker (AsyncWorker* worker) {
+ uv_queue_work(
+ GetCurrentEventLoop()
+ , &worker->request
+ , AsyncExecute
+ , reinterpret_cast<uv_after_work_cb>(AsyncExecuteComplete)
+ );
+}
+
+namespace imp {
+
+inline
+ExternalOneByteStringResource const*
+GetExternalResource(v8::Local<v8::String> str) {
+#if NODE_MODULE_VERSION < ATOM_0_21_MODULE_VERSION
+ return str->GetExternalAsciiStringResource();
+#else
+ return str->GetExternalOneByteStringResource();
+#endif
+}
+
+inline
+bool
+IsExternal(v8::Local<v8::String> str) {
+#if NODE_MODULE_VERSION < ATOM_0_21_MODULE_VERSION
+ return str->IsExternalAscii();
+#else
+ return str->IsExternalOneByte();
+#endif
+}
+
+} // end of namespace imp
+
+enum Encoding {ASCII, UTF8, BASE64, UCS2, BINARY, HEX, BUFFER};
+
+#if NODE_MODULE_VERSION < NODE_0_10_MODULE_VERSION
+# include "nan_string_bytes.h" // NOLINT(build/include)
+#endif
+
+inline v8::Local<v8::Value> Encode(
+ const void *buf, size_t len, enum Encoding encoding = BINARY) {
+#if (NODE_MODULE_VERSION >= ATOM_0_21_MODULE_VERSION)
+ v8::Isolate* isolate = v8::Isolate::GetCurrent();
+ node::encoding node_enc = static_cast<node::encoding>(encoding);
+
+ if (encoding == UCS2) {
+ return node::Encode(
+ isolate
+ , reinterpret_cast<const uint16_t *>(buf)
+ , len / 2);
+ } else {
+ return node::Encode(
+ isolate
+ , reinterpret_cast<const char *>(buf)
+ , len
+ , node_enc);
+ }
+#elif (NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION)
+ return node::Encode(
+ v8::Isolate::GetCurrent()
+ , buf, len
+ , static_cast<node::encoding>(encoding));
+#else
+# if NODE_MODULE_VERSION >= NODE_0_10_MODULE_VERSION
+ return node::Encode(buf, len, static_cast<node::encoding>(encoding));
+# else
+ return imp::Encode(reinterpret_cast<const char*>(buf), len, encoding);
+# endif
+#endif
+}
+
+inline ssize_t DecodeBytes(
+ v8::Local<v8::Value> val, enum Encoding encoding = BINARY) {
+#if (NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION)
+ return node::DecodeBytes(
+ v8::Isolate::GetCurrent()
+ , val
+ , static_cast<node::encoding>(encoding));
+#else
+# if (NODE_MODULE_VERSION < NODE_0_10_MODULE_VERSION)
+ if (encoding == BUFFER) {
+ return node::DecodeBytes(val, node::BINARY);
+ }
+# endif
+ return node::DecodeBytes(val, static_cast<node::encoding>(encoding));
+#endif
+}
+
+inline ssize_t DecodeWrite(
+ char *buf
+ , size_t len
+ , v8::Local<v8::Value> val
+ , enum Encoding encoding = BINARY) {
+#if (NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION)
+ return node::DecodeWrite(
+ v8::Isolate::GetCurrent()
+ , buf
+ , len
+ , val
+ , static_cast<node::encoding>(encoding));
+#else
+# if (NODE_MODULE_VERSION < NODE_0_10_MODULE_VERSION)
+ if (encoding == BUFFER) {
+ return node::DecodeWrite(buf, len, val, node::BINARY);
+ }
+# endif
+ return node::DecodeWrite(
+ buf
+ , len
+ , val
+ , static_cast<node::encoding>(encoding));
+#endif
+}
+
+inline void SetPrototypeTemplate(
+ v8::Local<v8::FunctionTemplate> templ
+ , const char *name
+ , v8::Local<v8::Data> value
+) {
+ HandleScope scope;
+ SetTemplate(templ->PrototypeTemplate(), name, value);
+}
+
+inline void SetPrototypeTemplate(
+ v8::Local<v8::FunctionTemplate> templ
+ , v8::Local<v8::String> name
+ , v8::Local<v8::Data> value
+ , v8::PropertyAttribute attributes
+) {
+ HandleScope scope;
+ SetTemplate(templ->PrototypeTemplate(), name, value, attributes);
+}
+
+inline void SetInstanceTemplate(
+ v8::Local<v8::FunctionTemplate> templ
+ , const char *name
+ , v8::Local<v8::Data> value
+) {
+ HandleScope scope;
+ SetTemplate(templ->InstanceTemplate(), name, value);
+}
+
+inline void SetInstanceTemplate(
+ v8::Local<v8::FunctionTemplate> templ
+ , v8::Local<v8::String> name
+ , v8::Local<v8::Data> value
+ , v8::PropertyAttribute attributes
+) {
+ HandleScope scope;
+ SetTemplate(templ->InstanceTemplate(), name, value, attributes);
+}
+
+namespace imp {
+
+// Note(@agnat): Helper to distinguish different receiver types. The first
+// version deals with receivers derived from v8::Template. The second version
+// handles everything else. The final argument only serves as discriminator and
+// is unused.
+template <typename T>
+inline
+void
+SetMethodAux(T recv,
+ v8::Local<v8::String> name,
+ v8::Local<v8::FunctionTemplate> tpl,
+ v8::Template *) {
+ recv->Set(name, tpl);
+}
+
+template <typename T>
+inline
+void
+SetMethodAux(T recv,
+ v8::Local<v8::String> name,
+ v8::Local<v8::FunctionTemplate> tpl,
+ ...) {
+ Set(recv, name, GetFunction(tpl).ToLocalChecked());
+}
+
+} // end of namespace imp
+
+template <typename T, template <typename> class HandleType>
+inline void SetMethod(
+ HandleType<T> recv
+ , const char *name
+ , FunctionCallback callback) {
+ HandleScope scope;
+ v8::Local<v8::FunctionTemplate> t = New<v8::FunctionTemplate>(callback);
+ v8::Local<v8::String> fn_name = New(name).ToLocalChecked();
+ t->SetClassName(fn_name);
+ // Note(@agnat): Pass an empty T* as discriminator. See note on
+ // SetMethodAux(...) above
+ imp::SetMethodAux(recv, fn_name, t, static_cast<T*>(0));
+}
+
+inline void SetPrototypeMethod(
+ v8::Local<v8::FunctionTemplate> recv
+ , const char* name, FunctionCallback callback) {
+ HandleScope scope;
+ v8::Local<v8::FunctionTemplate> t = New<v8::FunctionTemplate>(
+ callback
+ , v8::Local<v8::Value>()
+ , New<v8::Signature>(recv));
+ v8::Local<v8::String> fn_name = New(name).ToLocalChecked();
+ recv->PrototypeTemplate()->Set(fn_name, t);
+ t->SetClassName(fn_name);
+}
+
+//=== Accessors and Such =======================================================
+
+inline void SetAccessor(
+ v8::Local<v8::ObjectTemplate> tpl
+ , v8::Local<v8::String> name
+ , GetterCallback getter
+ , SetterCallback setter = 0
+ , v8::Local<v8::Value> data = v8::Local<v8::Value>()
+ , v8::AccessControl settings = v8::DEFAULT
+ , v8::PropertyAttribute attribute = v8::None
+ , imp::Sig signature = imp::Sig()) {
+ HandleScope scope;
+
+ imp::NativeGetter getter_ =
+ imp::GetterCallbackWrapper;
+ imp::NativeSetter setter_ =
+ setter ? imp::SetterCallbackWrapper : 0;
+
+ v8::Local<v8::ObjectTemplate> otpl = New<v8::ObjectTemplate>();
+ otpl->SetInternalFieldCount(imp::kAccessorFieldCount);
+ v8::Local<v8::Object> obj = NewInstance(otpl).ToLocalChecked();
+
+ obj->SetInternalField(
+ imp::kGetterIndex
+ , New<v8::External>(reinterpret_cast<void *>(getter)));
+
+ if (setter != 0) {
+ obj->SetInternalField(
+ imp::kSetterIndex
+ , New<v8::External>(reinterpret_cast<void *>(setter)));
+ }
+
+ if (!data.IsEmpty()) {
+ obj->SetInternalField(imp::kDataIndex, data);
+ }
+
+ tpl->SetAccessor(
+ name
+ , getter_
+ , setter_
+ , obj
+ , settings
+ , attribute
+ , signature);
+}
+
+inline bool SetAccessor(
+ v8::Local<v8::Object> obj
+ , v8::Local<v8::String> name
+ , GetterCallback getter
+ , SetterCallback setter = 0
+ , v8::Local<v8::Value> data = v8::Local<v8::Value>()
+ , v8::AccessControl settings = v8::DEFAULT
+ , v8::PropertyAttribute attribute = v8::None) {
+ HandleScope scope;
+
+ imp::NativeGetter getter_ =
+ imp::GetterCallbackWrapper;
+ imp::NativeSetter setter_ =
+ setter ? imp::SetterCallbackWrapper : 0;
+
+ v8::Local<v8::ObjectTemplate> otpl = New<v8::ObjectTemplate>();
+ otpl->SetInternalFieldCount(imp::kAccessorFieldCount);
+ v8::Local<v8::Object> dataobj = NewInstance(otpl).ToLocalChecked();
+
+ dataobj->SetInternalField(
+ imp::kGetterIndex
+ , New<v8::External>(reinterpret_cast<void *>(getter)));
+
+ if (!data.IsEmpty()) {
+ dataobj->SetInternalField(imp::kDataIndex, data);
+ }
+
+ if (setter) {
+ dataobj->SetInternalField(
+ imp::kSetterIndex
+ , New<v8::External>(reinterpret_cast<void *>(setter)));
+ }
+
+#if (NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION)
+ return obj->SetAccessor(
+ GetCurrentContext()
+ , name
+ , getter_
+ , setter_
+ , dataobj
+ , settings
+ , attribute).FromMaybe(false);
+#else
+ return obj->SetAccessor(
+ name
+ , getter_
+ , setter_
+ , dataobj
+ , settings
+ , attribute);
+#endif
+}
+
+inline void SetNamedPropertyHandler(
+ v8::Local<v8::ObjectTemplate> tpl
+ , PropertyGetterCallback getter
+ , PropertySetterCallback setter = 0
+ , PropertyQueryCallback query = 0
+ , PropertyDeleterCallback deleter = 0
+ , PropertyEnumeratorCallback enumerator = 0
+ , v8::Local<v8::Value> data = v8::Local<v8::Value>()) {
+ HandleScope scope;
+
+ imp::NativePropertyGetter getter_ =
+ imp::PropertyGetterCallbackWrapper;
+ imp::NativePropertySetter setter_ =
+ setter ? imp::PropertySetterCallbackWrapper : 0;
+ imp::NativePropertyQuery query_ =
+ query ? imp::PropertyQueryCallbackWrapper : 0;
+ imp::NativePropertyDeleter *deleter_ =
+ deleter ? imp::PropertyDeleterCallbackWrapper : 0;
+ imp::NativePropertyEnumerator enumerator_ =
+ enumerator ? imp::PropertyEnumeratorCallbackWrapper : 0;
+
+ v8::Local<v8::ObjectTemplate> otpl = New<v8::ObjectTemplate>();
+ otpl->SetInternalFieldCount(imp::kPropertyFieldCount);
+ v8::Local<v8::Object> obj = NewInstance(otpl).ToLocalChecked();
+ obj->SetInternalField(
+ imp::kPropertyGetterIndex
+ , New<v8::External>(reinterpret_cast<void *>(getter)));
+
+ if (setter) {
+ obj->SetInternalField(
+ imp::kPropertySetterIndex
+ , New<v8::External>(reinterpret_cast<void *>(setter)));
+ }
+
+ if (query) {
+ obj->SetInternalField(
+ imp::kPropertyQueryIndex
+ , New<v8::External>(reinterpret_cast<void *>(query)));
+ }
+
+ if (deleter) {
+ obj->SetInternalField(
+ imp::kPropertyDeleterIndex
+ , New<v8::External>(reinterpret_cast<void *>(deleter)));
+ }
+
+ if (enumerator) {
+ obj->SetInternalField(
+ imp::kPropertyEnumeratorIndex
+ , New<v8::External>(reinterpret_cast<void *>(enumerator)));
+ }
+
+ if (!data.IsEmpty()) {
+ obj->SetInternalField(imp::kDataIndex, data);
+ }
+
+#if NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION
+ tpl->SetHandler(v8::NamedPropertyHandlerConfiguration(
+ getter_, setter_, query_, deleter_, enumerator_, obj));
+#else
+ tpl->SetNamedPropertyHandler(
+ getter_
+ , setter_
+ , query_
+ , deleter_
+ , enumerator_
+ , obj);
+#endif
+}
+
+inline void SetIndexedPropertyHandler(
+ v8::Local<v8::ObjectTemplate> tpl
+ , IndexGetterCallback getter
+ , IndexSetterCallback setter = 0
+ , IndexQueryCallback query = 0
+ , IndexDeleterCallback deleter = 0
+ , IndexEnumeratorCallback enumerator = 0
+ , v8::Local<v8::Value> data = v8::Local<v8::Value>()) {
+ HandleScope scope;
+
+ imp::NativeIndexGetter getter_ =
+ imp::IndexGetterCallbackWrapper;
+ imp::NativeIndexSetter setter_ =
+ setter ? imp::IndexSetterCallbackWrapper : 0;
+ imp::NativeIndexQuery query_ =
+ query ? imp::IndexQueryCallbackWrapper : 0;
+ imp::NativeIndexDeleter deleter_ =
+ deleter ? imp::IndexDeleterCallbackWrapper : 0;
+ imp::NativeIndexEnumerator enumerator_ =
+ enumerator ? imp::IndexEnumeratorCallbackWrapper : 0;
+
+ v8::Local<v8::ObjectTemplate> otpl = New<v8::ObjectTemplate>();
+ otpl->SetInternalFieldCount(imp::kIndexPropertyFieldCount);
+ v8::Local<v8::Object> obj = NewInstance(otpl).ToLocalChecked();
+ obj->SetInternalField(
+ imp::kIndexPropertyGetterIndex
+ , New<v8::External>(reinterpret_cast<void *>(getter)));
+
+ if (setter) {
+ obj->SetInternalField(
+ imp::kIndexPropertySetterIndex
+ , New<v8::External>(reinterpret_cast<void *>(setter)));
+ }
+
+ if (query) {
+ obj->SetInternalField(
+ imp::kIndexPropertyQueryIndex
+ , New<v8::External>(reinterpret_cast<void *>(query)));
+ }
+
+ if (deleter) {
+ obj->SetInternalField(
+ imp::kIndexPropertyDeleterIndex
+ , New<v8::External>(reinterpret_cast<void *>(deleter)));
+ }
+
+ if (enumerator) {
+ obj->SetInternalField(
+ imp::kIndexPropertyEnumeratorIndex
+ , New<v8::External>(reinterpret_cast<void *>(enumerator)));
+ }
+
+ if (!data.IsEmpty()) {
+ obj->SetInternalField(imp::kDataIndex, data);
+ }
+
+#if NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION
+ tpl->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+ getter_, setter_, query_, deleter_, enumerator_, obj));
+#else
+ tpl->SetIndexedPropertyHandler(
+ getter_
+ , setter_
+ , query_
+ , deleter_
+ , enumerator_
+ , obj);
+#endif
+}
+
+inline void SetCallHandler(
+ v8::Local<v8::FunctionTemplate> tpl
+ , FunctionCallback callback
+ , v8::Local<v8::Value> data = v8::Local<v8::Value>()) {
+ HandleScope scope;
+
+ v8::Local<v8::ObjectTemplate> otpl = New<v8::ObjectTemplate>();
+ otpl->SetInternalFieldCount(imp::kFunctionFieldCount);
+ v8::Local<v8::Object> obj = NewInstance(otpl).ToLocalChecked();
+
+ obj->SetInternalField(
+ imp::kFunctionIndex
+ , New<v8::External>(reinterpret_cast<void *>(callback)));
+
+ if (!data.IsEmpty()) {
+ obj->SetInternalField(imp::kDataIndex, data);
+ }
+
+ tpl->SetCallHandler(imp::FunctionCallbackWrapper, obj);
+}
+
+
+inline void SetCallAsFunctionHandler(
+ v8::Local<v8::ObjectTemplate> tpl,
+ FunctionCallback callback,
+ v8::Local<v8::Value> data = v8::Local<v8::Value>()) {
+ HandleScope scope;
+
+ v8::Local<v8::ObjectTemplate> otpl = New<v8::ObjectTemplate>();
+ otpl->SetInternalFieldCount(imp::kFunctionFieldCount);
+ v8::Local<v8::Object> obj = NewInstance(otpl).ToLocalChecked();
+
+ obj->SetInternalField(
+ imp::kFunctionIndex
+ , New<v8::External>(reinterpret_cast<void *>(callback)));
+
+ if (!data.IsEmpty()) {
+ obj->SetInternalField(imp::kDataIndex, data);
+ }
+
+ tpl->SetCallAsFunctionHandler(imp::FunctionCallbackWrapper, obj);
+}
+
+//=== Weak Persistent Handling =================================================
+
+#include "nan_weak.h" // NOLINT(build/include)
+
+//=== ObjectWrap ===============================================================
+
+#include "nan_object_wrap.h" // NOLINT(build/include)
+
+//=== HiddenValue/Private ======================================================
+
+#include "nan_private.h" // NOLINT(build/include)
+
+//=== Export ==================================================================
+
+inline
+void
+Export(ADDON_REGISTER_FUNCTION_ARGS_TYPE target, const char *name,
+ FunctionCallback f) {
+ HandleScope scope;
+
+ Set(target, New<v8::String>(name).ToLocalChecked(),
+ GetFunction(New<v8::FunctionTemplate>(f)).ToLocalChecked());
+}
+
+//=== Tap Reverse Binding =====================================================
+
+struct Tap {
+ explicit Tap(v8::Local<v8::Value> t) : t_() {
+ HandleScope scope;
+
+ t_.Reset(To<v8::Object>(t).ToLocalChecked());
+ }
+
+ ~Tap() { t_.Reset(); } // not sure if neccessary
+
+ inline void plan(int i) {
+ HandleScope scope;
+ v8::Local<v8::Value> arg = New(i);
+ Call("plan", New(t_), 1, &arg);
+ }
+
+ inline void ok(bool isOk, const char *msg = NULL) {
+ HandleScope scope;
+ v8::Local<v8::Value> args[2];
+ args[0] = New(isOk);
+ if (msg) args[1] = New(msg).ToLocalChecked();
+ Call("ok", New(t_), msg ? 2 : 1, args);
+ }
+
+ inline void pass(const char * msg = NULL) {
+ HandleScope scope;
+ v8::Local<v8::Value> hmsg;
+ if (msg) hmsg = New(msg).ToLocalChecked();
+ Call("pass", New(t_), msg ? 1 : 0, &hmsg);
+ }
+
+ inline void end() {
+ HandleScope scope;
+ Call("end", New(t_), 0, NULL);
+ }
+
+ private:
+ Persistent<v8::Object> t_;
+};
+
+#define NAN_STRINGIZE2(x) #x
+#define NAN_STRINGIZE(x) NAN_STRINGIZE2(x)
+#define NAN_TEST_EXPRESSION(expression) \
+ ( expression ), __FILE__ ":" NAN_STRINGIZE(__LINE__) ": " #expression
+
+#define NAN_EXPORT(target, function) Export(target, #function, function)
+
+#undef TYPE_CHECK
+
+//=== Generic Maybefication ===================================================
+
+namespace imp {
+
+template <typename T> struct Maybefier;
+
+template <typename T> struct Maybefier<v8::Local<T> > {
+ inline static MaybeLocal<T> convert(v8::Local<T> v) {
+ return v;
+ }
+};
+
+template <typename T> struct Maybefier<MaybeLocal<T> > {
+ inline static MaybeLocal<T> convert(MaybeLocal<T> v) {
+ return v;
+ }
+};
+
+} // end of namespace imp
+
+template <typename T, template <typename> class MaybeMaybe>
+inline MaybeLocal<T>
+MakeMaybe(MaybeMaybe<T> v) {
+ return imp::Maybefier<MaybeMaybe<T> >::convert(v);
+}
+
+//=== TypedArrayContents =======================================================
+
+#include "nan_typedarray_contents.h" // NOLINT(build/include)
+
+//=== JSON =====================================================================
+
+#include "nan_json.h" // NOLINT(build/include)
+
+} // end of namespace Nan
+
+#endif // NAN_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_CALLBACKS_H_
+#define NAN_CALLBACKS_H_
+
+template<typename T> class FunctionCallbackInfo;
+template<typename T> class PropertyCallbackInfo;
+template<typename T> class Global;
+
+typedef void(*FunctionCallback)(const FunctionCallbackInfo<v8::Value>&);
+typedef void(*GetterCallback)
+ (v8::Local<v8::String>, const PropertyCallbackInfo<v8::Value>&);
+typedef void(*SetterCallback)(
+ v8::Local<v8::String>,
+ v8::Local<v8::Value>,
+ const PropertyCallbackInfo<void>&);
+typedef void(*PropertyGetterCallback)(
+ v8::Local<v8::String>,
+ const PropertyCallbackInfo<v8::Value>&);
+typedef void(*PropertySetterCallback)(
+ v8::Local<v8::String>,
+ v8::Local<v8::Value>,
+ const PropertyCallbackInfo<v8::Value>&);
+typedef void(*PropertyEnumeratorCallback)
+ (const PropertyCallbackInfo<v8::Array>&);
+typedef void(*PropertyDeleterCallback)(
+ v8::Local<v8::String>,
+ const PropertyCallbackInfo<v8::Boolean>&);
+typedef void(*PropertyQueryCallback)(
+ v8::Local<v8::String>,
+ const PropertyCallbackInfo<v8::Integer>&);
+typedef void(*IndexGetterCallback)(
+ uint32_t,
+ const PropertyCallbackInfo<v8::Value>&);
+typedef void(*IndexSetterCallback)(
+ uint32_t,
+ v8::Local<v8::Value>,
+ const PropertyCallbackInfo<v8::Value>&);
+typedef void(*IndexEnumeratorCallback)
+ (const PropertyCallbackInfo<v8::Array>&);
+typedef void(*IndexDeleterCallback)(
+ uint32_t,
+ const PropertyCallbackInfo<v8::Boolean>&);
+typedef void(*IndexQueryCallback)(
+ uint32_t,
+ const PropertyCallbackInfo<v8::Integer>&);
+
+namespace imp {
+typedef v8::Local<v8::AccessorSignature> Sig;
+
+static const int kDataIndex = 0;
+
+static const int kFunctionIndex = 1;
+static const int kFunctionFieldCount = 2;
+
+static const int kGetterIndex = 1;
+static const int kSetterIndex = 2;
+static const int kAccessorFieldCount = 3;
+
+static const int kPropertyGetterIndex = 1;
+static const int kPropertySetterIndex = 2;
+static const int kPropertyEnumeratorIndex = 3;
+static const int kPropertyDeleterIndex = 4;
+static const int kPropertyQueryIndex = 5;
+static const int kPropertyFieldCount = 6;
+
+static const int kIndexPropertyGetterIndex = 1;
+static const int kIndexPropertySetterIndex = 2;
+static const int kIndexPropertyEnumeratorIndex = 3;
+static const int kIndexPropertyDeleterIndex = 4;
+static const int kIndexPropertyQueryIndex = 5;
+static const int kIndexPropertyFieldCount = 6;
+
+} // end of namespace imp
+
+#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+# include "nan_callbacks_12_inl.h" // NOLINT(build/include)
+#else
+# include "nan_callbacks_pre_12_inl.h" // NOLINT(build/include)
+#endif
+
+#endif // NAN_CALLBACKS_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_CALLBACKS_12_INL_H_
+#define NAN_CALLBACKS_12_INL_H_
+
+template<typename T>
+class ReturnValue {
+ v8::ReturnValue<T> value_;
+
+ public:
+ template <class S>
+ explicit inline ReturnValue(const v8::ReturnValue<S> &value) :
+ value_(value) {}
+ template <class S>
+ explicit inline ReturnValue(const ReturnValue<S>& that)
+ : value_(that.value_) {
+ TYPE_CHECK(T, S);
+ }
+
+ // Handle setters
+ template <typename S> inline void Set(const v8::Local<S> &handle) {
+ TYPE_CHECK(T, S);
+ value_.Set(handle);
+ }
+
+ template <typename S> inline void Set(const Global<S> &handle) {
+ TYPE_CHECK(T, S);
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && \
+ (V8_MINOR_VERSION > 5 || (V8_MINOR_VERSION == 5 && \
+ defined(V8_BUILD_NUMBER) && V8_BUILD_NUMBER >= 8))))
+ value_.Set(handle);
+#else
+ value_.Set(*reinterpret_cast<const v8::Persistent<S>*>(&handle));
+ const_cast<Global<S> &>(handle).Reset();
+#endif
+ }
+
+ // Fast primitive setters
+ inline void Set(bool value) {
+ TYPE_CHECK(T, v8::Boolean);
+ value_.Set(value);
+ }
+
+ inline void Set(double i) {
+ TYPE_CHECK(T, v8::Number);
+ value_.Set(i);
+ }
+
+ inline void Set(int32_t i) {
+ TYPE_CHECK(T, v8::Integer);
+ value_.Set(i);
+ }
+
+ inline void Set(uint32_t i) {
+ TYPE_CHECK(T, v8::Integer);
+ value_.Set(i);
+ }
+
+ // Fast JS primitive setters
+ inline void SetNull() {
+ TYPE_CHECK(T, v8::Primitive);
+ value_.SetNull();
+ }
+
+ inline void SetUndefined() {
+ TYPE_CHECK(T, v8::Primitive);
+ value_.SetUndefined();
+ }
+
+ inline void SetEmptyString() {
+ TYPE_CHECK(T, v8::String);
+ value_.SetEmptyString();
+ }
+
+ // Convenience getter for isolate
+ inline v8::Isolate *GetIsolate() const {
+ return value_.GetIsolate();
+ }
+
+ // Pointer setter: Uncompilable to prevent inadvertent misuse.
+ template<typename S>
+ inline void Set(S *whatever) { TYPE_CHECK(S*, v8::Primitive); }
+};
+
+template<typename T>
+class FunctionCallbackInfo {
+ const v8::FunctionCallbackInfo<T> &info_;
+ const v8::Local<v8::Value> data_;
+
+ public:
+ explicit inline FunctionCallbackInfo(
+ const v8::FunctionCallbackInfo<T> &info
+ , v8::Local<v8::Value> data) :
+ info_(info)
+ , data_(data) {}
+
+ inline ReturnValue<T> GetReturnValue() const {
+ return ReturnValue<T>(info_.GetReturnValue());
+ }
+
+#if NODE_MAJOR_VERSION < 10
+ inline v8::Local<v8::Function> Callee() const { return info_.Callee(); }
+#endif
+ inline v8::Local<v8::Value> Data() const { return data_; }
+ inline v8::Local<v8::Object> Holder() const { return info_.Holder(); }
+ inline bool IsConstructCall() const { return info_.IsConstructCall(); }
+ inline int Length() const { return info_.Length(); }
+ inline v8::Local<v8::Value> operator[](int i) const { return info_[i]; }
+ inline v8::Local<v8::Object> This() const { return info_.This(); }
+ inline v8::Isolate *GetIsolate() const { return info_.GetIsolate(); }
+
+
+ protected:
+ static const int kHolderIndex = 0;
+ static const int kIsolateIndex = 1;
+ static const int kReturnValueDefaultValueIndex = 2;
+ static const int kReturnValueIndex = 3;
+ static const int kDataIndex = 4;
+ static const int kCalleeIndex = 5;
+ static const int kContextSaveIndex = 6;
+ static const int kArgsLength = 7;
+
+ private:
+ NAN_DISALLOW_ASSIGN_COPY_MOVE(FunctionCallbackInfo)
+};
+
+template<typename T>
+class PropertyCallbackInfo {
+ const v8::PropertyCallbackInfo<T> &info_;
+ const v8::Local<v8::Value> data_;
+
+ public:
+ explicit inline PropertyCallbackInfo(
+ const v8::PropertyCallbackInfo<T> &info
+ , const v8::Local<v8::Value> data) :
+ info_(info)
+ , data_(data) {}
+
+ inline v8::Isolate* GetIsolate() const { return info_.GetIsolate(); }
+ inline v8::Local<v8::Value> Data() const { return data_; }
+ inline v8::Local<v8::Object> This() const { return info_.This(); }
+ inline v8::Local<v8::Object> Holder() const { return info_.Holder(); }
+ inline ReturnValue<T> GetReturnValue() const {
+ return ReturnValue<T>(info_.GetReturnValue());
+ }
+
+ protected:
+ static const int kHolderIndex = 0;
+ static const int kIsolateIndex = 1;
+ static const int kReturnValueDefaultValueIndex = 2;
+ static const int kReturnValueIndex = 3;
+ static const int kDataIndex = 4;
+ static const int kThisIndex = 5;
+ static const int kArgsLength = 6;
+
+ private:
+ NAN_DISALLOW_ASSIGN_COPY_MOVE(PropertyCallbackInfo)
+};
+
+namespace imp {
+static
+void FunctionCallbackWrapper(const v8::FunctionCallbackInfo<v8::Value> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ FunctionCallback callback = reinterpret_cast<FunctionCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kFunctionIndex).As<v8::External>()->Value()));
+ FunctionCallbackInfo<v8::Value>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ callback(cbinfo);
+}
+
+typedef void (*NativeFunction)(const v8::FunctionCallbackInfo<v8::Value> &);
+
+#if NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION
+static
+void GetterCallbackWrapper(
+ v8::Local<v8::Name> property
+ , const v8::PropertyCallbackInfo<v8::Value> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Value>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ GetterCallback callback = reinterpret_cast<GetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kGetterIndex).As<v8::External>()->Value()));
+ callback(property.As<v8::String>(), cbinfo);
+}
+
+typedef void (*NativeGetter)
+ (v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value> &);
+
+static
+void SetterCallbackWrapper(
+ v8::Local<v8::Name> property
+ , v8::Local<v8::Value> value
+ , const v8::PropertyCallbackInfo<void> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<void>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ SetterCallback callback = reinterpret_cast<SetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kSetterIndex).As<v8::External>()->Value()));
+ callback(property.As<v8::String>(), value, cbinfo);
+}
+
+typedef void (*NativeSetter)(
+ v8::Local<v8::Name>
+ , v8::Local<v8::Value>
+ , const v8::PropertyCallbackInfo<void> &);
+#else
+static
+void GetterCallbackWrapper(
+ v8::Local<v8::String> property
+ , const v8::PropertyCallbackInfo<v8::Value> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Value>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ GetterCallback callback = reinterpret_cast<GetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kGetterIndex).As<v8::External>()->Value()));
+ callback(property, cbinfo);
+}
+
+typedef void (*NativeGetter)
+ (v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Value> &);
+
+static
+void SetterCallbackWrapper(
+ v8::Local<v8::String> property
+ , v8::Local<v8::Value> value
+ , const v8::PropertyCallbackInfo<void> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<void>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ SetterCallback callback = reinterpret_cast<SetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kSetterIndex).As<v8::External>()->Value()));
+ callback(property, value, cbinfo);
+}
+
+typedef void (*NativeSetter)(
+ v8::Local<v8::String>
+ , v8::Local<v8::Value>
+ , const v8::PropertyCallbackInfo<void> &);
+#endif
+
+#if NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION
+static
+void PropertyGetterCallbackWrapper(
+ v8::Local<v8::Name> property
+ , const v8::PropertyCallbackInfo<v8::Value> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Value>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ PropertyGetterCallback callback = reinterpret_cast<PropertyGetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kPropertyGetterIndex)
+ .As<v8::External>()->Value()));
+ callback(property.As<v8::String>(), cbinfo);
+}
+
+typedef void (*NativePropertyGetter)
+ (v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Value> &);
+
+static
+void PropertySetterCallbackWrapper(
+ v8::Local<v8::Name> property
+ , v8::Local<v8::Value> value
+ , const v8::PropertyCallbackInfo<v8::Value> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Value>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ PropertySetterCallback callback = reinterpret_cast<PropertySetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kPropertySetterIndex)
+ .As<v8::External>()->Value()));
+ callback(property.As<v8::String>(), value, cbinfo);
+}
+
+typedef void (*NativePropertySetter)(
+ v8::Local<v8::Name>
+ , v8::Local<v8::Value>
+ , const v8::PropertyCallbackInfo<v8::Value> &);
+
+static
+void PropertyEnumeratorCallbackWrapper(
+ const v8::PropertyCallbackInfo<v8::Array> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Array>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ PropertyEnumeratorCallback callback =
+ reinterpret_cast<PropertyEnumeratorCallback>(reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kPropertyEnumeratorIndex)
+ .As<v8::External>()->Value()));
+ callback(cbinfo);
+}
+
+typedef void (*NativePropertyEnumerator)
+ (const v8::PropertyCallbackInfo<v8::Array> &);
+
+static
+void PropertyDeleterCallbackWrapper(
+ v8::Local<v8::Name> property
+ , const v8::PropertyCallbackInfo<v8::Boolean> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Boolean>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ PropertyDeleterCallback callback = reinterpret_cast<PropertyDeleterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kPropertyDeleterIndex)
+ .As<v8::External>()->Value()));
+ callback(property.As<v8::String>(), cbinfo);
+}
+
+typedef void (NativePropertyDeleter)
+ (v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Boolean> &);
+
+static
+void PropertyQueryCallbackWrapper(
+ v8::Local<v8::Name> property
+ , const v8::PropertyCallbackInfo<v8::Integer> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Integer>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ PropertyQueryCallback callback = reinterpret_cast<PropertyQueryCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kPropertyQueryIndex)
+ .As<v8::External>()->Value()));
+ callback(property.As<v8::String>(), cbinfo);
+}
+
+typedef void (*NativePropertyQuery)
+ (v8::Local<v8::Name>, const v8::PropertyCallbackInfo<v8::Integer> &);
+#else
+static
+void PropertyGetterCallbackWrapper(
+ v8::Local<v8::String> property
+ , const v8::PropertyCallbackInfo<v8::Value> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Value>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ PropertyGetterCallback callback = reinterpret_cast<PropertyGetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kPropertyGetterIndex)
+ .As<v8::External>()->Value()));
+ callback(property, cbinfo);
+}
+
+typedef void (*NativePropertyGetter)
+ (v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Value> &);
+
+static
+void PropertySetterCallbackWrapper(
+ v8::Local<v8::String> property
+ , v8::Local<v8::Value> value
+ , const v8::PropertyCallbackInfo<v8::Value> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Value>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ PropertySetterCallback callback = reinterpret_cast<PropertySetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kPropertySetterIndex)
+ .As<v8::External>()->Value()));
+ callback(property, value, cbinfo);
+}
+
+typedef void (*NativePropertySetter)(
+ v8::Local<v8::String>
+ , v8::Local<v8::Value>
+ , const v8::PropertyCallbackInfo<v8::Value> &);
+
+static
+void PropertyEnumeratorCallbackWrapper(
+ const v8::PropertyCallbackInfo<v8::Array> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Array>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ PropertyEnumeratorCallback callback =
+ reinterpret_cast<PropertyEnumeratorCallback>(reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kPropertyEnumeratorIndex)
+ .As<v8::External>()->Value()));
+ callback(cbinfo);
+}
+
+typedef void (*NativePropertyEnumerator)
+ (const v8::PropertyCallbackInfo<v8::Array> &);
+
+static
+void PropertyDeleterCallbackWrapper(
+ v8::Local<v8::String> property
+ , const v8::PropertyCallbackInfo<v8::Boolean> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Boolean>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ PropertyDeleterCallback callback = reinterpret_cast<PropertyDeleterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kPropertyDeleterIndex)
+ .As<v8::External>()->Value()));
+ callback(property, cbinfo);
+}
+
+typedef void (NativePropertyDeleter)
+ (v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Boolean> &);
+
+static
+void PropertyQueryCallbackWrapper(
+ v8::Local<v8::String> property
+ , const v8::PropertyCallbackInfo<v8::Integer> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Integer>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ PropertyQueryCallback callback = reinterpret_cast<PropertyQueryCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kPropertyQueryIndex)
+ .As<v8::External>()->Value()));
+ callback(property, cbinfo);
+}
+
+typedef void (*NativePropertyQuery)
+ (v8::Local<v8::String>, const v8::PropertyCallbackInfo<v8::Integer> &);
+#endif
+
+static
+void IndexGetterCallbackWrapper(
+ uint32_t index, const v8::PropertyCallbackInfo<v8::Value> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Value>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ IndexGetterCallback callback = reinterpret_cast<IndexGetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kIndexPropertyGetterIndex)
+ .As<v8::External>()->Value()));
+ callback(index, cbinfo);
+}
+
+typedef void (*NativeIndexGetter)
+ (uint32_t, const v8::PropertyCallbackInfo<v8::Value> &);
+
+static
+void IndexSetterCallbackWrapper(
+ uint32_t index
+ , v8::Local<v8::Value> value
+ , const v8::PropertyCallbackInfo<v8::Value> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Value>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ IndexSetterCallback callback = reinterpret_cast<IndexSetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kIndexPropertySetterIndex)
+ .As<v8::External>()->Value()));
+ callback(index, value, cbinfo);
+}
+
+typedef void (*NativeIndexSetter)(
+ uint32_t
+ , v8::Local<v8::Value>
+ , const v8::PropertyCallbackInfo<v8::Value> &);
+
+static
+void IndexEnumeratorCallbackWrapper(
+ const v8::PropertyCallbackInfo<v8::Array> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Array>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ IndexEnumeratorCallback callback = reinterpret_cast<IndexEnumeratorCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(
+ kIndexPropertyEnumeratorIndex).As<v8::External>()->Value()));
+ callback(cbinfo);
+}
+
+typedef void (*NativeIndexEnumerator)
+ (const v8::PropertyCallbackInfo<v8::Array> &);
+
+static
+void IndexDeleterCallbackWrapper(
+ uint32_t index, const v8::PropertyCallbackInfo<v8::Boolean> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Boolean>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ IndexDeleterCallback callback = reinterpret_cast<IndexDeleterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kIndexPropertyDeleterIndex)
+ .As<v8::External>()->Value()));
+ callback(index, cbinfo);
+}
+
+typedef void (*NativeIndexDeleter)
+ (uint32_t, const v8::PropertyCallbackInfo<v8::Boolean> &);
+
+static
+void IndexQueryCallbackWrapper(
+ uint32_t index, const v8::PropertyCallbackInfo<v8::Integer> &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Integer>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ IndexQueryCallback callback = reinterpret_cast<IndexQueryCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kIndexPropertyQueryIndex)
+ .As<v8::External>()->Value()));
+ callback(index, cbinfo);
+}
+
+typedef void (*NativeIndexQuery)
+ (uint32_t, const v8::PropertyCallbackInfo<v8::Integer> &);
+} // end of namespace imp
+
+#endif // NAN_CALLBACKS_12_INL_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_CALLBACKS_PRE_12_INL_H_
+#define NAN_CALLBACKS_PRE_12_INL_H_
+
+namespace imp {
+template<typename T> class ReturnValueImp;
+} // end of namespace imp
+
+template<typename T>
+class ReturnValue {
+ v8::Isolate *isolate_;
+ v8::Persistent<T> *value_;
+ friend class imp::ReturnValueImp<T>;
+
+ public:
+ template <class S>
+ explicit inline ReturnValue(v8::Isolate *isolate, v8::Persistent<S> *p) :
+ isolate_(isolate), value_(p) {}
+ template <class S>
+ explicit inline ReturnValue(const ReturnValue<S>& that)
+ : isolate_(that.isolate_), value_(that.value_) {
+ TYPE_CHECK(T, S);
+ }
+
+ // Handle setters
+ template <typename S> inline void Set(const v8::Local<S> &handle) {
+ TYPE_CHECK(T, S);
+ value_->Dispose();
+ *value_ = v8::Persistent<T>::New(handle);
+ }
+
+ template <typename S> inline void Set(const Global<S> &handle) {
+ TYPE_CHECK(T, S);
+ value_->Dispose();
+ *value_ = v8::Persistent<T>::New(handle.persistent);
+ const_cast<Global<S> &>(handle).Reset();
+ }
+
+ // Fast primitive setters
+ inline void Set(bool value) {
+ v8::HandleScope scope;
+
+ TYPE_CHECK(T, v8::Boolean);
+ value_->Dispose();
+ *value_ = v8::Persistent<T>::New(v8::Boolean::New(value));
+ }
+
+ inline void Set(double i) {
+ v8::HandleScope scope;
+
+ TYPE_CHECK(T, v8::Number);
+ value_->Dispose();
+ *value_ = v8::Persistent<T>::New(v8::Number::New(i));
+ }
+
+ inline void Set(int32_t i) {
+ v8::HandleScope scope;
+
+ TYPE_CHECK(T, v8::Integer);
+ value_->Dispose();
+ *value_ = v8::Persistent<T>::New(v8::Int32::New(i));
+ }
+
+ inline void Set(uint32_t i) {
+ v8::HandleScope scope;
+
+ TYPE_CHECK(T, v8::Integer);
+ value_->Dispose();
+ *value_ = v8::Persistent<T>::New(v8::Uint32::NewFromUnsigned(i));
+ }
+
+ // Fast JS primitive setters
+ inline void SetNull() {
+ v8::HandleScope scope;
+
+ TYPE_CHECK(T, v8::Primitive);
+ value_->Dispose();
+ *value_ = v8::Persistent<T>::New(v8::Null());
+ }
+
+ inline void SetUndefined() {
+ v8::HandleScope scope;
+
+ TYPE_CHECK(T, v8::Primitive);
+ value_->Dispose();
+ *value_ = v8::Persistent<T>::New(v8::Undefined());
+ }
+
+ inline void SetEmptyString() {
+ v8::HandleScope scope;
+
+ TYPE_CHECK(T, v8::String);
+ value_->Dispose();
+ *value_ = v8::Persistent<T>::New(v8::String::Empty());
+ }
+
+ // Convenience getter for isolate
+ inline v8::Isolate *GetIsolate() const {
+ return isolate_;
+ }
+
+ // Pointer setter: Uncompilable to prevent inadvertent misuse.
+ template<typename S>
+ inline void Set(S *whatever) { TYPE_CHECK(S*, v8::Primitive); }
+};
+
+template<typename T>
+class FunctionCallbackInfo {
+ const v8::Arguments &args_;
+ v8::Local<v8::Value> data_;
+ ReturnValue<T> return_value_;
+ v8::Persistent<T> retval_;
+
+ public:
+ explicit inline FunctionCallbackInfo(
+ const v8::Arguments &args
+ , v8::Local<v8::Value> data) :
+ args_(args)
+ , data_(data)
+ , return_value_(args.GetIsolate(), &retval_)
+ , retval_(v8::Persistent<T>::New(v8::Undefined())) {}
+
+ inline ~FunctionCallbackInfo() {
+ retval_.Dispose();
+ retval_.Clear();
+ }
+
+ inline ReturnValue<T> GetReturnValue() const {
+ return ReturnValue<T>(return_value_);
+ }
+
+ inline v8::Local<v8::Function> Callee() const { return args_.Callee(); }
+ inline v8::Local<v8::Value> Data() const { return data_; }
+ inline v8::Local<v8::Object> Holder() const { return args_.Holder(); }
+ inline bool IsConstructCall() const { return args_.IsConstructCall(); }
+ inline int Length() const { return args_.Length(); }
+ inline v8::Local<v8::Value> operator[](int i) const { return args_[i]; }
+ inline v8::Local<v8::Object> This() const { return args_.This(); }
+ inline v8::Isolate *GetIsolate() const { return args_.GetIsolate(); }
+
+
+ protected:
+ static const int kHolderIndex = 0;
+ static const int kIsolateIndex = 1;
+ static const int kReturnValueDefaultValueIndex = 2;
+ static const int kReturnValueIndex = 3;
+ static const int kDataIndex = 4;
+ static const int kCalleeIndex = 5;
+ static const int kContextSaveIndex = 6;
+ static const int kArgsLength = 7;
+
+ private:
+ NAN_DISALLOW_ASSIGN_COPY_MOVE(FunctionCallbackInfo)
+};
+
+template<typename T>
+class PropertyCallbackInfoBase {
+ const v8::AccessorInfo &info_;
+ const v8::Local<v8::Value> data_;
+
+ public:
+ explicit inline PropertyCallbackInfoBase(
+ const v8::AccessorInfo &info
+ , const v8::Local<v8::Value> data) :
+ info_(info)
+ , data_(data) {}
+
+ inline v8::Isolate* GetIsolate() const { return info_.GetIsolate(); }
+ inline v8::Local<v8::Value> Data() const { return data_; }
+ inline v8::Local<v8::Object> This() const { return info_.This(); }
+ inline v8::Local<v8::Object> Holder() const { return info_.Holder(); }
+
+ protected:
+ static const int kHolderIndex = 0;
+ static const int kIsolateIndex = 1;
+ static const int kReturnValueDefaultValueIndex = 2;
+ static const int kReturnValueIndex = 3;
+ static const int kDataIndex = 4;
+ static const int kThisIndex = 5;
+ static const int kArgsLength = 6;
+
+ private:
+ NAN_DISALLOW_ASSIGN_COPY_MOVE(PropertyCallbackInfoBase)
+};
+
+template<typename T>
+class PropertyCallbackInfo : public PropertyCallbackInfoBase<T> {
+ ReturnValue<T> return_value_;
+ v8::Persistent<T> retval_;
+
+ public:
+ explicit inline PropertyCallbackInfo(
+ const v8::AccessorInfo &info
+ , const v8::Local<v8::Value> data) :
+ PropertyCallbackInfoBase<T>(info, data)
+ , return_value_(info.GetIsolate(), &retval_)
+ , retval_(v8::Persistent<T>::New(v8::Undefined())) {}
+
+ inline ~PropertyCallbackInfo() {
+ retval_.Dispose();
+ retval_.Clear();
+ }
+
+ inline ReturnValue<T> GetReturnValue() const { return return_value_; }
+};
+
+template<>
+class PropertyCallbackInfo<v8::Array> :
+ public PropertyCallbackInfoBase<v8::Array> {
+ ReturnValue<v8::Array> return_value_;
+ v8::Persistent<v8::Array> retval_;
+
+ public:
+ explicit inline PropertyCallbackInfo(
+ const v8::AccessorInfo &info
+ , const v8::Local<v8::Value> data) :
+ PropertyCallbackInfoBase<v8::Array>(info, data)
+ , return_value_(info.GetIsolate(), &retval_)
+ , retval_(v8::Persistent<v8::Array>::New(v8::Local<v8::Array>())) {}
+
+ inline ~PropertyCallbackInfo() {
+ retval_.Dispose();
+ retval_.Clear();
+ }
+
+ inline ReturnValue<v8::Array> GetReturnValue() const {
+ return return_value_;
+ }
+};
+
+template<>
+class PropertyCallbackInfo<v8::Boolean> :
+ public PropertyCallbackInfoBase<v8::Boolean> {
+ ReturnValue<v8::Boolean> return_value_;
+ v8::Persistent<v8::Boolean> retval_;
+
+ public:
+ explicit inline PropertyCallbackInfo(
+ const v8::AccessorInfo &info
+ , const v8::Local<v8::Value> data) :
+ PropertyCallbackInfoBase<v8::Boolean>(info, data)
+ , return_value_(info.GetIsolate(), &retval_)
+ , retval_(v8::Persistent<v8::Boolean>::New(v8::Local<v8::Boolean>())) {}
+
+ inline ~PropertyCallbackInfo() {
+ retval_.Dispose();
+ retval_.Clear();
+ }
+
+ inline ReturnValue<v8::Boolean> GetReturnValue() const {
+ return return_value_;
+ }
+};
+
+template<>
+class PropertyCallbackInfo<v8::Integer> :
+ public PropertyCallbackInfoBase<v8::Integer> {
+ ReturnValue<v8::Integer> return_value_;
+ v8::Persistent<v8::Integer> retval_;
+
+ public:
+ explicit inline PropertyCallbackInfo(
+ const v8::AccessorInfo &info
+ , const v8::Local<v8::Value> data) :
+ PropertyCallbackInfoBase<v8::Integer>(info, data)
+ , return_value_(info.GetIsolate(), &retval_)
+ , retval_(v8::Persistent<v8::Integer>::New(v8::Local<v8::Integer>())) {}
+
+ inline ~PropertyCallbackInfo() {
+ retval_.Dispose();
+ retval_.Clear();
+ }
+
+ inline ReturnValue<v8::Integer> GetReturnValue() const {
+ return return_value_;
+ }
+};
+
+namespace imp {
+template<typename T>
+class ReturnValueImp : public ReturnValue<T> {
+ public:
+ explicit ReturnValueImp(ReturnValue<T> that) :
+ ReturnValue<T>(that) {}
+ inline v8::Handle<T> Value() {
+ return *ReturnValue<T>::value_;
+ }
+};
+
+static
+v8::Handle<v8::Value> FunctionCallbackWrapper(const v8::Arguments &args) {
+ v8::Local<v8::Object> obj = args.Data().As<v8::Object>();
+ FunctionCallback callback = reinterpret_cast<FunctionCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kFunctionIndex).As<v8::External>()->Value()));
+ FunctionCallbackInfo<v8::Value>
+ cbinfo(args, obj->GetInternalField(kDataIndex));
+ callback(cbinfo);
+ return ReturnValueImp<v8::Value>(cbinfo.GetReturnValue()).Value();
+}
+
+typedef v8::Handle<v8::Value> (*NativeFunction)(const v8::Arguments &);
+
+static
+v8::Handle<v8::Value> GetterCallbackWrapper(
+ v8::Local<v8::String> property, const v8::AccessorInfo &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Value>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ GetterCallback callback = reinterpret_cast<GetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kGetterIndex).As<v8::External>()->Value()));
+ callback(property, cbinfo);
+ return ReturnValueImp<v8::Value>(cbinfo.GetReturnValue()).Value();
+}
+
+typedef v8::Handle<v8::Value> (*NativeGetter)
+ (v8::Local<v8::String>, const v8::AccessorInfo &);
+
+static
+void SetterCallbackWrapper(
+ v8::Local<v8::String> property
+ , v8::Local<v8::Value> value
+ , const v8::AccessorInfo &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<void>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ SetterCallback callback = reinterpret_cast<SetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kSetterIndex).As<v8::External>()->Value()));
+ callback(property, value, cbinfo);
+}
+
+typedef void (*NativeSetter)
+ (v8::Local<v8::String>, v8::Local<v8::Value>, const v8::AccessorInfo &);
+
+static
+v8::Handle<v8::Value> PropertyGetterCallbackWrapper(
+ v8::Local<v8::String> property, const v8::AccessorInfo &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Value>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ PropertyGetterCallback callback = reinterpret_cast<PropertyGetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kPropertyGetterIndex)
+ .As<v8::External>()->Value()));
+ callback(property, cbinfo);
+ return ReturnValueImp<v8::Value>(cbinfo.GetReturnValue()).Value();
+}
+
+typedef v8::Handle<v8::Value> (*NativePropertyGetter)
+ (v8::Local<v8::String>, const v8::AccessorInfo &);
+
+static
+v8::Handle<v8::Value> PropertySetterCallbackWrapper(
+ v8::Local<v8::String> property
+ , v8::Local<v8::Value> value
+ , const v8::AccessorInfo &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Value>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ PropertySetterCallback callback = reinterpret_cast<PropertySetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kPropertySetterIndex)
+ .As<v8::External>()->Value()));
+ callback(property, value, cbinfo);
+ return ReturnValueImp<v8::Value>(cbinfo.GetReturnValue()).Value();
+}
+
+typedef v8::Handle<v8::Value> (*NativePropertySetter)
+ (v8::Local<v8::String>, v8::Local<v8::Value>, const v8::AccessorInfo &);
+
+static
+v8::Handle<v8::Array> PropertyEnumeratorCallbackWrapper(
+ const v8::AccessorInfo &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Array>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ PropertyEnumeratorCallback callback =
+ reinterpret_cast<PropertyEnumeratorCallback>(reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kPropertyEnumeratorIndex)
+ .As<v8::External>()->Value()));
+ callback(cbinfo);
+ return ReturnValueImp<v8::Array>(cbinfo.GetReturnValue()).Value();
+}
+
+typedef v8::Handle<v8::Array> (*NativePropertyEnumerator)
+ (const v8::AccessorInfo &);
+
+static
+v8::Handle<v8::Boolean> PropertyDeleterCallbackWrapper(
+ v8::Local<v8::String> property
+ , const v8::AccessorInfo &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Boolean>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ PropertyDeleterCallback callback = reinterpret_cast<PropertyDeleterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kPropertyDeleterIndex)
+ .As<v8::External>()->Value()));
+ callback(property, cbinfo);
+ return ReturnValueImp<v8::Boolean>(cbinfo.GetReturnValue()).Value();
+}
+
+typedef v8::Handle<v8::Boolean> (NativePropertyDeleter)
+ (v8::Local<v8::String>, const v8::AccessorInfo &);
+
+static
+v8::Handle<v8::Integer> PropertyQueryCallbackWrapper(
+ v8::Local<v8::String> property, const v8::AccessorInfo &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Integer>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ PropertyQueryCallback callback = reinterpret_cast<PropertyQueryCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kPropertyQueryIndex)
+ .As<v8::External>()->Value()));
+ callback(property, cbinfo);
+ return ReturnValueImp<v8::Integer>(cbinfo.GetReturnValue()).Value();
+}
+
+typedef v8::Handle<v8::Integer> (*NativePropertyQuery)
+ (v8::Local<v8::String>, const v8::AccessorInfo &);
+
+static
+v8::Handle<v8::Value> IndexGetterCallbackWrapper(
+ uint32_t index, const v8::AccessorInfo &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Value>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ IndexGetterCallback callback = reinterpret_cast<IndexGetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kIndexPropertyGetterIndex)
+ .As<v8::External>()->Value()));
+ callback(index, cbinfo);
+ return ReturnValueImp<v8::Value>(cbinfo.GetReturnValue()).Value();
+}
+
+typedef v8::Handle<v8::Value> (*NativeIndexGetter)
+ (uint32_t, const v8::AccessorInfo &);
+
+static
+v8::Handle<v8::Value> IndexSetterCallbackWrapper(
+ uint32_t index
+ , v8::Local<v8::Value> value
+ , const v8::AccessorInfo &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Value>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ IndexSetterCallback callback = reinterpret_cast<IndexSetterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kIndexPropertySetterIndex)
+ .As<v8::External>()->Value()));
+ callback(index, value, cbinfo);
+ return ReturnValueImp<v8::Value>(cbinfo.GetReturnValue()).Value();
+}
+
+typedef v8::Handle<v8::Value> (*NativeIndexSetter)
+ (uint32_t, v8::Local<v8::Value>, const v8::AccessorInfo &);
+
+static
+v8::Handle<v8::Array> IndexEnumeratorCallbackWrapper(
+ const v8::AccessorInfo &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Array>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ IndexEnumeratorCallback callback = reinterpret_cast<IndexEnumeratorCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kIndexPropertyEnumeratorIndex)
+ .As<v8::External>()->Value()));
+ callback(cbinfo);
+ return ReturnValueImp<v8::Array>(cbinfo.GetReturnValue()).Value();
+}
+
+typedef v8::Handle<v8::Array> (*NativeIndexEnumerator)
+ (const v8::AccessorInfo &);
+
+static
+v8::Handle<v8::Boolean> IndexDeleterCallbackWrapper(
+ uint32_t index, const v8::AccessorInfo &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Boolean>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ IndexDeleterCallback callback = reinterpret_cast<IndexDeleterCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kIndexPropertyDeleterIndex)
+ .As<v8::External>()->Value()));
+ callback(index, cbinfo);
+ return ReturnValueImp<v8::Boolean>(cbinfo.GetReturnValue()).Value();
+}
+
+typedef v8::Handle<v8::Boolean> (*NativeIndexDeleter)
+ (uint32_t, const v8::AccessorInfo &);
+
+static
+v8::Handle<v8::Integer> IndexQueryCallbackWrapper(
+ uint32_t index, const v8::AccessorInfo &info) {
+ v8::Local<v8::Object> obj = info.Data().As<v8::Object>();
+ PropertyCallbackInfo<v8::Integer>
+ cbinfo(info, obj->GetInternalField(kDataIndex));
+ IndexQueryCallback callback = reinterpret_cast<IndexQueryCallback>(
+ reinterpret_cast<intptr_t>(
+ obj->GetInternalField(kIndexPropertyQueryIndex)
+ .As<v8::External>()->Value()));
+ callback(index, cbinfo);
+ return ReturnValueImp<v8::Integer>(cbinfo.GetReturnValue()).Value();
+}
+
+typedef v8::Handle<v8::Integer> (*NativeIndexQuery)
+ (uint32_t, const v8::AccessorInfo &);
+} // end of namespace imp
+
+#endif // NAN_CALLBACKS_PRE_12_INL_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_CONVERTERS_H_
+#define NAN_CONVERTERS_H_
+
+namespace imp {
+template<typename T> struct ToFactoryBase {
+ typedef MaybeLocal<T> return_t;
+};
+template<typename T> struct ValueFactoryBase { typedef Maybe<T> return_t; };
+
+template<typename T> struct ToFactory;
+
+template<>
+struct ToFactory<v8::Function> : ToFactoryBase<v8::Function> {
+ static inline return_t convert(v8::Local<v8::Value> val) {
+ if (val.IsEmpty() || !val->IsFunction()) return MaybeLocal<v8::Function>();
+ return MaybeLocal<v8::Function>(val.As<v8::Function>());
+ }
+};
+
+#define X(TYPE) \
+ template<> \
+ struct ToFactory<v8::TYPE> : ToFactoryBase<v8::TYPE> { \
+ static inline return_t convert(v8::Local<v8::Value> val); \
+ };
+
+X(Boolean)
+X(Number)
+X(String)
+X(Object)
+X(Integer)
+X(Uint32)
+X(Int32)
+
+#undef X
+
+#define X(TYPE) \
+ template<> \
+ struct ToFactory<TYPE> : ValueFactoryBase<TYPE> { \
+ static inline return_t convert(v8::Local<v8::Value> val); \
+ };
+
+X(bool)
+X(double)
+X(int64_t)
+X(uint32_t)
+X(int32_t)
+
+#undef X
+} // end of namespace imp
+
+template<typename T>
+inline
+typename imp::ToFactory<T>::return_t To(v8::Local<v8::Value> val) {
+ return imp::ToFactory<T>::convert(val);
+}
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+# include "nan_converters_43_inl.h"
+#else
+# include "nan_converters_pre_43_inl.h"
+#endif
+
+#endif // NAN_CONVERTERS_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_CONVERTERS_43_INL_H_
+#define NAN_CONVERTERS_43_INL_H_
+
+#define X(TYPE) \
+imp::ToFactory<v8::TYPE>::return_t \
+imp::ToFactory<v8::TYPE>::convert(v8::Local<v8::Value> val) { \
+ v8::Isolate *isolate = v8::Isolate::GetCurrent(); \
+ v8::EscapableHandleScope scope(isolate); \
+ return scope.Escape( \
+ val->To ## TYPE(isolate->GetCurrentContext()) \
+ .FromMaybe(v8::Local<v8::TYPE>())); \
+}
+
+X(Number)
+X(String)
+X(Object)
+X(Integer)
+X(Uint32)
+X(Int32)
+// V8 <= 7.0
+#if V8_MAJOR_VERSION < 7 || (V8_MAJOR_VERSION == 7 && V8_MINOR_VERSION == 0)
+X(Boolean)
+#else
+imp::ToFactory<v8::Boolean>::return_t \
+imp::ToFactory<v8::Boolean>::convert(v8::Local<v8::Value> val) { \
+ v8::Isolate *isolate = v8::Isolate::GetCurrent(); \
+ v8::EscapableHandleScope scope(isolate); \
+ return scope.Escape(val->ToBoolean(isolate)); \
+}
+#endif
+
+#undef X
+
+#define X(TYPE, NAME) \
+imp::ToFactory<TYPE>::return_t \
+imp::ToFactory<TYPE>::convert(v8::Local<v8::Value> val) { \
+ v8::Isolate *isolate = v8::Isolate::GetCurrent(); \
+ v8::HandleScope scope(isolate); \
+ return val->NAME ## Value(isolate->GetCurrentContext()); \
+}
+
+X(double, Number)
+X(int64_t, Integer)
+X(uint32_t, Uint32)
+X(int32_t, Int32)
+// V8 <= 7.0
+#if V8_MAJOR_VERSION < 7 || (V8_MAJOR_VERSION == 7 && V8_MINOR_VERSION == 0)
+X(bool, Boolean)
+#else
+imp::ToFactory<bool>::return_t \
+imp::ToFactory<bool>::convert(v8::Local<v8::Value> val) { \
+ v8::Isolate *isolate = v8::Isolate::GetCurrent(); \
+ v8::HandleScope scope(isolate); \
+ return Just<bool>(val->BooleanValue(isolate)); \
+}
+#endif
+
+#undef X
+
+#endif // NAN_CONVERTERS_43_INL_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_CONVERTERS_PRE_43_INL_H_
+#define NAN_CONVERTERS_PRE_43_INL_H_
+
+#define X(TYPE) \
+imp::ToFactory<v8::TYPE>::return_t \
+imp::ToFactory<v8::TYPE>::convert(v8::Local<v8::Value> val) { \
+ return val->To ## TYPE(); \
+}
+
+X(Boolean)
+X(Number)
+X(String)
+X(Object)
+X(Integer)
+X(Uint32)
+X(Int32)
+
+#undef X
+
+#define X(TYPE, NAME) \
+imp::ToFactory<TYPE>::return_t \
+imp::ToFactory<TYPE>::convert(v8::Local<v8::Value> val) { \
+ return Just(val->NAME ## Value()); \
+}
+
+X(bool, Boolean)
+X(double, Number)
+X(int64_t, Integer)
+X(uint32_t, Uint32)
+X(int32_t, Int32)
+
+#undef X
+
+#endif // NAN_CONVERTERS_PRE_43_INL_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_DEFINE_OWN_PROPERTY_HELPER_H_
+#define NAN_DEFINE_OWN_PROPERTY_HELPER_H_
+
+namespace imp {
+
+inline Maybe<bool> DefineOwnPropertyHelper(
+ v8::PropertyAttribute current
+ , v8::Handle<v8::Object> obj
+ , v8::Handle<v8::String> key
+ , v8::Handle<v8::Value> value
+ , v8::PropertyAttribute attribs = v8::None) {
+ return !(current & v8::DontDelete) || // configurable OR
+ (!(current & v8::ReadOnly) && // writable AND
+ !((attribs ^ current) & ~v8::ReadOnly)) // same excluding RO
+ ? Just<bool>(obj->ForceSet(key, value, attribs))
+ : Nothing<bool>();
+}
+
+} // end of namespace imp
+
+#endif // NAN_DEFINE_OWN_PROPERTY_HELPER_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_IMPLEMENTATION_12_INL_H_
+#define NAN_IMPLEMENTATION_12_INL_H_
+//==============================================================================
+// node v0.11 implementation
+//==============================================================================
+
+namespace imp {
+
+//=== Array ====================================================================
+
+Factory<v8::Array>::return_t
+Factory<v8::Array>::New() {
+ return v8::Array::New(v8::Isolate::GetCurrent());
+}
+
+Factory<v8::Array>::return_t
+Factory<v8::Array>::New(int length) {
+ return v8::Array::New(v8::Isolate::GetCurrent(), length);
+}
+
+//=== Boolean ==================================================================
+
+Factory<v8::Boolean>::return_t
+Factory<v8::Boolean>::New(bool value) {
+ return v8::Boolean::New(v8::Isolate::GetCurrent(), value);
+}
+
+//=== Boolean Object ===========================================================
+
+Factory<v8::BooleanObject>::return_t
+Factory<v8::BooleanObject>::New(bool value) {
+#if (NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION)
+ return v8::BooleanObject::New(
+ v8::Isolate::GetCurrent(), value).As<v8::BooleanObject>();
+#else
+ return v8::BooleanObject::New(value).As<v8::BooleanObject>();
+#endif
+}
+
+//=== Context ==================================================================
+
+Factory<v8::Context>::return_t
+Factory<v8::Context>::New( v8::ExtensionConfiguration* extensions
+ , v8::Local<v8::ObjectTemplate> tmpl
+ , v8::Local<v8::Value> obj) {
+ return v8::Context::New(v8::Isolate::GetCurrent(), extensions, tmpl, obj);
+}
+
+//=== Date =====================================================================
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+Factory<v8::Date>::return_t
+Factory<v8::Date>::New(double value) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(v8::Date::New(isolate->GetCurrentContext(), value)
+ .FromMaybe(v8::Local<v8::Value>()).As<v8::Date>());
+}
+#else
+Factory<v8::Date>::return_t
+Factory<v8::Date>::New(double value) {
+ return v8::Date::New(v8::Isolate::GetCurrent(), value).As<v8::Date>();
+}
+#endif
+
+//=== External =================================================================
+
+Factory<v8::External>::return_t
+Factory<v8::External>::New(void * value) {
+ return v8::External::New(v8::Isolate::GetCurrent(), value);
+}
+
+//=== Function =================================================================
+
+Factory<v8::Function>::return_t
+Factory<v8::Function>::New( FunctionCallback callback
+ , v8::Local<v8::Value> data) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ v8::Local<v8::ObjectTemplate> tpl = v8::ObjectTemplate::New(isolate);
+ tpl->SetInternalFieldCount(imp::kFunctionFieldCount);
+ v8::Local<v8::Object> obj = NewInstance(tpl).ToLocalChecked();
+
+ obj->SetInternalField(
+ imp::kFunctionIndex
+ , v8::External::New(isolate, reinterpret_cast<void *>(callback)));
+
+ v8::Local<v8::Value> val = v8::Local<v8::Value>::New(isolate, data);
+
+ if (!val.IsEmpty()) {
+ obj->SetInternalField(imp::kDataIndex, val);
+ }
+
+#if NODE_MAJOR_VERSION >= 10
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Function> function =
+ v8::Function::New(context, imp::FunctionCallbackWrapper, obj)
+ .ToLocalChecked();
+#else
+ v8::Local<v8::Function> function =
+ v8::Function::New(isolate, imp::FunctionCallbackWrapper, obj);
+#endif
+
+ return scope.Escape(function);
+}
+
+//=== Function Template ========================================================
+
+Factory<v8::FunctionTemplate>::return_t
+Factory<v8::FunctionTemplate>::New( FunctionCallback callback
+ , v8::Local<v8::Value> data
+ , v8::Local<v8::Signature> signature) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ if (callback) {
+ v8::EscapableHandleScope scope(isolate);
+ v8::Local<v8::ObjectTemplate> tpl = v8::ObjectTemplate::New(isolate);
+ tpl->SetInternalFieldCount(imp::kFunctionFieldCount);
+ v8::Local<v8::Object> obj = NewInstance(tpl).ToLocalChecked();
+
+ obj->SetInternalField(
+ imp::kFunctionIndex
+ , v8::External::New(isolate, reinterpret_cast<void *>(callback)));
+ v8::Local<v8::Value> val = v8::Local<v8::Value>::New(isolate, data);
+
+ if (!val.IsEmpty()) {
+ obj->SetInternalField(imp::kDataIndex, val);
+ }
+
+ return scope.Escape(v8::FunctionTemplate::New( isolate
+ , imp::FunctionCallbackWrapper
+ , obj
+ , signature));
+ } else {
+ return v8::FunctionTemplate::New(isolate, 0, data, signature);
+ }
+}
+
+//=== Number ===================================================================
+
+Factory<v8::Number>::return_t
+Factory<v8::Number>::New(double value) {
+ return v8::Number::New(v8::Isolate::GetCurrent(), value);
+}
+
+//=== Number Object ============================================================
+
+Factory<v8::NumberObject>::return_t
+Factory<v8::NumberObject>::New(double value) {
+ return v8::NumberObject::New( v8::Isolate::GetCurrent()
+ , value).As<v8::NumberObject>();
+}
+
+//=== Integer, Int32 and Uint32 ================================================
+
+template <typename T>
+typename IntegerFactory<T>::return_t
+IntegerFactory<T>::New(int32_t value) {
+ return To<T>(T::New(v8::Isolate::GetCurrent(), value));
+}
+
+template <typename T>
+typename IntegerFactory<T>::return_t
+IntegerFactory<T>::New(uint32_t value) {
+ return To<T>(T::NewFromUnsigned(v8::Isolate::GetCurrent(), value));
+}
+
+Factory<v8::Uint32>::return_t
+Factory<v8::Uint32>::New(int32_t value) {
+ return To<v8::Uint32>(
+ v8::Uint32::NewFromUnsigned(v8::Isolate::GetCurrent(), value));
+}
+
+Factory<v8::Uint32>::return_t
+Factory<v8::Uint32>::New(uint32_t value) {
+ return To<v8::Uint32>(
+ v8::Uint32::NewFromUnsigned(v8::Isolate::GetCurrent(), value));
+}
+
+//=== Object ===================================================================
+
+Factory<v8::Object>::return_t
+Factory<v8::Object>::New() {
+ return v8::Object::New(v8::Isolate::GetCurrent());
+}
+
+//=== Object Template ==========================================================
+
+Factory<v8::ObjectTemplate>::return_t
+Factory<v8::ObjectTemplate>::New() {
+ return v8::ObjectTemplate::New(v8::Isolate::GetCurrent());
+}
+
+//=== RegExp ===================================================================
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+Factory<v8::RegExp>::return_t
+Factory<v8::RegExp>::New(
+ v8::Local<v8::String> pattern
+ , v8::RegExp::Flags flags) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(
+ v8::RegExp::New(isolate->GetCurrentContext(), pattern, flags)
+ .FromMaybe(v8::Local<v8::RegExp>()));
+}
+#else
+Factory<v8::RegExp>::return_t
+Factory<v8::RegExp>::New(
+ v8::Local<v8::String> pattern
+ , v8::RegExp::Flags flags) {
+ return v8::RegExp::New(pattern, flags);
+}
+#endif
+
+//=== Script ===================================================================
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+Factory<v8::Script>::return_t
+Factory<v8::Script>::New( v8::Local<v8::String> source) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ v8::ScriptCompiler::Source src(source);
+ return scope.Escape(
+ v8::ScriptCompiler::Compile(isolate->GetCurrentContext(), &src)
+ .FromMaybe(v8::Local<v8::Script>()));
+}
+
+Factory<v8::Script>::return_t
+Factory<v8::Script>::New( v8::Local<v8::String> source
+ , v8::ScriptOrigin const& origin) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ v8::ScriptCompiler::Source src(source, origin);
+ return scope.Escape(
+ v8::ScriptCompiler::Compile(isolate->GetCurrentContext(), &src)
+ .FromMaybe(v8::Local<v8::Script>()));
+}
+#else
+Factory<v8::Script>::return_t
+Factory<v8::Script>::New( v8::Local<v8::String> source) {
+ v8::ScriptCompiler::Source src(source);
+ return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &src);
+}
+
+Factory<v8::Script>::return_t
+Factory<v8::Script>::New( v8::Local<v8::String> source
+ , v8::ScriptOrigin const& origin) {
+ v8::ScriptCompiler::Source src(source, origin);
+ return v8::ScriptCompiler::Compile(v8::Isolate::GetCurrent(), &src);
+}
+#endif
+
+//=== Signature ================================================================
+
+Factory<v8::Signature>::return_t
+Factory<v8::Signature>::New(Factory<v8::Signature>::FTH receiver) {
+ return v8::Signature::New(v8::Isolate::GetCurrent(), receiver);
+}
+
+//=== String ===================================================================
+
+Factory<v8::String>::return_t
+Factory<v8::String>::New() {
+ return v8::String::Empty(v8::Isolate::GetCurrent());
+}
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+Factory<v8::String>::return_t
+Factory<v8::String>::New(const char * value, int length) {
+ return v8::String::NewFromUtf8(
+ v8::Isolate::GetCurrent(), value, v8::NewStringType::kNormal, length);
+}
+
+Factory<v8::String>::return_t
+Factory<v8::String>::New(std::string const& value) {
+ assert(value.size() <= INT_MAX && "string too long");
+ return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(),
+ value.data(), v8::NewStringType::kNormal, static_cast<int>(value.size()));
+}
+
+Factory<v8::String>::return_t
+Factory<v8::String>::New(const uint16_t * value, int length) {
+ return v8::String::NewFromTwoByte(v8::Isolate::GetCurrent(), value,
+ v8::NewStringType::kNormal, length);
+}
+
+Factory<v8::String>::return_t
+Factory<v8::String>::New(v8::String::ExternalStringResource * value) {
+ return v8::String::NewExternalTwoByte(v8::Isolate::GetCurrent(), value);
+}
+
+Factory<v8::String>::return_t
+Factory<v8::String>::New(ExternalOneByteStringResource * value) {
+ return v8::String::NewExternalOneByte(v8::Isolate::GetCurrent(), value);
+}
+#else
+Factory<v8::String>::return_t
+Factory<v8::String>::New(const char * value, int length) {
+ return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), value,
+ v8::String::kNormalString, length);
+}
+
+Factory<v8::String>::return_t
+Factory<v8::String>::New(
+ std::string const& value) /* NOLINT(build/include_what_you_use) */ {
+ assert(value.size() <= INT_MAX && "string too long");
+ return v8::String::NewFromUtf8(v8::Isolate::GetCurrent(), value.data(),
+ v8::String::kNormalString,
+ static_cast<int>(value.size()));
+}
+
+Factory<v8::String>::return_t
+Factory<v8::String>::New(const uint16_t * value, int length) {
+ return v8::String::NewFromTwoByte(v8::Isolate::GetCurrent(), value,
+ v8::String::kNormalString, length);
+}
+
+Factory<v8::String>::return_t
+Factory<v8::String>::New(v8::String::ExternalStringResource * value) {
+ return v8::String::NewExternal(v8::Isolate::GetCurrent(), value);
+}
+
+Factory<v8::String>::return_t
+Factory<v8::String>::New(ExternalOneByteStringResource * value) {
+ return v8::String::NewExternal(v8::Isolate::GetCurrent(), value);
+}
+#endif
+
+//=== String Object ============================================================
+
+// See https://github.com/nodejs/nan/pull/811#discussion_r224594980.
+// Disable the warning as there is no way around it.
+// TODO(bnoordhuis) Use isolate-based version in Node.js v12.
+Factory<v8::StringObject>::return_t
+Factory<v8::StringObject>::New(v8::Local<v8::String> value) {
+// V8 > 7.0
+#if V8_MAJOR_VERSION > 7 || (V8_MAJOR_VERSION == 7 && V8_MINOR_VERSION > 0)
+ return v8::StringObject::New(v8::Isolate::GetCurrent(), value)
+ .As<v8::StringObject>();
+#else
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4996)
+#endif
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+ return v8::StringObject::New(value).As<v8::StringObject>();
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+#endif
+}
+
+//=== Unbound Script ===========================================================
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+Factory<v8::UnboundScript>::return_t
+Factory<v8::UnboundScript>::New(v8::Local<v8::String> source) {
+ v8::ScriptCompiler::Source src(source);
+ return v8::ScriptCompiler::CompileUnboundScript(
+ v8::Isolate::GetCurrent(), &src);
+}
+
+Factory<v8::UnboundScript>::return_t
+Factory<v8::UnboundScript>::New( v8::Local<v8::String> source
+ , v8::ScriptOrigin const& origin) {
+ v8::ScriptCompiler::Source src(source, origin);
+ return v8::ScriptCompiler::CompileUnboundScript(
+ v8::Isolate::GetCurrent(), &src);
+}
+#else
+Factory<v8::UnboundScript>::return_t
+Factory<v8::UnboundScript>::New(v8::Local<v8::String> source) {
+ v8::ScriptCompiler::Source src(source);
+ return v8::ScriptCompiler::CompileUnbound(v8::Isolate::GetCurrent(), &src);
+}
+
+Factory<v8::UnboundScript>::return_t
+Factory<v8::UnboundScript>::New( v8::Local<v8::String> source
+ , v8::ScriptOrigin const& origin) {
+ v8::ScriptCompiler::Source src(source, origin);
+ return v8::ScriptCompiler::CompileUnbound(v8::Isolate::GetCurrent(), &src);
+}
+#endif
+
+} // end of namespace imp
+
+//=== Presistents and Handles ==================================================
+
+#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+template <typename T>
+inline v8::Local<T> New(v8::Handle<T> h) {
+ return v8::Local<T>::New(v8::Isolate::GetCurrent(), h);
+}
+#endif
+
+template <typename T, typename M>
+inline v8::Local<T> New(v8::Persistent<T, M> const& p) {
+ return v8::Local<T>::New(v8::Isolate::GetCurrent(), p);
+}
+
+template <typename T, typename M>
+inline v8::Local<T> New(Persistent<T, M> const& p) {
+ return v8::Local<T>::New(v8::Isolate::GetCurrent(), p);
+}
+
+template <typename T>
+inline v8::Local<T> New(Global<T> const& p) {
+ return v8::Local<T>::New(v8::Isolate::GetCurrent(), p);
+}
+
+#endif // NAN_IMPLEMENTATION_12_INL_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_IMPLEMENTATION_PRE_12_INL_H_
+#define NAN_IMPLEMENTATION_PRE_12_INL_H_
+
+//==============================================================================
+// node v0.10 implementation
+//==============================================================================
+
+namespace imp {
+
+//=== Array ====================================================================
+
+Factory<v8::Array>::return_t
+Factory<v8::Array>::New() {
+ return v8::Array::New();
+}
+
+Factory<v8::Array>::return_t
+Factory<v8::Array>::New(int length) {
+ return v8::Array::New(length);
+}
+
+//=== Boolean ==================================================================
+
+Factory<v8::Boolean>::return_t
+Factory<v8::Boolean>::New(bool value) {
+ return v8::Boolean::New(value)->ToBoolean();
+}
+
+//=== Boolean Object ===========================================================
+
+Factory<v8::BooleanObject>::return_t
+Factory<v8::BooleanObject>::New(bool value) {
+ return v8::BooleanObject::New(value).As<v8::BooleanObject>();
+}
+
+//=== Context ==================================================================
+
+Factory<v8::Context>::return_t
+Factory<v8::Context>::New( v8::ExtensionConfiguration* extensions
+ , v8::Local<v8::ObjectTemplate> tmpl
+ , v8::Local<v8::Value> obj) {
+ v8::Persistent<v8::Context> ctx = v8::Context::New(extensions, tmpl, obj);
+ v8::Local<v8::Context> lctx = v8::Local<v8::Context>::New(ctx);
+ ctx.Dispose();
+ return lctx;
+}
+
+//=== Date =====================================================================
+
+Factory<v8::Date>::return_t
+Factory<v8::Date>::New(double value) {
+ return v8::Date::New(value).As<v8::Date>();
+}
+
+//=== External =================================================================
+
+Factory<v8::External>::return_t
+Factory<v8::External>::New(void * value) {
+ return v8::External::New(value);
+}
+
+//=== Function =================================================================
+
+Factory<v8::Function>::return_t
+Factory<v8::Function>::New( FunctionCallback callback
+ , v8::Local<v8::Value> data) {
+ v8::HandleScope scope;
+
+ return scope.Close(Factory<v8::FunctionTemplate>::New(
+ callback, data, v8::Local<v8::Signature>())
+ ->GetFunction());
+}
+
+
+//=== FunctionTemplate =========================================================
+
+Factory<v8::FunctionTemplate>::return_t
+Factory<v8::FunctionTemplate>::New( FunctionCallback callback
+ , v8::Local<v8::Value> data
+ , v8::Local<v8::Signature> signature) {
+ if (callback) {
+ v8::HandleScope scope;
+
+ v8::Local<v8::ObjectTemplate> tpl = v8::ObjectTemplate::New();
+ tpl->SetInternalFieldCount(imp::kFunctionFieldCount);
+ v8::Local<v8::Object> obj = tpl->NewInstance();
+
+ obj->SetInternalField(
+ imp::kFunctionIndex
+ , v8::External::New(reinterpret_cast<void *>(callback)));
+
+ v8::Local<v8::Value> val = v8::Local<v8::Value>::New(data);
+
+ if (!val.IsEmpty()) {
+ obj->SetInternalField(imp::kDataIndex, val);
+ }
+
+ // Note(agnat): Emulate length argument here. Unfortunately, I couldn't find
+ // a way. Have at it though...
+ return scope.Close(
+ v8::FunctionTemplate::New(imp::FunctionCallbackWrapper
+ , obj
+ , signature));
+ } else {
+ return v8::FunctionTemplate::New(0, data, signature);
+ }
+}
+
+//=== Number ===================================================================
+
+Factory<v8::Number>::return_t
+Factory<v8::Number>::New(double value) {
+ return v8::Number::New(value);
+}
+
+//=== Number Object ============================================================
+
+Factory<v8::NumberObject>::return_t
+Factory<v8::NumberObject>::New(double value) {
+ return v8::NumberObject::New(value).As<v8::NumberObject>();
+}
+
+//=== Integer, Int32 and Uint32 ================================================
+
+template <typename T>
+typename IntegerFactory<T>::return_t
+IntegerFactory<T>::New(int32_t value) {
+ return To<T>(T::New(value));
+}
+
+template <typename T>
+typename IntegerFactory<T>::return_t
+IntegerFactory<T>::New(uint32_t value) {
+ return To<T>(T::NewFromUnsigned(value));
+}
+
+Factory<v8::Uint32>::return_t
+Factory<v8::Uint32>::New(int32_t value) {
+ return To<v8::Uint32>(v8::Uint32::NewFromUnsigned(value));
+}
+
+Factory<v8::Uint32>::return_t
+Factory<v8::Uint32>::New(uint32_t value) {
+ return To<v8::Uint32>(v8::Uint32::NewFromUnsigned(value));
+}
+
+
+//=== Object ===================================================================
+
+Factory<v8::Object>::return_t
+Factory<v8::Object>::New() {
+ return v8::Object::New();
+}
+
+//=== Object Template ==========================================================
+
+Factory<v8::ObjectTemplate>::return_t
+Factory<v8::ObjectTemplate>::New() {
+ return v8::ObjectTemplate::New();
+}
+
+//=== RegExp ===================================================================
+
+Factory<v8::RegExp>::return_t
+Factory<v8::RegExp>::New(
+ v8::Local<v8::String> pattern
+ , v8::RegExp::Flags flags) {
+ return v8::RegExp::New(pattern, flags);
+}
+
+//=== Script ===================================================================
+
+Factory<v8::Script>::return_t
+Factory<v8::Script>::New( v8::Local<v8::String> source) {
+ return v8::Script::New(source);
+}
+Factory<v8::Script>::return_t
+Factory<v8::Script>::New( v8::Local<v8::String> source
+ , v8::ScriptOrigin const& origin) {
+ return v8::Script::New(source, const_cast<v8::ScriptOrigin*>(&origin));
+}
+
+//=== Signature ================================================================
+
+Factory<v8::Signature>::return_t
+Factory<v8::Signature>::New(Factory<v8::Signature>::FTH receiver) {
+ return v8::Signature::New(receiver);
+}
+
+//=== String ===================================================================
+
+Factory<v8::String>::return_t
+Factory<v8::String>::New() {
+ return v8::String::Empty();
+}
+
+Factory<v8::String>::return_t
+Factory<v8::String>::New(const char * value, int length) {
+ return v8::String::New(value, length);
+}
+
+Factory<v8::String>::return_t
+Factory<v8::String>::New(
+ std::string const& value) /* NOLINT(build/include_what_you_use) */ {
+ assert(value.size() <= INT_MAX && "string too long");
+ return v8::String::New(value.data(), static_cast<int>(value.size()));
+}
+
+Factory<v8::String>::return_t
+Factory<v8::String>::New(const uint16_t * value, int length) {
+ return v8::String::New(value, length);
+}
+
+Factory<v8::String>::return_t
+Factory<v8::String>::New(v8::String::ExternalStringResource * value) {
+ return v8::String::NewExternal(value);
+}
+
+Factory<v8::String>::return_t
+Factory<v8::String>::New(v8::String::ExternalAsciiStringResource * value) {
+ return v8::String::NewExternal(value);
+}
+
+//=== String Object ============================================================
+
+Factory<v8::StringObject>::return_t
+Factory<v8::StringObject>::New(v8::Local<v8::String> value) {
+ return v8::StringObject::New(value).As<v8::StringObject>();
+}
+
+} // end of namespace imp
+
+//=== Presistents and Handles ==================================================
+
+template <typename T>
+inline v8::Local<T> New(v8::Handle<T> h) {
+ return v8::Local<T>::New(h);
+}
+
+template <typename T>
+inline v8::Local<T> New(v8::Persistent<T> const& p) {
+ return v8::Local<T>::New(p);
+}
+
+template <typename T, typename M>
+inline v8::Local<T> New(Persistent<T, M> const& p) {
+ return v8::Local<T>::New(p.persistent);
+}
+
+template <typename T>
+inline v8::Local<T> New(Global<T> const& p) {
+ return v8::Local<T>::New(p.persistent);
+}
+
+#endif // NAN_IMPLEMENTATION_PRE_12_INL_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_JSON_H_
+#define NAN_JSON_H_
+
+#if NODE_MODULE_VERSION < NODE_0_12_MODULE_VERSION
+#define NAN_JSON_H_NEED_PARSE 1
+#else
+#define NAN_JSON_H_NEED_PARSE 0
+#endif // NODE_MODULE_VERSION < NODE_0_12_MODULE_VERSION
+
+#if NODE_MODULE_VERSION >= NODE_7_0_MODULE_VERSION
+#define NAN_JSON_H_NEED_STRINGIFY 0
+#else
+#define NAN_JSON_H_NEED_STRINGIFY 1
+#endif // NODE_MODULE_VERSION >= NODE_7_0_MODULE_VERSION
+
+class JSON {
+ public:
+ JSON() {
+#if NAN_JSON_H_NEED_PARSE + NAN_JSON_H_NEED_STRINGIFY
+ Nan::HandleScope scope;
+
+ Nan::MaybeLocal<v8::Value> maybe_global_json = Nan::Get(
+ Nan::GetCurrentContext()->Global(),
+ Nan::New("JSON").ToLocalChecked()
+ );
+
+ assert(!maybe_global_json.IsEmpty() && "global JSON is empty");
+ v8::Local<v8::Value> val_global_json = maybe_global_json.ToLocalChecked();
+
+ assert(val_global_json->IsObject() && "global JSON is not an object");
+ Nan::MaybeLocal<v8::Object> maybe_obj_global_json =
+ Nan::To<v8::Object>(val_global_json);
+
+ assert(!maybe_obj_global_json.IsEmpty() && "global JSON object is empty");
+ v8::Local<v8::Object> global_json = maybe_obj_global_json.ToLocalChecked();
+
+#if NAN_JSON_H_NEED_PARSE
+ Nan::MaybeLocal<v8::Value> maybe_parse_method = Nan::Get(
+ global_json, Nan::New("parse").ToLocalChecked()
+ );
+
+ assert(!maybe_parse_method.IsEmpty() && "JSON.parse is empty");
+ v8::Local<v8::Value> parse_method = maybe_parse_method.ToLocalChecked();
+
+ assert(parse_method->IsFunction() && "JSON.parse is not a function");
+ parse_cb_.Reset(parse_method.As<v8::Function>());
+#endif // NAN_JSON_H_NEED_PARSE
+
+#if NAN_JSON_H_NEED_STRINGIFY
+ Nan::MaybeLocal<v8::Value> maybe_stringify_method = Nan::Get(
+ global_json, Nan::New("stringify").ToLocalChecked()
+ );
+
+ assert(!maybe_stringify_method.IsEmpty() && "JSON.stringify is empty");
+ v8::Local<v8::Value> stringify_method =
+ maybe_stringify_method.ToLocalChecked();
+
+ assert(
+ stringify_method->IsFunction() && "JSON.stringify is not a function"
+ );
+ stringify_cb_.Reset(stringify_method.As<v8::Function>());
+#endif // NAN_JSON_H_NEED_STRINGIFY
+#endif // NAN_JSON_H_NEED_PARSE + NAN_JSON_H_NEED_STRINGIFY
+ }
+
+ inline
+ Nan::MaybeLocal<v8::Value> Parse(v8::Local<v8::String> json_string) {
+ Nan::EscapableHandleScope scope;
+#if NAN_JSON_H_NEED_PARSE
+ return scope.Escape(parse(json_string));
+#else
+ Nan::MaybeLocal<v8::Value> result;
+#if NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION && \
+ NODE_MODULE_VERSION <= IOJS_2_0_MODULE_VERSION
+ result = v8::JSON::Parse(json_string);
+#else
+#if NODE_MODULE_VERSION > NODE_6_0_MODULE_VERSION
+ v8::Local<v8::Context> context_or_isolate = Nan::GetCurrentContext();
+#else
+ v8::Isolate* context_or_isolate = v8::Isolate::GetCurrent();
+#endif // NODE_MODULE_VERSION > NODE_6_0_MODULE_VERSION
+ result = v8::JSON::Parse(context_or_isolate, json_string);
+#endif // NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION &&
+ // NODE_MODULE_VERSION <= IOJS_2_0_MODULE_VERSION
+ if (result.IsEmpty()) return v8::Local<v8::Value>();
+ return scope.Escape(result.ToLocalChecked());
+#endif // NAN_JSON_H_NEED_PARSE
+ }
+
+ inline
+ Nan::MaybeLocal<v8::String> Stringify(v8::Local<v8::Object> json_object) {
+ Nan::EscapableHandleScope scope;
+ Nan::MaybeLocal<v8::String> result =
+#if NAN_JSON_H_NEED_STRINGIFY
+ Nan::To<v8::String>(stringify(json_object));
+#else
+ v8::JSON::Stringify(Nan::GetCurrentContext(), json_object);
+#endif // NAN_JSON_H_NEED_STRINGIFY
+ if (result.IsEmpty()) return v8::Local<v8::String>();
+ return scope.Escape(result.ToLocalChecked());
+ }
+
+ inline
+ Nan::MaybeLocal<v8::String> Stringify(v8::Local<v8::Object> json_object,
+ v8::Local<v8::String> gap) {
+ Nan::EscapableHandleScope scope;
+ Nan::MaybeLocal<v8::String> result =
+#if NAN_JSON_H_NEED_STRINGIFY
+ Nan::To<v8::String>(stringify(json_object, gap));
+#else
+ v8::JSON::Stringify(Nan::GetCurrentContext(), json_object, gap);
+#endif // NAN_JSON_H_NEED_STRINGIFY
+ if (result.IsEmpty()) return v8::Local<v8::String>();
+ return scope.Escape(result.ToLocalChecked());
+ }
+
+ private:
+ NAN_DISALLOW_ASSIGN_COPY_MOVE(JSON)
+#if NAN_JSON_H_NEED_PARSE
+ Nan::Callback parse_cb_;
+#endif // NAN_JSON_H_NEED_PARSE
+#if NAN_JSON_H_NEED_STRINGIFY
+ Nan::Callback stringify_cb_;
+#endif // NAN_JSON_H_NEED_STRINGIFY
+
+#if NAN_JSON_H_NEED_PARSE
+ inline v8::Local<v8::Value> parse(v8::Local<v8::Value> arg) {
+ assert(!parse_cb_.IsEmpty() && "parse_cb_ is empty");
+ AsyncResource resource("nan:JSON.parse");
+ return parse_cb_.Call(1, &arg, &resource).FromMaybe(v8::Local<v8::Value>());
+ }
+#endif // NAN_JSON_H_NEED_PARSE
+
+#if NAN_JSON_H_NEED_STRINGIFY
+ inline v8::Local<v8::Value> stringify(v8::Local<v8::Value> arg) {
+ assert(!stringify_cb_.IsEmpty() && "stringify_cb_ is empty");
+ AsyncResource resource("nan:JSON.stringify");
+ return stringify_cb_.Call(1, &arg, &resource)
+ .FromMaybe(v8::Local<v8::Value>());
+ }
+
+ inline v8::Local<v8::Value> stringify(v8::Local<v8::Value> arg,
+ v8::Local<v8::String> gap) {
+ assert(!stringify_cb_.IsEmpty() && "stringify_cb_ is empty");
+
+ v8::Local<v8::Value> argv[] = {
+ arg,
+ Nan::Null(),
+ gap
+ };
+ AsyncResource resource("nan:JSON.stringify");
+ return stringify_cb_.Call(3, argv, &resource)
+ .FromMaybe(v8::Local<v8::Value>());
+ }
+#endif // NAN_JSON_H_NEED_STRINGIFY
+};
+
+#endif // NAN_JSON_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_MAYBE_43_INL_H_
+#define NAN_MAYBE_43_INL_H_
+
+template<typename T>
+using MaybeLocal = v8::MaybeLocal<T>;
+
+inline
+MaybeLocal<v8::String> ToDetailString(v8::Local<v8::Value> val) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(val->ToDetailString(isolate->GetCurrentContext())
+ .FromMaybe(v8::Local<v8::String>()));
+}
+
+inline
+MaybeLocal<v8::Uint32> ToArrayIndex(v8::Local<v8::Value> val) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(val->ToArrayIndex(isolate->GetCurrentContext())
+ .FromMaybe(v8::Local<v8::Uint32>()));
+}
+
+inline
+Maybe<bool> Equals(v8::Local<v8::Value> a, v8::Local<v8::Value>(b)) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return a->Equals(isolate->GetCurrentContext(), b);
+}
+
+inline
+MaybeLocal<v8::Object> NewInstance(v8::Local<v8::Function> h) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(h->NewInstance(isolate->GetCurrentContext())
+ .FromMaybe(v8::Local<v8::Object>()));
+}
+
+inline
+MaybeLocal<v8::Object> NewInstance(
+ v8::Local<v8::Function> h
+ , int argc
+ , v8::Local<v8::Value> argv[]) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(h->NewInstance(isolate->GetCurrentContext(), argc, argv)
+ .FromMaybe(v8::Local<v8::Object>()));
+}
+
+inline
+MaybeLocal<v8::Object> NewInstance(v8::Local<v8::ObjectTemplate> h) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(h->NewInstance(isolate->GetCurrentContext())
+ .FromMaybe(v8::Local<v8::Object>()));
+}
+
+
+inline MaybeLocal<v8::Function> GetFunction(
+ v8::Local<v8::FunctionTemplate> t) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(t->GetFunction(isolate->GetCurrentContext())
+ .FromMaybe(v8::Local<v8::Function>()));
+}
+
+inline Maybe<bool> Set(
+ v8::Local<v8::Object> obj
+ , v8::Local<v8::Value> key
+ , v8::Local<v8::Value> value) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return obj->Set(isolate->GetCurrentContext(), key, value);
+}
+
+inline Maybe<bool> Set(
+ v8::Local<v8::Object> obj
+ , uint32_t index
+ , v8::Local<v8::Value> value) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return obj->Set(isolate->GetCurrentContext(), index, value);
+}
+
+#if NODE_MODULE_VERSION < NODE_4_0_MODULE_VERSION
+#include "nan_define_own_property_helper.h" // NOLINT(build/include)
+#endif
+
+inline Maybe<bool> DefineOwnProperty(
+ v8::Local<v8::Object> obj
+ , v8::Local<v8::String> key
+ , v8::Local<v8::Value> value
+ , v8::PropertyAttribute attribs = v8::None) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+#if NODE_MODULE_VERSION >= NODE_4_0_MODULE_VERSION
+ return obj->DefineOwnProperty(isolate->GetCurrentContext(), key, value,
+ attribs);
+#else
+ Maybe<v8::PropertyAttribute> maybeCurrent =
+ obj->GetPropertyAttributes(isolate->GetCurrentContext(), key);
+ if (maybeCurrent.IsNothing()) {
+ return Nothing<bool>();
+ }
+ v8::PropertyAttribute current = maybeCurrent.FromJust();
+ return imp::DefineOwnPropertyHelper(current, obj, key, value, attribs);
+#endif
+}
+
+NAN_DEPRECATED inline Maybe<bool> ForceSet(
+ v8::Local<v8::Object> obj
+ , v8::Local<v8::Value> key
+ , v8::Local<v8::Value> value
+ , v8::PropertyAttribute attribs = v8::None) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+#if NODE_MODULE_VERSION >= NODE_9_0_MODULE_VERSION
+ return key->IsName()
+ ? obj->DefineOwnProperty(isolate->GetCurrentContext(),
+ key.As<v8::Name>(), value, attribs)
+ : Nothing<bool>();
+#else
+ return obj->ForceSet(isolate->GetCurrentContext(), key, value, attribs);
+#endif
+}
+
+inline MaybeLocal<v8::Value> Get(
+ v8::Local<v8::Object> obj
+ , v8::Local<v8::Value> key) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(obj->Get(isolate->GetCurrentContext(), key)
+ .FromMaybe(v8::Local<v8::Value>()));
+}
+
+inline
+MaybeLocal<v8::Value> Get(v8::Local<v8::Object> obj, uint32_t index) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(obj->Get(isolate->GetCurrentContext(), index)
+ .FromMaybe(v8::Local<v8::Value>()));
+}
+
+inline v8::PropertyAttribute GetPropertyAttributes(
+ v8::Local<v8::Object> obj
+ , v8::Local<v8::Value> key) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return obj->GetPropertyAttributes(isolate->GetCurrentContext(), key)
+ .FromJust();
+}
+
+inline Maybe<bool> Has(
+ v8::Local<v8::Object> obj
+ , v8::Local<v8::String> key) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return obj->Has(isolate->GetCurrentContext(), key);
+}
+
+inline Maybe<bool> Has(v8::Local<v8::Object> obj, uint32_t index) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return obj->Has(isolate->GetCurrentContext(), index);
+}
+
+inline Maybe<bool> Delete(
+ v8::Local<v8::Object> obj
+ , v8::Local<v8::String> key) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return obj->Delete(isolate->GetCurrentContext(), key);
+}
+
+inline
+Maybe<bool> Delete(v8::Local<v8::Object> obj, uint32_t index) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return obj->Delete(isolate->GetCurrentContext(), index);
+}
+
+inline
+MaybeLocal<v8::Array> GetPropertyNames(v8::Local<v8::Object> obj) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(obj->GetPropertyNames(isolate->GetCurrentContext())
+ .FromMaybe(v8::Local<v8::Array>()));
+}
+
+inline
+MaybeLocal<v8::Array> GetOwnPropertyNames(v8::Local<v8::Object> obj) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(obj->GetOwnPropertyNames(isolate->GetCurrentContext())
+ .FromMaybe(v8::Local<v8::Array>()));
+}
+
+inline Maybe<bool> SetPrototype(
+ v8::Local<v8::Object> obj
+ , v8::Local<v8::Value> prototype) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return obj->SetPrototype(isolate->GetCurrentContext(), prototype);
+}
+
+inline MaybeLocal<v8::String> ObjectProtoToString(
+ v8::Local<v8::Object> obj) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(obj->ObjectProtoToString(isolate->GetCurrentContext())
+ .FromMaybe(v8::Local<v8::String>()));
+}
+
+inline Maybe<bool> HasOwnProperty(
+ v8::Local<v8::Object> obj
+ , v8::Local<v8::String> key) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return obj->HasOwnProperty(isolate->GetCurrentContext(), key);
+}
+
+inline Maybe<bool> HasRealNamedProperty(
+ v8::Local<v8::Object> obj
+ , v8::Local<v8::String> key) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return obj->HasRealNamedProperty(isolate->GetCurrentContext(), key);
+}
+
+inline Maybe<bool> HasRealIndexedProperty(
+ v8::Local<v8::Object> obj
+ , uint32_t index) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return obj->HasRealIndexedProperty(isolate->GetCurrentContext(), index);
+}
+
+inline Maybe<bool> HasRealNamedCallbackProperty(
+ v8::Local<v8::Object> obj
+ , v8::Local<v8::String> key) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return obj->HasRealNamedCallbackProperty(isolate->GetCurrentContext(), key);
+}
+
+inline MaybeLocal<v8::Value> GetRealNamedPropertyInPrototypeChain(
+ v8::Local<v8::Object> obj
+ , v8::Local<v8::String> key) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(obj->GetRealNamedPropertyInPrototypeChain(
+ isolate->GetCurrentContext(), key)
+ .FromMaybe(v8::Local<v8::Value>()));
+}
+
+inline MaybeLocal<v8::Value> GetRealNamedProperty(
+ v8::Local<v8::Object> obj
+ , v8::Local<v8::String> key) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(
+ obj->GetRealNamedProperty(isolate->GetCurrentContext(), key)
+ .FromMaybe(v8::Local<v8::Value>()));
+}
+
+inline MaybeLocal<v8::Value> CallAsFunction(
+ v8::Local<v8::Object> obj
+ , v8::Local<v8::Object> recv
+ , int argc
+ , v8::Local<v8::Value> argv[]) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(
+ obj->CallAsFunction(isolate->GetCurrentContext(), recv, argc, argv)
+ .FromMaybe(v8::Local<v8::Value>()));
+}
+
+inline MaybeLocal<v8::Value> CallAsConstructor(
+ v8::Local<v8::Object> obj
+ , int argc, v8::Local<v8::Value> argv[]) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(
+ obj->CallAsConstructor(isolate->GetCurrentContext(), argc, argv)
+ .FromMaybe(v8::Local<v8::Value>()));
+}
+
+inline
+MaybeLocal<v8::String> GetSourceLine(v8::Local<v8::Message> msg) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(msg->GetSourceLine(isolate->GetCurrentContext())
+ .FromMaybe(v8::Local<v8::String>()));
+}
+
+inline Maybe<int> GetLineNumber(v8::Local<v8::Message> msg) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return msg->GetLineNumber(isolate->GetCurrentContext());
+}
+
+inline Maybe<int> GetStartColumn(v8::Local<v8::Message> msg) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return msg->GetStartColumn(isolate->GetCurrentContext());
+}
+
+inline Maybe<int> GetEndColumn(v8::Local<v8::Message> msg) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::HandleScope scope(isolate);
+ return msg->GetEndColumn(isolate->GetCurrentContext());
+}
+
+inline MaybeLocal<v8::Object> CloneElementAt(
+ v8::Local<v8::Array> array
+ , uint32_t index) {
+#if (NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION)
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Value> elem;
+ v8::Local<v8::Object> obj;
+ if (!array->Get(context, index).ToLocal(&elem)) {
+ return scope.Escape(obj);
+ }
+ if (!elem->ToObject(context).ToLocal(&obj)) {
+ return scope.Escape(v8::Local<v8::Object>());
+ }
+ return scope.Escape(obj->Clone());
+#else
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(array->CloneElementAt(isolate->GetCurrentContext(), index)
+ .FromMaybe(v8::Local<v8::Object>()));
+#endif
+}
+
+inline MaybeLocal<v8::Value> Call(
+ v8::Local<v8::Function> fun
+ , v8::Local<v8::Object> recv
+ , int argc
+ , v8::Local<v8::Value> argv[]) {
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ return scope.Escape(fun->Call(isolate->GetCurrentContext(), recv, argc, argv)
+ .FromMaybe(v8::Local<v8::Value>()));
+}
+
+#endif // NAN_MAYBE_43_INL_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_MAYBE_PRE_43_INL_H_
+#define NAN_MAYBE_PRE_43_INL_H_
+
+template<typename T>
+class MaybeLocal {
+ public:
+ inline MaybeLocal() : val_(v8::Local<T>()) {}
+
+ template<typename S>
+# if NODE_MODULE_VERSION >= NODE_0_12_MODULE_VERSION
+ inline
+ MaybeLocal(v8::Local<S> that) : val_(that) {} // NOLINT(runtime/explicit)
+# else
+ inline
+ MaybeLocal(v8::Local<S> that) : // NOLINT(runtime/explicit)
+ val_(*reinterpret_cast<v8::Local<T>*>(&that)) {}
+# endif
+
+ inline bool IsEmpty() const { return val_.IsEmpty(); }
+
+ template<typename S>
+ inline bool ToLocal(v8::Local<S> *out) const {
+ *out = val_;
+ return !IsEmpty();
+ }
+
+ inline v8::Local<T> ToLocalChecked() const {
+#if defined(V8_ENABLE_CHECKS)
+ assert(!IsEmpty() && "ToLocalChecked is Empty");
+#endif // V8_ENABLE_CHECKS
+ return val_;
+ }
+
+ template<typename S>
+ inline v8::Local<S> FromMaybe(v8::Local<S> default_value) const {
+ return IsEmpty() ? default_value : v8::Local<S>(val_);
+ }
+
+ private:
+ v8::Local<T> val_;
+};
+
+inline
+MaybeLocal<v8::String> ToDetailString(v8::Handle<v8::Value> val) {
+ return MaybeLocal<v8::String>(val->ToDetailString());
+}
+
+inline
+MaybeLocal<v8::Uint32> ToArrayIndex(v8::Handle<v8::Value> val) {
+ return MaybeLocal<v8::Uint32>(val->ToArrayIndex());
+}
+
+inline
+Maybe<bool> Equals(v8::Handle<v8::Value> a, v8::Handle<v8::Value>(b)) {
+ return Just<bool>(a->Equals(b));
+}
+
+inline
+MaybeLocal<v8::Object> NewInstance(v8::Handle<v8::Function> h) {
+ return MaybeLocal<v8::Object>(h->NewInstance());
+}
+
+inline
+MaybeLocal<v8::Object> NewInstance(
+ v8::Local<v8::Function> h
+ , int argc
+ , v8::Local<v8::Value> argv[]) {
+ return MaybeLocal<v8::Object>(h->NewInstance(argc, argv));
+}
+
+inline
+MaybeLocal<v8::Object> NewInstance(v8::Handle<v8::ObjectTemplate> h) {
+ return MaybeLocal<v8::Object>(h->NewInstance());
+}
+
+inline
+MaybeLocal<v8::Function> GetFunction(v8::Handle<v8::FunctionTemplate> t) {
+ return MaybeLocal<v8::Function>(t->GetFunction());
+}
+
+inline Maybe<bool> Set(
+ v8::Handle<v8::Object> obj
+ , v8::Handle<v8::Value> key
+ , v8::Handle<v8::Value> value) {
+ return Just<bool>(obj->Set(key, value));
+}
+
+inline Maybe<bool> Set(
+ v8::Handle<v8::Object> obj
+ , uint32_t index
+ , v8::Handle<v8::Value> value) {
+ return Just<bool>(obj->Set(index, value));
+}
+
+#include "nan_define_own_property_helper.h" // NOLINT(build/include)
+
+inline Maybe<bool> DefineOwnProperty(
+ v8::Handle<v8::Object> obj
+ , v8::Handle<v8::String> key
+ , v8::Handle<v8::Value> value
+ , v8::PropertyAttribute attribs = v8::None) {
+ v8::PropertyAttribute current = obj->GetPropertyAttributes(key);
+ return imp::DefineOwnPropertyHelper(current, obj, key, value, attribs);
+}
+
+NAN_DEPRECATED inline Maybe<bool> ForceSet(
+ v8::Handle<v8::Object> obj
+ , v8::Handle<v8::Value> key
+ , v8::Handle<v8::Value> value
+ , v8::PropertyAttribute attribs = v8::None) {
+ return Just<bool>(obj->ForceSet(key, value, attribs));
+}
+
+inline MaybeLocal<v8::Value> Get(
+ v8::Handle<v8::Object> obj
+ , v8::Handle<v8::Value> key) {
+ return MaybeLocal<v8::Value>(obj->Get(key));
+}
+
+inline MaybeLocal<v8::Value> Get(
+ v8::Handle<v8::Object> obj
+ , uint32_t index) {
+ return MaybeLocal<v8::Value>(obj->Get(index));
+}
+
+inline Maybe<v8::PropertyAttribute> GetPropertyAttributes(
+ v8::Handle<v8::Object> obj
+ , v8::Handle<v8::Value> key) {
+ return Just<v8::PropertyAttribute>(obj->GetPropertyAttributes(key));
+}
+
+inline Maybe<bool> Has(
+ v8::Handle<v8::Object> obj
+ , v8::Handle<v8::String> key) {
+ return Just<bool>(obj->Has(key));
+}
+
+inline Maybe<bool> Has(
+ v8::Handle<v8::Object> obj
+ , uint32_t index) {
+ return Just<bool>(obj->Has(index));
+}
+
+inline Maybe<bool> Delete(
+ v8::Handle<v8::Object> obj
+ , v8::Handle<v8::String> key) {
+ return Just<bool>(obj->Delete(key));
+}
+
+inline Maybe<bool> Delete(
+ v8::Handle<v8::Object> obj
+ , uint32_t index) {
+ return Just<bool>(obj->Delete(index));
+}
+
+inline
+MaybeLocal<v8::Array> GetPropertyNames(v8::Handle<v8::Object> obj) {
+ return MaybeLocal<v8::Array>(obj->GetPropertyNames());
+}
+
+inline
+MaybeLocal<v8::Array> GetOwnPropertyNames(v8::Handle<v8::Object> obj) {
+ return MaybeLocal<v8::Array>(obj->GetOwnPropertyNames());
+}
+
+inline Maybe<bool> SetPrototype(
+ v8::Handle<v8::Object> obj
+ , v8::Handle<v8::Value> prototype) {
+ return Just<bool>(obj->SetPrototype(prototype));
+}
+
+inline MaybeLocal<v8::String> ObjectProtoToString(
+ v8::Handle<v8::Object> obj) {
+ return MaybeLocal<v8::String>(obj->ObjectProtoToString());
+}
+
+inline Maybe<bool> HasOwnProperty(
+ v8::Handle<v8::Object> obj
+ , v8::Handle<v8::String> key) {
+ return Just<bool>(obj->HasOwnProperty(key));
+}
+
+inline Maybe<bool> HasRealNamedProperty(
+ v8::Handle<v8::Object> obj
+ , v8::Handle<v8::String> key) {
+ return Just<bool>(obj->HasRealNamedProperty(key));
+}
+
+inline Maybe<bool> HasRealIndexedProperty(
+ v8::Handle<v8::Object> obj
+ , uint32_t index) {
+ return Just<bool>(obj->HasRealIndexedProperty(index));
+}
+
+inline Maybe<bool> HasRealNamedCallbackProperty(
+ v8::Handle<v8::Object> obj
+ , v8::Handle<v8::String> key) {
+ return Just<bool>(obj->HasRealNamedCallbackProperty(key));
+}
+
+inline MaybeLocal<v8::Value> GetRealNamedPropertyInPrototypeChain(
+ v8::Handle<v8::Object> obj
+ , v8::Handle<v8::String> key) {
+ return MaybeLocal<v8::Value>(
+ obj->GetRealNamedPropertyInPrototypeChain(key));
+}
+
+inline MaybeLocal<v8::Value> GetRealNamedProperty(
+ v8::Handle<v8::Object> obj
+ , v8::Handle<v8::String> key) {
+ return MaybeLocal<v8::Value>(obj->GetRealNamedProperty(key));
+}
+
+inline MaybeLocal<v8::Value> CallAsFunction(
+ v8::Handle<v8::Object> obj
+ , v8::Handle<v8::Object> recv
+ , int argc
+ , v8::Handle<v8::Value> argv[]) {
+ return MaybeLocal<v8::Value>(obj->CallAsFunction(recv, argc, argv));
+}
+
+inline MaybeLocal<v8::Value> CallAsConstructor(
+ v8::Handle<v8::Object> obj
+ , int argc
+ , v8::Local<v8::Value> argv[]) {
+ return MaybeLocal<v8::Value>(obj->CallAsConstructor(argc, argv));
+}
+
+inline
+MaybeLocal<v8::String> GetSourceLine(v8::Handle<v8::Message> msg) {
+ return MaybeLocal<v8::String>(msg->GetSourceLine());
+}
+
+inline Maybe<int> GetLineNumber(v8::Handle<v8::Message> msg) {
+ return Just<int>(msg->GetLineNumber());
+}
+
+inline Maybe<int> GetStartColumn(v8::Handle<v8::Message> msg) {
+ return Just<int>(msg->GetStartColumn());
+}
+
+inline Maybe<int> GetEndColumn(v8::Handle<v8::Message> msg) {
+ return Just<int>(msg->GetEndColumn());
+}
+
+inline MaybeLocal<v8::Object> CloneElementAt(
+ v8::Handle<v8::Array> array
+ , uint32_t index) {
+ return MaybeLocal<v8::Object>(array->CloneElementAt(index));
+}
+
+inline MaybeLocal<v8::Value> Call(
+ v8::Local<v8::Function> fun
+ , v8::Local<v8::Object> recv
+ , int argc
+ , v8::Local<v8::Value> argv[]) {
+ return MaybeLocal<v8::Value>(fun->Call(recv, argc, argv));
+}
+
+#endif // NAN_MAYBE_PRE_43_INL_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_NEW_H_
+#define NAN_NEW_H_
+
+namespace imp { // scnr
+
+// TODO(agnat): Generalize
+template <typename T> v8::Local<T> To(v8::Local<v8::Integer> i);
+
+template <>
+inline
+v8::Local<v8::Integer>
+To<v8::Integer>(v8::Local<v8::Integer> i) {
+ return Nan::To<v8::Integer>(i).ToLocalChecked();
+}
+
+template <>
+inline
+v8::Local<v8::Int32>
+To<v8::Int32>(v8::Local<v8::Integer> i) {
+ return Nan::To<v8::Int32>(i).ToLocalChecked();
+}
+
+template <>
+inline
+v8::Local<v8::Uint32>
+To<v8::Uint32>(v8::Local<v8::Integer> i) {
+ return Nan::To<v8::Uint32>(i).ToLocalChecked();
+}
+
+template <typename T> struct FactoryBase {
+ typedef v8::Local<T> return_t;
+};
+
+template <typename T> struct MaybeFactoryBase {
+ typedef MaybeLocal<T> return_t;
+};
+
+template <typename T> struct Factory;
+
+template <>
+struct Factory<v8::Array> : FactoryBase<v8::Array> {
+ static inline return_t New();
+ static inline return_t New(int length);
+};
+
+template <>
+struct Factory<v8::Boolean> : FactoryBase<v8::Boolean> {
+ static inline return_t New(bool value);
+};
+
+template <>
+struct Factory<v8::BooleanObject> : FactoryBase<v8::BooleanObject> {
+ static inline return_t New(bool value);
+};
+
+template <>
+struct Factory<v8::Context> : FactoryBase<v8::Context> {
+ static inline
+ return_t
+ New( v8::ExtensionConfiguration* extensions = NULL
+ , v8::Local<v8::ObjectTemplate> tmpl = v8::Local<v8::ObjectTemplate>()
+ , v8::Local<v8::Value> obj = v8::Local<v8::Value>());
+};
+
+template <>
+struct Factory<v8::Date> : MaybeFactoryBase<v8::Date> {
+ static inline return_t New(double value);
+};
+
+template <>
+struct Factory<v8::External> : FactoryBase<v8::External> {
+ static inline return_t New(void *value);
+};
+
+template <>
+struct Factory<v8::Function> : FactoryBase<v8::Function> {
+ static inline
+ return_t
+ New( FunctionCallback callback
+ , v8::Local<v8::Value> data = v8::Local<v8::Value>());
+};
+
+template <>
+struct Factory<v8::FunctionTemplate> : FactoryBase<v8::FunctionTemplate> {
+ static inline
+ return_t
+ New( FunctionCallback callback = NULL
+ , v8::Local<v8::Value> data = v8::Local<v8::Value>()
+ , v8::Local<v8::Signature> signature = v8::Local<v8::Signature>());
+};
+
+template <>
+struct Factory<v8::Number> : FactoryBase<v8::Number> {
+ static inline return_t New(double value);
+};
+
+template <>
+struct Factory<v8::NumberObject> : FactoryBase<v8::NumberObject> {
+ static inline return_t New(double value);
+};
+
+template <typename T>
+struct IntegerFactory : FactoryBase<T> {
+ typedef typename FactoryBase<T>::return_t return_t;
+ static inline return_t New(int32_t value);
+ static inline return_t New(uint32_t value);
+};
+
+template <>
+struct Factory<v8::Integer> : IntegerFactory<v8::Integer> {};
+
+template <>
+struct Factory<v8::Int32> : IntegerFactory<v8::Int32> {};
+
+template <>
+struct Factory<v8::Uint32> : FactoryBase<v8::Uint32> {
+ static inline return_t New(int32_t value);
+ static inline return_t New(uint32_t value);
+};
+
+template <>
+struct Factory<v8::Object> : FactoryBase<v8::Object> {
+ static inline return_t New();
+};
+
+template <>
+struct Factory<v8::ObjectTemplate> : FactoryBase<v8::ObjectTemplate> {
+ static inline return_t New();
+};
+
+template <>
+struct Factory<v8::RegExp> : MaybeFactoryBase<v8::RegExp> {
+ static inline return_t New(
+ v8::Local<v8::String> pattern, v8::RegExp::Flags flags);
+};
+
+template <>
+struct Factory<v8::Script> : MaybeFactoryBase<v8::Script> {
+ static inline return_t New( v8::Local<v8::String> source);
+ static inline return_t New( v8::Local<v8::String> source
+ , v8::ScriptOrigin const& origin);
+};
+
+template <>
+struct Factory<v8::Signature> : FactoryBase<v8::Signature> {
+ typedef v8::Local<v8::FunctionTemplate> FTH;
+ static inline return_t New(FTH receiver = FTH());
+};
+
+template <>
+struct Factory<v8::String> : MaybeFactoryBase<v8::String> {
+ static inline return_t New();
+ static inline return_t New(const char *value, int length = -1);
+ static inline return_t New(const uint16_t *value, int length = -1);
+ static inline return_t New(std::string const& value);
+
+ static inline return_t New(v8::String::ExternalStringResource * value);
+ static inline return_t New(ExternalOneByteStringResource * value);
+};
+
+template <>
+struct Factory<v8::StringObject> : FactoryBase<v8::StringObject> {
+ static inline return_t New(v8::Local<v8::String> value);
+};
+
+} // end of namespace imp
+
+#if (NODE_MODULE_VERSION >= 12)
+
+namespace imp {
+
+template <>
+struct Factory<v8::UnboundScript> : MaybeFactoryBase<v8::UnboundScript> {
+ static inline return_t New( v8::Local<v8::String> source);
+ static inline return_t New( v8::Local<v8::String> source
+ , v8::ScriptOrigin const& origin);
+};
+
+} // end of namespace imp
+
+# include "nan_implementation_12_inl.h"
+
+#else // NODE_MODULE_VERSION >= 12
+
+# include "nan_implementation_pre_12_inl.h"
+
+#endif
+
+//=== API ======================================================================
+
+template <typename T>
+typename imp::Factory<T>::return_t
+New() {
+ return imp::Factory<T>::New();
+}
+
+template <typename T, typename A0>
+typename imp::Factory<T>::return_t
+New(A0 arg0) {
+ return imp::Factory<T>::New(arg0);
+}
+
+template <typename T, typename A0, typename A1>
+typename imp::Factory<T>::return_t
+New(A0 arg0, A1 arg1) {
+ return imp::Factory<T>::New(arg0, arg1);
+}
+
+template <typename T, typename A0, typename A1, typename A2>
+typename imp::Factory<T>::return_t
+New(A0 arg0, A1 arg1, A2 arg2) {
+ return imp::Factory<T>::New(arg0, arg1, arg2);
+}
+
+template <typename T, typename A0, typename A1, typename A2, typename A3>
+typename imp::Factory<T>::return_t
+New(A0 arg0, A1 arg1, A2 arg2, A3 arg3) {
+ return imp::Factory<T>::New(arg0, arg1, arg2, arg3);
+}
+
+// Note(agnat): When passing overloaded function pointers to template functions
+// as generic arguments the compiler needs help in picking the right overload.
+// These two functions handle New<Function> and New<FunctionTemplate> with
+// all argument variations.
+
+// v8::Function and v8::FunctionTemplate with one or two arguments
+template <typename T>
+typename imp::Factory<T>::return_t
+New( FunctionCallback callback
+ , v8::Local<v8::Value> data = v8::Local<v8::Value>()) {
+ return imp::Factory<T>::New(callback, data);
+}
+
+// v8::Function and v8::FunctionTemplate with three arguments
+template <typename T, typename A2>
+typename imp::Factory<T>::return_t
+New( FunctionCallback callback
+ , v8::Local<v8::Value> data = v8::Local<v8::Value>()
+ , A2 a2 = A2()) {
+ return imp::Factory<T>::New(callback, data, a2);
+}
+
+// Convenience
+
+#if NODE_MODULE_VERSION < IOJS_3_0_MODULE_VERSION
+template <typename T> inline v8::Local<T> New(v8::Handle<T> h);
+#endif
+
+#if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+template <typename T, typename M>
+ inline v8::Local<T> New(v8::Persistent<T, M> const& p);
+#else
+template <typename T> inline v8::Local<T> New(v8::Persistent<T> const& p);
+#endif
+template <typename T, typename M>
+inline v8::Local<T> New(Persistent<T, M> const& p);
+template <typename T>
+inline v8::Local<T> New(Global<T> const& p);
+
+inline
+imp::Factory<v8::Boolean>::return_t
+New(bool value) {
+ return New<v8::Boolean>(value);
+}
+
+inline
+imp::Factory<v8::Int32>::return_t
+New(int32_t value) {
+ return New<v8::Int32>(value);
+}
+
+inline
+imp::Factory<v8::Uint32>::return_t
+New(uint32_t value) {
+ return New<v8::Uint32>(value);
+}
+
+inline
+imp::Factory<v8::Number>::return_t
+New(double value) {
+ return New<v8::Number>(value);
+}
+
+inline
+imp::Factory<v8::String>::return_t
+New(std::string const& value) { // NOLINT(build/include_what_you_use)
+ return New<v8::String>(value);
+}
+
+inline
+imp::Factory<v8::String>::return_t
+New(const char * value, int length) {
+ return New<v8::String>(value, length);
+}
+
+inline
+imp::Factory<v8::String>::return_t
+New(const uint16_t * value, int length) {
+ return New<v8::String>(value, length);
+}
+
+inline
+imp::Factory<v8::String>::return_t
+New(const char * value) {
+ return New<v8::String>(value);
+}
+
+inline
+imp::Factory<v8::String>::return_t
+New(const uint16_t * value) {
+ return New<v8::String>(value);
+}
+
+inline
+imp::Factory<v8::String>::return_t
+New(v8::String::ExternalStringResource * value) {
+ return New<v8::String>(value);
+}
+
+inline
+imp::Factory<v8::String>::return_t
+New(ExternalOneByteStringResource * value) {
+ return New<v8::String>(value);
+}
+
+inline
+imp::Factory<v8::RegExp>::return_t
+New(v8::Local<v8::String> pattern, v8::RegExp::Flags flags) {
+ return New<v8::RegExp>(pattern, flags);
+}
+
+#endif // NAN_NEW_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_OBJECT_WRAP_H_
+#define NAN_OBJECT_WRAP_H_
+
+class ObjectWrap {
+ public:
+ ObjectWrap() {
+ refs_ = 0;
+ }
+
+
+ virtual ~ObjectWrap() {
+ if (persistent().IsEmpty()) {
+ return;
+ }
+
+ persistent().ClearWeak();
+ persistent().Reset();
+ }
+
+
+ template <class T>
+ static inline T* Unwrap(v8::Local<v8::Object> object) {
+ assert(!object.IsEmpty());
+ assert(object->InternalFieldCount() > 0);
+ // Cast to ObjectWrap before casting to T. A direct cast from void
+ // to T won't work right when T has more than one base class.
+ void* ptr = GetInternalFieldPointer(object, 0);
+ ObjectWrap* wrap = static_cast<ObjectWrap*>(ptr);
+ return static_cast<T*>(wrap);
+ }
+
+
+ inline v8::Local<v8::Object> handle() const {
+ return New(handle_);
+ }
+
+
+ inline Persistent<v8::Object>& persistent() {
+ return handle_;
+ }
+
+
+ protected:
+ inline void Wrap(v8::Local<v8::Object> object) {
+ assert(persistent().IsEmpty());
+ assert(object->InternalFieldCount() > 0);
+ SetInternalFieldPointer(object, 0, this);
+ persistent().Reset(object);
+ MakeWeak();
+ }
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+
+ inline void MakeWeak() {
+ persistent().v8::PersistentBase<v8::Object>::SetWeak(
+ this, WeakCallback, v8::WeakCallbackType::kParameter);
+#if NODE_MAJOR_VERSION < 10
+ // FIXME(bnoordhuis) Probably superfluous in older Node.js versions too.
+ persistent().MarkIndependent();
+#endif
+ }
+
+#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+
+ inline void MakeWeak() {
+ persistent().v8::PersistentBase<v8::Object>::SetWeak(this, WeakCallback);
+ persistent().MarkIndependent();
+ }
+
+#else
+
+ inline void MakeWeak() {
+ persistent().persistent.MakeWeak(this, WeakCallback);
+ persistent().MarkIndependent();
+ }
+
+#endif
+
+ /* Ref() marks the object as being attached to an event loop.
+ * Refed objects will not be garbage collected, even if
+ * all references are lost.
+ */
+ virtual void Ref() {
+ assert(!persistent().IsEmpty());
+ persistent().ClearWeak();
+ refs_++;
+ }
+
+ /* Unref() marks an object as detached from the event loop. This is its
+ * default state. When an object with a "weak" reference changes from
+ * attached to detached state it will be freed. Be careful not to access
+ * the object after making this call as it might be gone!
+ * (A "weak reference" means an object that only has a
+ * persistant handle.)
+ *
+ * DO NOT CALL THIS FROM DESTRUCTOR
+ */
+ virtual void Unref() {
+ assert(!persistent().IsEmpty());
+ assert(!persistent().IsWeak());
+ assert(refs_ > 0);
+ if (--refs_ == 0)
+ MakeWeak();
+ }
+
+ int refs_; // ro
+
+ private:
+ NAN_DISALLOW_ASSIGN_COPY_MOVE(ObjectWrap)
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+
+ static void
+ WeakCallback(v8::WeakCallbackInfo<ObjectWrap> const& info) {
+ ObjectWrap* wrap = info.GetParameter();
+ assert(wrap->refs_ == 0);
+ wrap->handle_.Reset();
+ delete wrap;
+ }
+
+#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+
+ static void
+ WeakCallback(v8::WeakCallbackData<v8::Object, ObjectWrap> const& data) {
+ ObjectWrap* wrap = data.GetParameter();
+ assert(wrap->refs_ == 0);
+ assert(wrap->handle_.IsNearDeath());
+ wrap->handle_.Reset();
+ delete wrap;
+ }
+
+#else
+
+ static void WeakCallback(v8::Persistent<v8::Value> value, void *data) {
+ ObjectWrap *wrap = static_cast<ObjectWrap*>(data);
+ assert(wrap->refs_ == 0);
+ assert(wrap->handle_.IsNearDeath());
+ wrap->handle_.Reset();
+ delete wrap;
+ }
+
+#endif
+ Persistent<v8::Object> handle_;
+};
+
+
+#endif // NAN_OBJECT_WRAP_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_PERSISTENT_12_INL_H_
+#define NAN_PERSISTENT_12_INL_H_
+
+template<typename T, typename M> class Persistent :
+ public v8::Persistent<T, M> {
+ public:
+ inline Persistent() : v8::Persistent<T, M>() {}
+
+ template<typename S> inline Persistent(v8::Local<S> that) :
+ v8::Persistent<T, M>(v8::Isolate::GetCurrent(), that) {}
+
+ template<typename S, typename M2>
+ inline
+ Persistent(const v8::Persistent<S, M2> &that) : // NOLINT(runtime/explicit)
+ v8::Persistent<T, M2>(v8::Isolate::GetCurrent(), that) {}
+
+ inline void Reset() { v8::PersistentBase<T>::Reset(); }
+
+ template <typename S>
+ inline void Reset(const v8::Local<S> &other) {
+ v8::PersistentBase<T>::Reset(v8::Isolate::GetCurrent(), other);
+ }
+
+ template <typename S>
+ inline void Reset(const v8::PersistentBase<S> &other) {
+ v8::PersistentBase<T>::Reset(v8::Isolate::GetCurrent(), other);
+ }
+
+ template<typename P>
+ inline void SetWeak(
+ P *parameter
+ , typename WeakCallbackInfo<P>::Callback callback
+ , WeakCallbackType type);
+
+ private:
+ inline T *operator*() const { return *PersistentBase<T>::persistent; }
+
+ template<typename S, typename M2>
+ inline void Copy(const Persistent<S, M2> &that) {
+ TYPE_CHECK(T, S);
+
+ this->Reset();
+
+ if (!that.IsEmpty()) {
+ this->Reset(that);
+ M::Copy(that, this);
+ }
+ }
+};
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+template<typename T>
+class Global : public v8::Global<T> {
+ public:
+ inline Global() : v8::Global<T>() {}
+
+ template<typename S> inline Global(v8::Local<S> that) :
+ v8::Global<T>(v8::Isolate::GetCurrent(), that) {}
+
+ template<typename S>
+ inline
+ Global(const v8::PersistentBase<S> &that) : // NOLINT(runtime/explicit)
+ v8::Global<S>(v8::Isolate::GetCurrent(), that) {}
+
+ inline void Reset() { v8::PersistentBase<T>::Reset(); }
+
+ template <typename S>
+ inline void Reset(const v8::Local<S> &other) {
+ v8::PersistentBase<T>::Reset(v8::Isolate::GetCurrent(), other);
+ }
+
+ template <typename S>
+ inline void Reset(const v8::PersistentBase<S> &other) {
+ v8::PersistentBase<T>::Reset(v8::Isolate::GetCurrent(), other);
+ }
+
+ template<typename P>
+ inline void SetWeak(
+ P *parameter
+ , typename WeakCallbackInfo<P>::Callback callback
+ , WeakCallbackType type) {
+ reinterpret_cast<Persistent<T>*>(this)->SetWeak(
+ parameter, callback, type);
+ }
+};
+#else
+template<typename T>
+class Global : public v8::UniquePersistent<T> {
+ public:
+ inline Global() : v8::UniquePersistent<T>() {}
+
+ template<typename S> inline Global(v8::Local<S> that) :
+ v8::UniquePersistent<T>(v8::Isolate::GetCurrent(), that) {}
+
+ template<typename S>
+ inline
+ Global(const v8::PersistentBase<S> &that) : // NOLINT(runtime/explicit)
+ v8::UniquePersistent<S>(v8::Isolate::GetCurrent(), that) {}
+
+ inline void Reset() { v8::PersistentBase<T>::Reset(); }
+
+ template <typename S>
+ inline void Reset(const v8::Local<S> &other) {
+ v8::PersistentBase<T>::Reset(v8::Isolate::GetCurrent(), other);
+ }
+
+ template <typename S>
+ inline void Reset(const v8::PersistentBase<S> &other) {
+ v8::PersistentBase<T>::Reset(v8::Isolate::GetCurrent(), other);
+ }
+
+ template<typename P>
+ inline void SetWeak(
+ P *parameter
+ , typename WeakCallbackInfo<P>::Callback callback
+ , WeakCallbackType type) {
+ reinterpret_cast<Persistent<T>*>(this)->SetWeak(
+ parameter, callback, type);
+ }
+};
+#endif
+
+#endif // NAN_PERSISTENT_12_INL_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_PERSISTENT_PRE_12_INL_H_
+#define NAN_PERSISTENT_PRE_12_INL_H_
+
+template<typename T>
+class PersistentBase {
+ v8::Persistent<T> persistent;
+ template<typename U>
+ friend v8::Local<U> New(const PersistentBase<U> &p);
+ template<typename U, typename M>
+ friend v8::Local<U> New(const Persistent<U, M> &p);
+ template<typename U>
+ friend v8::Local<U> New(const Global<U> &p);
+ template<typename S> friend class ReturnValue;
+
+ public:
+ inline PersistentBase() :
+ persistent() {}
+
+ inline void Reset() {
+ persistent.Dispose();
+ persistent.Clear();
+ }
+
+ template<typename S>
+ inline void Reset(const v8::Local<S> &other) {
+ TYPE_CHECK(T, S);
+
+ if (!persistent.IsEmpty()) {
+ persistent.Dispose();
+ }
+
+ if (other.IsEmpty()) {
+ persistent.Clear();
+ } else {
+ persistent = v8::Persistent<T>::New(other);
+ }
+ }
+
+ template<typename S>
+ inline void Reset(const PersistentBase<S> &other) {
+ TYPE_CHECK(T, S);
+
+ if (!persistent.IsEmpty()) {
+ persistent.Dispose();
+ }
+
+ if (other.IsEmpty()) {
+ persistent.Clear();
+ } else {
+ persistent = v8::Persistent<T>::New(other.persistent);
+ }
+ }
+
+ inline bool IsEmpty() const { return persistent.IsEmpty(); }
+
+ inline void Empty() { persistent.Clear(); }
+
+ template<typename S>
+ inline bool operator==(const PersistentBase<S> &that) const {
+ return this->persistent == that.persistent;
+ }
+
+ template<typename S>
+ inline bool operator==(const v8::Local<S> &that) const {
+ return this->persistent == that;
+ }
+
+ template<typename S>
+ inline bool operator!=(const PersistentBase<S> &that) const {
+ return !operator==(that);
+ }
+
+ template<typename S>
+ inline bool operator!=(const v8::Local<S> &that) const {
+ return !operator==(that);
+ }
+
+ template<typename P>
+ inline void SetWeak(
+ P *parameter
+ , typename WeakCallbackInfo<P>::Callback callback
+ , WeakCallbackType type);
+
+ inline void ClearWeak() { persistent.ClearWeak(); }
+
+ inline void MarkIndependent() { persistent.MarkIndependent(); }
+
+ inline bool IsIndependent() const { return persistent.IsIndependent(); }
+
+ inline bool IsNearDeath() const { return persistent.IsNearDeath(); }
+
+ inline bool IsWeak() const { return persistent.IsWeak(); }
+
+ private:
+ inline explicit PersistentBase(v8::Persistent<T> that) :
+ persistent(that) { }
+ inline explicit PersistentBase(T *val) : persistent(val) {}
+ template<typename S, typename M> friend class Persistent;
+ template<typename S> friend class Global;
+ friend class ObjectWrap;
+};
+
+template<typename T>
+class NonCopyablePersistentTraits {
+ public:
+ typedef Persistent<T, NonCopyablePersistentTraits<T> >
+ NonCopyablePersistent;
+ static const bool kResetInDestructor = false;
+ template<typename S, typename M>
+ inline static void Copy(const Persistent<S, M> &source,
+ NonCopyablePersistent *dest) {
+ Uncompilable<v8::Object>();
+ }
+
+ template<typename O> inline static void Uncompilable() {
+ TYPE_CHECK(O, v8::Primitive);
+ }
+};
+
+template<typename T>
+struct CopyablePersistentTraits {
+ typedef Persistent<T, CopyablePersistentTraits<T> > CopyablePersistent;
+ static const bool kResetInDestructor = true;
+ template<typename S, typename M>
+ static inline void Copy(const Persistent<S, M> &source,
+ CopyablePersistent *dest) {}
+};
+
+template<typename T, typename M> class Persistent :
+ public PersistentBase<T> {
+ public:
+ inline Persistent() {}
+
+ template<typename S> inline Persistent(v8::Handle<S> that)
+ : PersistentBase<T>(v8::Persistent<T>::New(that)) {
+ TYPE_CHECK(T, S);
+ }
+
+ inline Persistent(const Persistent &that) : PersistentBase<T>() {
+ Copy(that);
+ }
+
+ template<typename S, typename M2>
+ inline Persistent(const Persistent<S, M2> &that) :
+ PersistentBase<T>() {
+ Copy(that);
+ }
+
+ inline Persistent &operator=(const Persistent &that) {
+ Copy(that);
+ return *this;
+ }
+
+ template <class S, class M2>
+ inline Persistent &operator=(const Persistent<S, M2> &that) {
+ Copy(that);
+ return *this;
+ }
+
+ inline ~Persistent() {
+ if (M::kResetInDestructor) this->Reset();
+ }
+
+ private:
+ inline T *operator*() const { return *PersistentBase<T>::persistent; }
+
+ template<typename S, typename M2>
+ inline void Copy(const Persistent<S, M2> &that) {
+ TYPE_CHECK(T, S);
+
+ this->Reset();
+
+ if (!that.IsEmpty()) {
+ this->persistent = v8::Persistent<T>::New(that.persistent);
+ M::Copy(that, this);
+ }
+ }
+};
+
+template<typename T>
+class Global : public PersistentBase<T> {
+ struct RValue {
+ inline explicit RValue(Global* obj) : object(obj) {}
+ Global* object;
+ };
+
+ public:
+ inline Global() : PersistentBase<T>(0) { }
+
+ template <typename S>
+ inline Global(v8::Local<S> that) // NOLINT(runtime/explicit)
+ : PersistentBase<T>(v8::Persistent<T>::New(that)) {
+ TYPE_CHECK(T, S);
+ }
+
+ template <typename S>
+ inline Global(const PersistentBase<S> &that) // NOLINT(runtime/explicit)
+ : PersistentBase<T>(that) {
+ TYPE_CHECK(T, S);
+ }
+ /**
+ * Move constructor.
+ */
+ inline Global(RValue rvalue) // NOLINT(runtime/explicit)
+ : PersistentBase<T>(rvalue.object->persistent) {
+ rvalue.object->Reset();
+ }
+ inline ~Global() { this->Reset(); }
+ /**
+ * Move via assignment.
+ */
+ template<typename S>
+ inline Global &operator=(Global<S> rhs) {
+ TYPE_CHECK(T, S);
+ this->Reset(rhs.persistent);
+ rhs.Reset();
+ return *this;
+ }
+ /**
+ * Cast operator for moves.
+ */
+ inline operator RValue() { return RValue(this); }
+ /**
+ * Pass allows returning uniques from functions, etc.
+ */
+ Global Pass() { return Global(RValue(this)); }
+
+ private:
+ Global(Global &);
+ void operator=(Global &);
+ template<typename S> friend class ReturnValue;
+};
+
+#endif // NAN_PERSISTENT_PRE_12_INL_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_PRIVATE_H_
+#define NAN_PRIVATE_H_
+
+inline Maybe<bool>
+HasPrivate(v8::Local<v8::Object> object, v8::Local<v8::String> key) {
+ HandleScope scope;
+#if NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Private> private_key = v8::Private::ForApi(isolate, key);
+ return object->HasPrivate(context, private_key);
+#else
+ return Just(!object->GetHiddenValue(key).IsEmpty());
+#endif
+}
+
+inline MaybeLocal<v8::Value>
+GetPrivate(v8::Local<v8::Object> object, v8::Local<v8::String> key) {
+#if NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::EscapableHandleScope scope(isolate);
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Private> private_key = v8::Private::ForApi(isolate, key);
+ v8::MaybeLocal<v8::Value> v = object->GetPrivate(context, private_key);
+ return scope.Escape(v.ToLocalChecked());
+#else
+ EscapableHandleScope scope;
+ v8::Local<v8::Value> v = object->GetHiddenValue(key);
+ if (v.IsEmpty()) {
+ v = Undefined();
+ }
+ return scope.Escape(v);
+#endif
+}
+
+inline Maybe<bool> SetPrivate(
+ v8::Local<v8::Object> object,
+ v8::Local<v8::String> key,
+ v8::Local<v8::Value> value) {
+#if NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION
+ HandleScope scope;
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::Local<v8::Context> context = isolate->GetCurrentContext();
+ v8::Local<v8::Private> private_key = v8::Private::ForApi(isolate, key);
+ return object->SetPrivate(context, private_key, value);
+#else
+ return Just(object->SetHiddenValue(key, value));
+#endif
+}
+
+inline Maybe<bool> DeletePrivate(
+ v8::Local<v8::Object> object,
+ v8::Local<v8::String> key) {
+#if NODE_MODULE_VERSION >= NODE_6_0_MODULE_VERSION
+ HandleScope scope;
+ v8::Isolate *isolate = v8::Isolate::GetCurrent();
+ v8::Local<v8::Private> private_key = v8::Private::ForApi(isolate, key);
+ return object->DeletePrivate(isolate->GetCurrentContext(), private_key);
+#else
+ return Just(object->DeleteHiddenValue(key));
+#endif
+}
+
+#endif // NAN_PRIVATE_H_
+
--- /dev/null
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#ifndef NAN_STRING_BYTES_H_
+#define NAN_STRING_BYTES_H_
+
+// Decodes a v8::Local<v8::String> or Buffer to a raw char*
+
+namespace imp {
+
+using v8::Local;
+using v8::Object;
+using v8::String;
+using v8::Value;
+
+
+//// Base 64 ////
+
+#define base64_encoded_size(size) ((size + 2 - ((size + 2) % 3)) / 3 * 4)
+
+
+
+//// HEX ////
+
+static bool contains_non_ascii_slow(const char* buf, size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ if (buf[i] & 0x80) return true;
+ }
+ return false;
+}
+
+
+static bool contains_non_ascii(const char* src, size_t len) {
+ if (len < 16) {
+ return contains_non_ascii_slow(src, len);
+ }
+
+ const unsigned bytes_per_word = sizeof(void*);
+ const unsigned align_mask = bytes_per_word - 1;
+ const unsigned unaligned = reinterpret_cast<uintptr_t>(src) & align_mask;
+
+ if (unaligned > 0) {
+ const unsigned n = bytes_per_word - unaligned;
+ if (contains_non_ascii_slow(src, n)) return true;
+ src += n;
+ len -= n;
+ }
+
+
+#if defined(__x86_64__) || defined(_WIN64)
+ const uintptr_t mask = 0x8080808080808080ll;
+#else
+ const uintptr_t mask = 0x80808080l;
+#endif
+
+ const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
+
+ for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
+ if (srcw[i] & mask) return true;
+ }
+
+ const unsigned remainder = len & align_mask;
+ if (remainder > 0) {
+ const size_t offset = len - remainder;
+ if (contains_non_ascii_slow(src + offset, remainder)) return true;
+ }
+
+ return false;
+}
+
+
+static void force_ascii_slow(const char* src, char* dst, size_t len) {
+ for (size_t i = 0; i < len; ++i) {
+ dst[i] = src[i] & 0x7f;
+ }
+}
+
+
+static void force_ascii(const char* src, char* dst, size_t len) {
+ if (len < 16) {
+ force_ascii_slow(src, dst, len);
+ return;
+ }
+
+ const unsigned bytes_per_word = sizeof(void*);
+ const unsigned align_mask = bytes_per_word - 1;
+ const unsigned src_unalign = reinterpret_cast<uintptr_t>(src) & align_mask;
+ const unsigned dst_unalign = reinterpret_cast<uintptr_t>(dst) & align_mask;
+
+ if (src_unalign > 0) {
+ if (src_unalign == dst_unalign) {
+ const unsigned unalign = bytes_per_word - src_unalign;
+ force_ascii_slow(src, dst, unalign);
+ src += unalign;
+ dst += unalign;
+ len -= src_unalign;
+ } else {
+ force_ascii_slow(src, dst, len);
+ return;
+ }
+ }
+
+#if defined(__x86_64__) || defined(_WIN64)
+ const uintptr_t mask = ~0x8080808080808080ll;
+#else
+ const uintptr_t mask = ~0x80808080l;
+#endif
+
+ const uintptr_t* srcw = reinterpret_cast<const uintptr_t*>(src);
+ uintptr_t* dstw = reinterpret_cast<uintptr_t*>(dst);
+
+ for (size_t i = 0, n = len / bytes_per_word; i < n; ++i) {
+ dstw[i] = srcw[i] & mask;
+ }
+
+ const unsigned remainder = len & align_mask;
+ if (remainder > 0) {
+ const size_t offset = len - remainder;
+ force_ascii_slow(src + offset, dst + offset, remainder);
+ }
+}
+
+
+static size_t base64_encode(const char* src,
+ size_t slen,
+ char* dst,
+ size_t dlen) {
+ // We know how much we'll write, just make sure that there's space.
+ assert(dlen >= base64_encoded_size(slen) &&
+ "not enough space provided for base64 encode");
+
+ dlen = base64_encoded_size(slen);
+
+ unsigned a;
+ unsigned b;
+ unsigned c;
+ unsigned i;
+ unsigned k;
+ unsigned n;
+
+ static const char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+
+ i = 0;
+ k = 0;
+ n = slen / 3 * 3;
+
+ while (i < n) {
+ a = src[i + 0] & 0xff;
+ b = src[i + 1] & 0xff;
+ c = src[i + 2] & 0xff;
+
+ dst[k + 0] = table[a >> 2];
+ dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
+ dst[k + 2] = table[((b & 0x0f) << 2) | (c >> 6)];
+ dst[k + 3] = table[c & 0x3f];
+
+ i += 3;
+ k += 4;
+ }
+
+ if (n != slen) {
+ switch (slen - n) {
+ case 1:
+ a = src[i + 0] & 0xff;
+ dst[k + 0] = table[a >> 2];
+ dst[k + 1] = table[(a & 3) << 4];
+ dst[k + 2] = '=';
+ dst[k + 3] = '=';
+ break;
+
+ case 2:
+ a = src[i + 0] & 0xff;
+ b = src[i + 1] & 0xff;
+ dst[k + 0] = table[a >> 2];
+ dst[k + 1] = table[((a & 3) << 4) | (b >> 4)];
+ dst[k + 2] = table[(b & 0x0f) << 2];
+ dst[k + 3] = '=';
+ break;
+ }
+ }
+
+ return dlen;
+}
+
+
+static size_t hex_encode(const char* src, size_t slen, char* dst, size_t dlen) {
+ // We know how much we'll write, just make sure that there's space.
+ assert(dlen >= slen * 2 &&
+ "not enough space provided for hex encode");
+
+ dlen = slen * 2;
+ for (uint32_t i = 0, k = 0; k < dlen; i += 1, k += 2) {
+ static const char hex[] = "0123456789abcdef";
+ uint8_t val = static_cast<uint8_t>(src[i]);
+ dst[k + 0] = hex[val >> 4];
+ dst[k + 1] = hex[val & 15];
+ }
+
+ return dlen;
+}
+
+
+
+static Local<Value> Encode(const char* buf,
+ size_t buflen,
+ enum Encoding encoding) {
+ assert(buflen <= node::Buffer::kMaxLength);
+ if (!buflen && encoding != BUFFER)
+ return New("").ToLocalChecked();
+
+ Local<String> val;
+ switch (encoding) {
+ case BUFFER:
+ return CopyBuffer(buf, buflen).ToLocalChecked();
+
+ case ASCII:
+ if (contains_non_ascii(buf, buflen)) {
+ char* out = new char[buflen];
+ force_ascii(buf, out, buflen);
+ val = New<String>(out, buflen).ToLocalChecked();
+ delete[] out;
+ } else {
+ val = New<String>(buf, buflen).ToLocalChecked();
+ }
+ break;
+
+ case UTF8:
+ val = New<String>(buf, buflen).ToLocalChecked();
+ break;
+
+ case BINARY: {
+ // TODO(isaacs) use ExternalTwoByteString?
+ const unsigned char *cbuf = reinterpret_cast<const unsigned char*>(buf);
+ uint16_t * twobytebuf = new uint16_t[buflen];
+ for (size_t i = 0; i < buflen; i++) {
+ // XXX is the following line platform independent?
+ twobytebuf[i] = cbuf[i];
+ }
+ val = New<String>(twobytebuf, buflen).ToLocalChecked();
+ delete[] twobytebuf;
+ break;
+ }
+
+ case BASE64: {
+ size_t dlen = base64_encoded_size(buflen);
+ char* dst = new char[dlen];
+
+ size_t written = base64_encode(buf, buflen, dst, dlen);
+ assert(written == dlen);
+
+ val = New<String>(dst, dlen).ToLocalChecked();
+ delete[] dst;
+ break;
+ }
+
+ case UCS2: {
+ const uint16_t* data = reinterpret_cast<const uint16_t*>(buf);
+ val = New<String>(data, buflen / 2).ToLocalChecked();
+ break;
+ }
+
+ case HEX: {
+ size_t dlen = buflen * 2;
+ char* dst = new char[dlen];
+ size_t written = hex_encode(buf, buflen, dst, dlen);
+ assert(written == dlen);
+
+ val = New<String>(dst, dlen).ToLocalChecked();
+ delete[] dst;
+ break;
+ }
+
+ default:
+ assert(0 && "unknown encoding");
+ break;
+ }
+
+ return val;
+}
+
+#undef base64_encoded_size
+
+} // end of namespace imp
+
+#endif // NAN_STRING_BYTES_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_TYPEDARRAY_CONTENTS_H_
+#define NAN_TYPEDARRAY_CONTENTS_H_
+
+template<typename T>
+class TypedArrayContents {
+ public:
+ inline explicit TypedArrayContents(v8::Local<v8::Value> from) :
+ length_(0), data_(NULL) {
+ HandleScope scope;
+
+ size_t length = 0;
+ void* data = NULL;
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+
+ if (from->IsArrayBufferView()) {
+ v8::Local<v8::ArrayBufferView> array =
+ v8::Local<v8::ArrayBufferView>::Cast(from);
+
+ const size_t byte_length = array->ByteLength();
+ const ptrdiff_t byte_offset = array->ByteOffset();
+ v8::Local<v8::ArrayBuffer> buffer = array->Buffer();
+
+ length = byte_length / sizeof(T);
+ data = static_cast<char*>(buffer->GetContents().Data()) + byte_offset;
+ }
+
+#else
+
+ if (from->IsObject() && !from->IsNull()) {
+ v8::Local<v8::Object> array = v8::Local<v8::Object>::Cast(from);
+
+ MaybeLocal<v8::Value> buffer = Get(array,
+ New<v8::String>("buffer").ToLocalChecked());
+ MaybeLocal<v8::Value> byte_length = Get(array,
+ New<v8::String>("byteLength").ToLocalChecked());
+ MaybeLocal<v8::Value> byte_offset = Get(array,
+ New<v8::String>("byteOffset").ToLocalChecked());
+
+ if (!buffer.IsEmpty() &&
+ !byte_length.IsEmpty() && byte_length.ToLocalChecked()->IsUint32() &&
+ !byte_offset.IsEmpty() && byte_offset.ToLocalChecked()->IsUint32()) {
+ data = array->GetIndexedPropertiesExternalArrayData();
+ if(data) {
+ length = byte_length.ToLocalChecked()->Uint32Value() / sizeof(T);
+ }
+ }
+ }
+
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1900 || __cplusplus >= 201103L
+ assert(reinterpret_cast<uintptr_t>(data) % alignof (T) == 0);
+#elif defined(_MSC_VER) && _MSC_VER >= 1600 || defined(__GNUC__)
+ assert(reinterpret_cast<uintptr_t>(data) % __alignof(T) == 0);
+#else
+ assert(reinterpret_cast<uintptr_t>(data) % sizeof (T) == 0);
+#endif
+
+ length_ = length;
+ data_ = static_cast<T*>(data);
+ }
+
+ inline size_t length() const { return length_; }
+ inline T* operator*() { return data_; }
+ inline const T* operator*() const { return data_; }
+
+ private:
+ NAN_DISALLOW_ASSIGN_COPY_MOVE(TypedArrayContents)
+
+ //Disable heap allocation
+ void *operator new(size_t size);
+ void operator delete(void *, size_t) {
+ abort();
+ }
+
+ size_t length_;
+ T* data_;
+};
+
+#endif // NAN_TYPEDARRAY_CONTENTS_H_
--- /dev/null
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+#ifndef NAN_WEAK_H_
+#define NAN_WEAK_H_
+
+static const int kInternalFieldsInWeakCallback = 2;
+static const int kNoInternalFieldIndex = -1;
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+# define NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ \
+ v8::WeakCallbackInfo<WeakCallbackInfo<T> > const&
+# define NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ \
+ NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_
+# define NAN_WEAK_PARAMETER_CALLBACK_SIG_ NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_
+# define NAN_WEAK_TWOFIELD_CALLBACK_SIG_ NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_
+#elif NODE_MODULE_VERSION > IOJS_1_1_MODULE_VERSION
+# define NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ \
+ v8::PhantomCallbackData<WeakCallbackInfo<T> > const&
+# define NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ \
+ NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_
+# define NAN_WEAK_PARAMETER_CALLBACK_SIG_ NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_
+# define NAN_WEAK_TWOFIELD_CALLBACK_SIG_ NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_
+#elif NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION
+# define NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ \
+ v8::PhantomCallbackData<WeakCallbackInfo<T> > const&
+# define NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ \
+ v8::InternalFieldsCallbackData<WeakCallbackInfo<T>, void> const&
+# define NAN_WEAK_PARAMETER_CALLBACK_SIG_ NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_
+# define NAN_WEAK_TWOFIELD_CALLBACK_SIG_ NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_
+#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+# define NAN_WEAK_CALLBACK_DATA_TYPE_ \
+ v8::WeakCallbackData<S, WeakCallbackInfo<T> > const&
+# define NAN_WEAK_CALLBACK_SIG_ NAN_WEAK_CALLBACK_DATA_TYPE_
+#else
+# define NAN_WEAK_CALLBACK_DATA_TYPE_ void *
+# define NAN_WEAK_CALLBACK_SIG_ \
+ v8::Persistent<v8::Value>, NAN_WEAK_CALLBACK_DATA_TYPE_
+#endif
+
+template<typename T>
+class WeakCallbackInfo {
+ public:
+ typedef void (*Callback)(const WeakCallbackInfo<T>& data);
+ WeakCallbackInfo(
+ Persistent<v8::Value> *persistent
+ , Callback callback
+ , void *parameter
+ , void *field1 = 0
+ , void *field2 = 0) :
+ callback_(callback), isolate_(0), parameter_(parameter) {
+ std::memcpy(&persistent_, persistent, sizeof (v8::Persistent<v8::Value>));
+ internal_fields_[0] = field1;
+ internal_fields_[1] = field2;
+ }
+ inline v8::Isolate *GetIsolate() const { return isolate_; }
+ inline T *GetParameter() const { return static_cast<T*>(parameter_); }
+ inline void *GetInternalField(int index) const {
+ assert((index == 0 || index == 1) && "internal field index out of bounds");
+ if (index == 0) {
+ return internal_fields_[0];
+ } else {
+ return internal_fields_[1];
+ }
+ }
+
+ private:
+ NAN_DISALLOW_ASSIGN_COPY_MOVE(WeakCallbackInfo)
+ Callback callback_;
+ v8::Isolate *isolate_;
+ void *parameter_;
+ void *internal_fields_[kInternalFieldsInWeakCallback];
+ v8::Persistent<v8::Value> persistent_;
+ template<typename S, typename M> friend class Persistent;
+ template<typename S> friend class PersistentBase;
+#if NODE_MODULE_VERSION <= NODE_0_12_MODULE_VERSION
+# if NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+ template<typename S>
+ static void invoke(NAN_WEAK_CALLBACK_SIG_ data);
+ template<typename S>
+ static WeakCallbackInfo *unwrap(NAN_WEAK_CALLBACK_DATA_TYPE_ data);
+# else
+ static void invoke(NAN_WEAK_CALLBACK_SIG_ data);
+ static WeakCallbackInfo *unwrap(NAN_WEAK_CALLBACK_DATA_TYPE_ data);
+# endif
+#else
+# if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+ template<bool isFirstPass>
+ static void invokeparameter(NAN_WEAK_PARAMETER_CALLBACK_SIG_ data);
+ template<bool isFirstPass>
+ static void invoketwofield(NAN_WEAK_TWOFIELD_CALLBACK_SIG_ data);
+# else
+ static void invokeparameter(NAN_WEAK_PARAMETER_CALLBACK_SIG_ data);
+ static void invoketwofield(NAN_WEAK_TWOFIELD_CALLBACK_SIG_ data);
+# endif
+ static WeakCallbackInfo *unwrapparameter(
+ NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ data);
+ static WeakCallbackInfo *unwraptwofield(
+ NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ data);
+#endif
+};
+
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+
+template<typename T>
+template<bool isFirstPass>
+void
+WeakCallbackInfo<T>::invokeparameter(NAN_WEAK_PARAMETER_CALLBACK_SIG_ data) {
+ WeakCallbackInfo<T> *cbinfo = unwrapparameter(data);
+ if (isFirstPass) {
+ cbinfo->persistent_.Reset();
+ data.SetSecondPassCallback(invokeparameter<false>);
+ } else {
+ cbinfo->callback_(*cbinfo);
+ delete cbinfo;
+ }
+}
+
+template<typename T>
+template<bool isFirstPass>
+void
+WeakCallbackInfo<T>::invoketwofield(NAN_WEAK_TWOFIELD_CALLBACK_SIG_ data) {
+ WeakCallbackInfo<T> *cbinfo = unwraptwofield(data);
+ if (isFirstPass) {
+ cbinfo->persistent_.Reset();
+ data.SetSecondPassCallback(invoketwofield<false>);
+ } else {
+ cbinfo->callback_(*cbinfo);
+ delete cbinfo;
+ }
+}
+
+template<typename T>
+WeakCallbackInfo<T> *WeakCallbackInfo<T>::unwrapparameter(
+ NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ data) {
+ WeakCallbackInfo<T> *cbinfo =
+ static_cast<WeakCallbackInfo<T>*>(data.GetParameter());
+ cbinfo->isolate_ = data.GetIsolate();
+ return cbinfo;
+}
+
+template<typename T>
+WeakCallbackInfo<T> *WeakCallbackInfo<T>::unwraptwofield(
+ NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ data) {
+ WeakCallbackInfo<T> *cbinfo =
+ static_cast<WeakCallbackInfo<T>*>(data.GetInternalField(0));
+ cbinfo->isolate_ = data.GetIsolate();
+ return cbinfo;
+}
+
+#undef NAN_WEAK_PARAMETER_CALLBACK_SIG_
+#undef NAN_WEAK_TWOFIELD_CALLBACK_SIG_
+#undef NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_
+#undef NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_
+# elif NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION
+
+template<typename T>
+void
+WeakCallbackInfo<T>::invokeparameter(NAN_WEAK_PARAMETER_CALLBACK_SIG_ data) {
+ WeakCallbackInfo<T> *cbinfo = unwrapparameter(data);
+ cbinfo->persistent_.Reset();
+ cbinfo->callback_(*cbinfo);
+ delete cbinfo;
+}
+
+template<typename T>
+void
+WeakCallbackInfo<T>::invoketwofield(NAN_WEAK_TWOFIELD_CALLBACK_SIG_ data) {
+ WeakCallbackInfo<T> *cbinfo = unwraptwofield(data);
+ cbinfo->persistent_.Reset();
+ cbinfo->callback_(*cbinfo);
+ delete cbinfo;
+}
+
+template<typename T>
+WeakCallbackInfo<T> *WeakCallbackInfo<T>::unwrapparameter(
+ NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_ data) {
+ WeakCallbackInfo<T> *cbinfo =
+ static_cast<WeakCallbackInfo<T>*>(data.GetParameter());
+ cbinfo->isolate_ = data.GetIsolate();
+ return cbinfo;
+}
+
+template<typename T>
+WeakCallbackInfo<T> *WeakCallbackInfo<T>::unwraptwofield(
+ NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_ data) {
+ WeakCallbackInfo<T> *cbinfo =
+ static_cast<WeakCallbackInfo<T>*>(data.GetInternalField1());
+ cbinfo->isolate_ = data.GetIsolate();
+ return cbinfo;
+}
+
+#undef NAN_WEAK_PARAMETER_CALLBACK_SIG_
+#undef NAN_WEAK_TWOFIELD_CALLBACK_SIG_
+#undef NAN_WEAK_PARAMETER_CALLBACK_DATA_TYPE_
+#undef NAN_WEAK_TWOFIELD_CALLBACK_DATA_TYPE_
+#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+
+template<typename T>
+template<typename S>
+void WeakCallbackInfo<T>::invoke(NAN_WEAK_CALLBACK_SIG_ data) {
+ WeakCallbackInfo<T> *cbinfo = unwrap(data);
+ cbinfo->persistent_.Reset();
+ cbinfo->callback_(*cbinfo);
+ delete cbinfo;
+}
+
+template<typename T>
+template<typename S>
+WeakCallbackInfo<T> *WeakCallbackInfo<T>::unwrap(
+ NAN_WEAK_CALLBACK_DATA_TYPE_ data) {
+ void *parameter = data.GetParameter();
+ WeakCallbackInfo<T> *cbinfo =
+ static_cast<WeakCallbackInfo<T>*>(parameter);
+ cbinfo->isolate_ = data.GetIsolate();
+ return cbinfo;
+}
+
+#undef NAN_WEAK_CALLBACK_SIG_
+#undef NAN_WEAK_CALLBACK_DATA_TYPE_
+#else
+
+template<typename T>
+void WeakCallbackInfo<T>::invoke(NAN_WEAK_CALLBACK_SIG_ data) {
+ WeakCallbackInfo<T> *cbinfo = unwrap(data);
+ cbinfo->persistent_.Dispose();
+ cbinfo->persistent_.Clear();
+ cbinfo->callback_(*cbinfo);
+ delete cbinfo;
+}
+
+template<typename T>
+WeakCallbackInfo<T> *WeakCallbackInfo<T>::unwrap(
+ NAN_WEAK_CALLBACK_DATA_TYPE_ data) {
+ WeakCallbackInfo<T> *cbinfo =
+ static_cast<WeakCallbackInfo<T>*>(data);
+ cbinfo->isolate_ = v8::Isolate::GetCurrent();
+ return cbinfo;
+}
+
+#undef NAN_WEAK_CALLBACK_SIG_
+#undef NAN_WEAK_CALLBACK_DATA_TYPE_
+#endif
+
+#if defined(V8_MAJOR_VERSION) && (V8_MAJOR_VERSION > 4 || \
+ (V8_MAJOR_VERSION == 4 && defined(V8_MINOR_VERSION) && V8_MINOR_VERSION >= 3))
+template<typename T, typename M>
+template<typename P>
+inline void Persistent<T, M>::SetWeak(
+ P *parameter
+ , typename WeakCallbackInfo<P>::Callback callback
+ , WeakCallbackType type) {
+ WeakCallbackInfo<P> *wcbd;
+ if (type == WeakCallbackType::kParameter) {
+ wcbd = new WeakCallbackInfo<P>(
+ reinterpret_cast<Persistent<v8::Value>*>(this)
+ , callback
+ , parameter);
+ v8::PersistentBase<T>::SetWeak(
+ wcbd
+ , WeakCallbackInfo<P>::template invokeparameter<true>
+ , type);
+ } else {
+ v8::Local<v8::Value>* self_v(reinterpret_cast<v8::Local<v8::Value>*>(this));
+ assert((*self_v)->IsObject());
+ v8::Local<v8::Object> self((*self_v).As<v8::Object>());
+ int count = self->InternalFieldCount();
+ void *internal_fields[kInternalFieldsInWeakCallback] = {0, 0};
+ for (int i = 0; i < count && i < kInternalFieldsInWeakCallback; i++) {
+ internal_fields[i] = self->GetAlignedPointerFromInternalField(i);
+ }
+ wcbd = new WeakCallbackInfo<P>(
+ reinterpret_cast<Persistent<v8::Value>*>(this)
+ , callback
+ , 0
+ , internal_fields[0]
+ , internal_fields[1]);
+ self->SetAlignedPointerInInternalField(0, wcbd);
+ v8::PersistentBase<T>::SetWeak(
+ static_cast<WeakCallbackInfo<P>*>(0)
+ , WeakCallbackInfo<P>::template invoketwofield<true>
+ , type);
+ }
+}
+#elif NODE_MODULE_VERSION > IOJS_1_1_MODULE_VERSION
+template<typename T, typename M>
+template<typename P>
+inline void Persistent<T, M>::SetWeak(
+ P *parameter
+ , typename WeakCallbackInfo<P>::Callback callback
+ , WeakCallbackType type) {
+ WeakCallbackInfo<P> *wcbd;
+ if (type == WeakCallbackType::kParameter) {
+ wcbd = new WeakCallbackInfo<P>(
+ reinterpret_cast<Persistent<v8::Value>*>(this)
+ , callback
+ , parameter);
+ v8::PersistentBase<T>::SetPhantom(
+ wcbd
+ , WeakCallbackInfo<P>::invokeparameter);
+ } else {
+ v8::Local<v8::Value>* self_v(reinterpret_cast<v8::Local<v8::Value>*>(this));
+ assert((*self_v)->IsObject());
+ v8::Local<v8::Object> self((*self_v).As<v8::Object>());
+ int count = self->InternalFieldCount();
+ void *internal_fields[kInternalFieldsInWeakCallback] = {0, 0};
+ for (int i = 0; i < count && i < kInternalFieldsInWeakCallback; i++) {
+ internal_fields[i] = self->GetAlignedPointerFromInternalField(i);
+ }
+ wcbd = new WeakCallbackInfo<P>(
+ reinterpret_cast<Persistent<v8::Value>*>(this)
+ , callback
+ , 0
+ , internal_fields[0]
+ , internal_fields[1]);
+ self->SetAlignedPointerInInternalField(0, wcbd);
+ v8::PersistentBase<T>::SetPhantom(
+ static_cast<WeakCallbackInfo<P>*>(0)
+ , WeakCallbackInfo<P>::invoketwofield
+ , 0
+ , count > 1 ? 1 : kNoInternalFieldIndex);
+ }
+}
+#elif NODE_MODULE_VERSION > NODE_0_12_MODULE_VERSION
+template<typename T, typename M>
+template<typename P>
+inline void Persistent<T, M>::SetWeak(
+ P *parameter
+ , typename WeakCallbackInfo<P>::Callback callback
+ , WeakCallbackType type) {
+ WeakCallbackInfo<P> *wcbd;
+ if (type == WeakCallbackType::kParameter) {
+ wcbd = new WeakCallbackInfo<P>(
+ reinterpret_cast<Persistent<v8::Value>*>(this)
+ , callback
+ , parameter);
+ v8::PersistentBase<T>::SetPhantom(
+ wcbd
+ , WeakCallbackInfo<P>::invokeparameter);
+ } else {
+ v8::Local<v8::Value>* self_v(reinterpret_cast<v8::Local<v8::Value>*>(this));
+ assert((*self_v)->IsObject());
+ v8::Local<v8::Object> self((*self_v).As<v8::Object>());
+ int count = self->InternalFieldCount();
+ void *internal_fields[kInternalFieldsInWeakCallback] = {0, 0};
+ for (int i = 0; i < count && i < kInternalFieldsInWeakCallback; i++) {
+ internal_fields[i] = self->GetAlignedPointerFromInternalField(i);
+ }
+ wcbd = new WeakCallbackInfo<P>(
+ reinterpret_cast<Persistent<v8::Value>*>(this)
+ , callback
+ , 0
+ , internal_fields[0]
+ , internal_fields[1]);
+ self->SetAlignedPointerInInternalField(0, wcbd);
+ v8::PersistentBase<T>::SetPhantom(
+ WeakCallbackInfo<P>::invoketwofield
+ , 0
+ , count > 1 ? 1 : kNoInternalFieldIndex);
+ }
+}
+#elif NODE_MODULE_VERSION > NODE_0_10_MODULE_VERSION
+template<typename T, typename M>
+template<typename P>
+inline void Persistent<T, M>::SetWeak(
+ P *parameter
+ , typename WeakCallbackInfo<P>::Callback callback
+ , WeakCallbackType type) {
+ WeakCallbackInfo<P> *wcbd;
+ if (type == WeakCallbackType::kParameter) {
+ wcbd = new WeakCallbackInfo<P>(
+ reinterpret_cast<Persistent<v8::Value>*>(this)
+ , callback
+ , parameter);
+ v8::PersistentBase<T>::SetWeak(wcbd, WeakCallbackInfo<P>::invoke);
+ } else {
+ v8::Local<v8::Value>* self_v(reinterpret_cast<v8::Local<v8::Value>*>(this));
+ assert((*self_v)->IsObject());
+ v8::Local<v8::Object> self((*self_v).As<v8::Object>());
+ int count = self->InternalFieldCount();
+ void *internal_fields[kInternalFieldsInWeakCallback] = {0, 0};
+ for (int i = 0; i < count && i < kInternalFieldsInWeakCallback; i++) {
+ internal_fields[i] = self->GetAlignedPointerFromInternalField(i);
+ }
+ wcbd = new WeakCallbackInfo<P>(
+ reinterpret_cast<Persistent<v8::Value>*>(this)
+ , callback
+ , 0
+ , internal_fields[0]
+ , internal_fields[1]);
+ v8::PersistentBase<T>::SetWeak(wcbd, WeakCallbackInfo<P>::invoke);
+ }
+}
+#else
+template<typename T>
+template<typename P>
+inline void PersistentBase<T>::SetWeak(
+ P *parameter
+ , typename WeakCallbackInfo<P>::Callback callback
+ , WeakCallbackType type) {
+ WeakCallbackInfo<P> *wcbd;
+ if (type == WeakCallbackType::kParameter) {
+ wcbd = new WeakCallbackInfo<P>(
+ reinterpret_cast<Persistent<v8::Value>*>(this)
+ , callback
+ , parameter);
+ persistent.MakeWeak(wcbd, WeakCallbackInfo<P>::invoke);
+ } else {
+ v8::Local<v8::Value>* self_v(reinterpret_cast<v8::Local<v8::Value>*>(this));
+ assert((*self_v)->IsObject());
+ v8::Local<v8::Object> self((*self_v).As<v8::Object>());
+ int count = self->InternalFieldCount();
+ void *internal_fields[kInternalFieldsInWeakCallback] = {0, 0};
+ for (int i = 0; i < count && i < kInternalFieldsInWeakCallback; i++) {
+ internal_fields[i] = self->GetPointerFromInternalField(i);
+ }
+ wcbd = new WeakCallbackInfo<P>(
+ reinterpret_cast<Persistent<v8::Value>*>(this)
+ , callback
+ , 0
+ , internal_fields[0]
+ , internal_fields[1]);
+ persistent.MakeWeak(wcbd, WeakCallbackInfo<P>::invoke);
+ }
+}
+#endif
+
+#endif // NAN_WEAK_H_
--- /dev/null
+{
+ "name": "nan",
+ "version": "2.14.0",
+ "description": "Native Abstractions for Node.js: C++ header for Node 0.8 -> 11 compatibility",
+ "main": "include_dirs.js",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/nodejs/nan.git"
+ },
+ "scripts": {
+ "test": "tap --gc --stderr test/js/*-test.js",
+ "test:worker": "node --experimental-worker test/tap-as-worker.js --gc --stderr test/js/*-test.js",
+ "rebuild-tests": "node-gyp rebuild --msvs_version=2015 --directory test",
+ "docs": "doc/.build.sh"
+ },
+ "contributors": [
+ {
+ "name": "Rod Vagg",
+ "email": "r@va.gg",
+ "url": "https://github.com/rvagg"
+ },
+ {
+ "name": "Benjamin Byholm",
+ "email": "bbyholm@abo.fi",
+ "url": "https://github.com/kkoopa/"
+ },
+ {
+ "name": "Trevor Norris",
+ "email": "trev.norris@gmail.com",
+ "url": "https://github.com/trevnorris"
+ },
+ {
+ "name": "Nathan Rajlich",
+ "email": "nathan@tootallnate.net",
+ "url": "https://github.com/TooTallNate"
+ },
+ {
+ "name": "Brett Lawson",
+ "email": "brett19@gmail.com",
+ "url": "https://github.com/brett19"
+ },
+ {
+ "name": "Ben Noordhuis",
+ "email": "info@bnoordhuis.nl",
+ "url": "https://github.com/bnoordhuis"
+ },
+ {
+ "name": "David Siegel",
+ "email": "david@artcom.de",
+ "url": "https://github.com/agnat"
+ },
+ {
+ "name": "Michael Ira Krufky",
+ "email": "mkrufky@gmail.com",
+ "url": "https://github.com/mkrufky"
+ }
+ ],
+ "devDependencies": {
+ "bindings": "~1.2.1",
+ "commander": "^2.8.1",
+ "glob": "^5.0.14",
+ "request": "=2.81.0",
+ "node-gyp": "~3.6.2",
+ "readable-stream": "^2.1.4",
+ "tap": "~0.7.1",
+ "xtend": "~4.0.0"
+ },
+ "license": "MIT",
+ "gitHead": "1dcc61bd06d84e389bfd5311b2b1492a14c74201",
+ "bugs": {
+ "url": "https://github.com/nodejs/nan/issues"
+ },
+ "homepage": "https://github.com/nodejs/nan#readme",
+ "_id": "nan@2.14.0",
+ "_npmVersion": "5.6.0",
+ "_nodeVersion": "9.6.0",
+ "_npmUser": {
+ "name": "kkoopa",
+ "email": "bbyholm@abo.fi"
+ },
+ "dist": {
+ "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
+ "shasum": "7818f722027b2459a86f0295d434d1fc2336c52c",
+ "tarball": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
+ "fileCount": 46,
+ "unpackedSize": 417060,
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJc3bXpCRA9TVsSAnZWagAApycP/2mhtcraLrh5RRziC2xM\nUKDaEjBIznHn7PqDWecW3HW/CGrUfmuxpDCBlE2fBm2cxF26nB/CV6xoD2W1\nkyu4MkRcKiAvNW0h4a5sTwXey0U6xc8JRBhBTWgfiY2aQoA4fIO5akmbIa/w\nyT6tspFQ0BQWKBrxlSOqfQ/lARU4Dzy2eiKu1aWMffQecgqOPTrlb5/QxFsr\nUmfdePyO2odVrjDiiNJsfkHeMh66ED4n7szrRjwkz7FTkoEF0dMOw/bWJU2X\nEYVziHG7rm9B4Blzv6KtqG4Y9Gty8epOG+itSLQcc088H86TXYXJn6y75+lf\n1Lw5E9lxw5XLfVnE7uzr0NVHhcj/M3RaGzXySi7v2AWMbF6wqxtAdebdNaew\nIpc3+NVj2OjA/79bzzhU76MG0PrYURE8UmVugHZHGp9L1PraD/jWqCT1JMGE\n1qGu2dSlsqoyNe9Y1pTs/kc+I4KLjwDqo14NyQQk8quvkyHrQ66oO5lAPN4U\n5ms7vR+FOZYrtX7jQDTAs9N169N0IxhGwgsUH4zRza2RkkdTzsjyEnPhqlrI\n6tIrfYldrudrGtcNmLJqY7fTUA86L3f7SQvlnpfsDPUFagfwQr4Uz9JE8q1k\nhbe8CqTuhbET2AZNFlBxf0ii3ipwNXXJtB/0hIVQCfud1vbdS1IuOibc2/YY\n6ep0\r\n=AZxH\r\n-----END PGP SIGNATURE-----\r\n"
+ },
+ "maintainers": [
+ {
+ "name": "kkoopa",
+ "email": "bbyholm@abo.fi"
+ },
+ {
+ "name": "rvagg",
+ "email": "rod@vagg.org"
+ }
+ ],
+ "directories": {},
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/nan_2.14.0_1558033896058_0.6879275796293267"
+ },
+ "_hasShrinkwrap": false,
+ "_shasum": "7818f722027b2459a86f0295d434d1fc2336c52c",
+ "_from": "nan@^2.14.0",
+ "_resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz"
+}
--- /dev/null
+#!/usr/bin/env node
+/*********************************************************************
+ * NAN - Native Abstractions for Node.js
+ *
+ * Copyright (c) 2018 NAN contributors
+ *
+ * MIT License <https://github.com/nodejs/nan/blob/master/LICENSE.md>
+ ********************************************************************/
+
+var commander = require('commander'),
+ fs = require('fs'),
+ glob = require('glob'),
+ groups = [],
+ total = 0,
+ warning1 = '/* ERROR: Rewrite using Buffer */\n',
+ warning2 = '\\/\\* ERROR\\: Rewrite using Buffer \\*\\/\\n',
+ length,
+ i;
+
+fs.readFile(__dirname + '/package.json', 'utf8', function (err, data) {
+ if (err) {
+ throw err;
+ }
+
+ commander
+ .version(JSON.parse(data).version)
+ .usage('[options] <file ...>')
+ .parse(process.argv);
+
+ if (!process.argv.slice(2).length) {
+ commander.outputHelp();
+ }
+});
+
+/* construct strings representing regular expressions
+ each expression contains a unique group allowing for identification of the match
+ the index of this key group, relative to the regular expression in question,
+ is indicated by the first array member */
+
+/* simple substistutions, key group is the entire match, 0 */
+groups.push([0, [
+ '_NAN_',
+ 'NODE_SET_METHOD',
+ 'NODE_SET_PROTOTYPE_METHOD',
+ 'NanAsciiString',
+ 'NanEscapeScope',
+ 'NanReturnValue',
+ 'NanUcs2String'].join('|')]);
+
+/* substitutions of parameterless macros, key group is 1 */
+groups.push([1, ['(', [
+ 'NanEscapableScope',
+ 'NanReturnNull',
+ 'NanReturnUndefined',
+ 'NanScope'].join('|'), ')\\(\\)'].join('')]);
+
+/* replace TryCatch with NanTryCatch once, gobbling possible namespace, key group 2 */
+groups.push([2, '(?:(?:v8\\:\\:)?|(Nan)?)(TryCatch)']);
+
+/* NanNew("string") will likely not fail a ToLocalChecked(), key group 1 */
+groups.push([1, ['(NanNew)', '(\\("[^\\"]*"[^\\)]*\\))(?!\\.ToLocalChecked\\(\\))'].join('')]);
+
+/* Removed v8 APIs, warn that the code needs rewriting using node::Buffer, key group 2 */
+groups.push([2, ['(', warning2, ')?', '^.*?(', [
+ 'GetIndexedPropertiesExternalArrayDataLength',
+ 'GetIndexedPropertiesExternalArrayData',
+ 'GetIndexedPropertiesExternalArrayDataType',
+ 'GetIndexedPropertiesPixelData',
+ 'GetIndexedPropertiesPixelDataLength',
+ 'HasIndexedPropertiesInExternalArrayData',
+ 'HasIndexedPropertiesInPixelData',
+ 'SetIndexedPropertiesToExternalArrayData',
+ 'SetIndexedPropertiesToPixelData'].join('|'), ')'].join('')]);
+
+/* No need for NanScope in V8-exposed methods, key group 2 */
+groups.push([2, ['((', [
+ 'NAN_METHOD',
+ 'NAN_GETTER',
+ 'NAN_SETTER',
+ 'NAN_PROPERTY_GETTER',
+ 'NAN_PROPERTY_SETTER',
+ 'NAN_PROPERTY_ENUMERATOR',
+ 'NAN_PROPERTY_DELETER',
+ 'NAN_PROPERTY_QUERY',
+ 'NAN_INDEX_GETTER',
+ 'NAN_INDEX_SETTER',
+ 'NAN_INDEX_ENUMERATOR',
+ 'NAN_INDEX_DELETER',
+ 'NAN_INDEX_QUERY'].join('|'), ')\\([^\\)]*\\)\\s*\\{)\\s*NanScope\\(\\)\\s*;'].join('')]);
+
+/* v8::Value::ToXXXXXXX returns v8::MaybeLocal<T>, key group 3 */
+groups.push([3, ['([\\s\\(\\)])([^\\s\\(\\)]+)->(', [
+ 'Boolean',
+ 'Number',
+ 'String',
+ 'Object',
+ 'Integer',
+ 'Uint32',
+ 'Int32'].join('|'), ')\\('].join('')]);
+
+/* v8::Value::XXXXXXXValue returns v8::Maybe<T>, key group 3 */
+groups.push([3, ['([\\s\\(\\)])([^\\s\\(\\)]+)->((?:', [
+ 'Boolean',
+ 'Number',
+ 'Integer',
+ 'Uint32',
+ 'Int32'].join('|'), ')Value)\\('].join('')]);
+
+/* NAN_WEAK_CALLBACK macro was removed, write out callback definition, key group 1 */
+groups.push([1, '(NAN_WEAK_CALLBACK)\\(([^\\s\\)]+)\\)']);
+
+/* node::ObjectWrap and v8::Persistent have been replaced with Nan implementations, key group 1 */
+groups.push([1, ['(', [
+ 'NanDisposePersistent',
+ 'NanObjectWrapHandle'].join('|'), ')\\s*\\(\\s*([^\\s\\)]+)'].join('')]);
+
+/* Since NanPersistent there is no need for NanMakeWeakPersistent, key group 1 */
+groups.push([1, '(NanMakeWeakPersistent)\\s*\\(\\s*([^\\s,]+)\\s*,\\s*']);
+
+/* Many methods of v8::Object and others now return v8::MaybeLocal<T>, key group 3 */
+groups.push([3, ['([\\s])([^\\s]+)->(', [
+ 'GetEndColumn',
+ 'GetFunction',
+ 'GetLineNumber',
+ 'NewInstance',
+ 'GetPropertyNames',
+ 'GetOwnPropertyNames',
+ 'GetSourceLine',
+ 'GetStartColumn',
+ 'ObjectProtoToString',
+ 'ToArrayIndex',
+ 'ToDetailString',
+ 'CallAsConstructor',
+ 'CallAsFunction',
+ 'CloneElementAt',
+ 'Delete',
+ 'ForceSet',
+ 'Get',
+ 'GetPropertyAttributes',
+ 'GetRealNamedProperty',
+ 'GetRealNamedPropertyInPrototypeChain',
+ 'Has',
+ 'HasOwnProperty',
+ 'HasRealIndexedProperty',
+ 'HasRealNamedCallbackProperty',
+ 'HasRealNamedProperty',
+ 'Set',
+ 'SetAccessor',
+ 'SetIndexedPropertyHandler',
+ 'SetNamedPropertyHandler',
+ 'SetPrototype'].join('|'), ')\\('].join('')]);
+
+/* You should get an error if any of these fail anyways,
+ or handle the error better, it is indicated either way, key group 2 */
+groups.push([2, ['NanNew(<(?:v8\\:\\:)?(', ['Date', 'String', 'RegExp'].join('|'), ')>)(\\([^\\)]*\\))(?!\\.ToLocalChecked\\(\\))'].join('')]);
+
+/* v8::Value::Equals now returns a v8::Maybe, key group 3 */
+groups.push([3, '([\\s\\(\\)])([^\\s\\(\\)]+)->(Equals)\\(([^\\s\\)]+)']);
+
+/* NanPersistent makes this unnecessary, key group 1 */
+groups.push([1, '(NanAssignPersistent)(?:<v8\\:\\:[^>]+>)?\\(([^,]+),\\s*']);
+
+/* args has been renamed to info, key group 2 */
+groups.push([2, '(\\W)(args)(\\W)'])
+
+/* node::ObjectWrap was replaced with NanObjectWrap, key group 2 */
+groups.push([2, '(\\W)(?:node\\:\\:)?(ObjectWrap)(\\W)']);
+
+/* v8::Persistent was replaced with NanPersistent, key group 2 */
+groups.push([2, '(\\W)(?:v8\\:\\:)?(Persistent)(\\W)']);
+
+/* counts the number of capturing groups in a well-formed regular expression,
+ ignoring non-capturing groups and escaped parentheses */
+function groupcount(s) {
+ var positive = s.match(/\((?!\?)/g),
+ negative = s.match(/\\\(/g);
+ return (positive ? positive.length : 0) - (negative ? negative.length : 0);
+}
+
+/* compute the absolute position of each key group in the joined master RegExp */
+for (i = 1, length = groups.length; i < length; i++) {
+ total += groupcount(groups[i - 1][1]);
+ groups[i][0] += total;
+}
+
+/* create the master RegExp, whis is the union of all the groups' expressions */
+master = new RegExp(groups.map(function (a) { return a[1]; }).join('|'), 'gm');
+
+/* replacement function for String.replace, receives 21 arguments */
+function replace() {
+ /* simple expressions */
+ switch (arguments[groups[0][0]]) {
+ case '_NAN_':
+ return 'NAN_';
+ case 'NODE_SET_METHOD':
+ return 'NanSetMethod';
+ case 'NODE_SET_PROTOTYPE_METHOD':
+ return 'NanSetPrototypeMethod';
+ case 'NanAsciiString':
+ return 'NanUtf8String';
+ case 'NanEscapeScope':
+ return 'scope.Escape';
+ case 'NanReturnNull':
+ return 'info.GetReturnValue().SetNull';
+ case 'NanReturnValue':
+ return 'info.GetReturnValue().Set';
+ case 'NanUcs2String':
+ return 'v8::String::Value';
+ default:
+ }
+
+ /* macros without arguments */
+ switch (arguments[groups[1][0]]) {
+ case 'NanEscapableScope':
+ return 'NanEscapableScope scope'
+ case 'NanReturnUndefined':
+ return 'return';
+ case 'NanScope':
+ return 'NanScope scope';
+ default:
+ }
+
+ /* TryCatch, emulate negative backref */
+ if (arguments[groups[2][0]] === 'TryCatch') {
+ return arguments[groups[2][0] - 1] ? arguments[0] : 'NanTryCatch';
+ }
+
+ /* NanNew("foo") --> NanNew("foo").ToLocalChecked() */
+ if (arguments[groups[3][0]] === 'NanNew') {
+ return [arguments[0], '.ToLocalChecked()'].join('');
+ }
+
+ /* insert warning for removed functions as comment on new line above */
+ switch (arguments[groups[4][0]]) {
+ case 'GetIndexedPropertiesExternalArrayData':
+ case 'GetIndexedPropertiesExternalArrayDataLength':
+ case 'GetIndexedPropertiesExternalArrayDataType':
+ case 'GetIndexedPropertiesPixelData':
+ case 'GetIndexedPropertiesPixelDataLength':
+ case 'HasIndexedPropertiesInExternalArrayData':
+ case 'HasIndexedPropertiesInPixelData':
+ case 'SetIndexedPropertiesToExternalArrayData':
+ case 'SetIndexedPropertiesToPixelData':
+ return arguments[groups[4][0] - 1] ? arguments[0] : [warning1, arguments[0]].join('');
+ default:
+ }
+
+ /* remove unnecessary NanScope() */
+ switch (arguments[groups[5][0]]) {
+ case 'NAN_GETTER':
+ case 'NAN_METHOD':
+ case 'NAN_SETTER':
+ case 'NAN_INDEX_DELETER':
+ case 'NAN_INDEX_ENUMERATOR':
+ case 'NAN_INDEX_GETTER':
+ case 'NAN_INDEX_QUERY':
+ case 'NAN_INDEX_SETTER':
+ case 'NAN_PROPERTY_DELETER':
+ case 'NAN_PROPERTY_ENUMERATOR':
+ case 'NAN_PROPERTY_GETTER':
+ case 'NAN_PROPERTY_QUERY':
+ case 'NAN_PROPERTY_SETTER':
+ return arguments[groups[5][0] - 1];
+ default:
+ }
+
+ /* Value converstion */
+ switch (arguments[groups[6][0]]) {
+ case 'Boolean':
+ case 'Int32':
+ case 'Integer':
+ case 'Number':
+ case 'Object':
+ case 'String':
+ case 'Uint32':
+ return [arguments[groups[6][0] - 2], 'NanTo<v8::', arguments[groups[6][0]], '>(', arguments[groups[6][0] - 1]].join('');
+ default:
+ }
+
+ /* other value conversion */
+ switch (arguments[groups[7][0]]) {
+ case 'BooleanValue':
+ return [arguments[groups[7][0] - 2], 'NanTo<bool>(', arguments[groups[7][0] - 1]].join('');
+ case 'Int32Value':
+ return [arguments[groups[7][0] - 2], 'NanTo<int32_t>(', arguments[groups[7][0] - 1]].join('');
+ case 'IntegerValue':
+ return [arguments[groups[7][0] - 2], 'NanTo<int64_t>(', arguments[groups[7][0] - 1]].join('');
+ case 'Uint32Value':
+ return [arguments[groups[7][0] - 2], 'NanTo<uint32_t>(', arguments[groups[7][0] - 1]].join('');
+ default:
+ }
+
+ /* NAN_WEAK_CALLBACK */
+ if (arguments[groups[8][0]] === 'NAN_WEAK_CALLBACK') {
+ return ['template<typename T>\nvoid ',
+ arguments[groups[8][0] + 1], '(const NanWeakCallbackInfo<T> &data)'].join('');
+ }
+
+ /* use methods on NAN classes instead */
+ switch (arguments[groups[9][0]]) {
+ case 'NanDisposePersistent':
+ return [arguments[groups[9][0] + 1], '.Reset('].join('');
+ case 'NanObjectWrapHandle':
+ return [arguments[groups[9][0] + 1], '->handle('].join('');
+ default:
+ }
+
+ /* use method on NanPersistent instead */
+ if (arguments[groups[10][0]] === 'NanMakeWeakPersistent') {
+ return arguments[groups[10][0] + 1] + '.SetWeak(';
+ }
+
+ /* These return Maybes, the upper ones take no arguments */
+ switch (arguments[groups[11][0]]) {
+ case 'GetEndColumn':
+ case 'GetFunction':
+ case 'GetLineNumber':
+ case 'GetOwnPropertyNames':
+ case 'GetPropertyNames':
+ case 'GetSourceLine':
+ case 'GetStartColumn':
+ case 'NewInstance':
+ case 'ObjectProtoToString':
+ case 'ToArrayIndex':
+ case 'ToDetailString':
+ return [arguments[groups[11][0] - 2], 'Nan', arguments[groups[11][0]], '(', arguments[groups[11][0] - 1]].join('');
+ case 'CallAsConstructor':
+ case 'CallAsFunction':
+ case 'CloneElementAt':
+ case 'Delete':
+ case 'ForceSet':
+ case 'Get':
+ case 'GetPropertyAttributes':
+ case 'GetRealNamedProperty':
+ case 'GetRealNamedPropertyInPrototypeChain':
+ case 'Has':
+ case 'HasOwnProperty':
+ case 'HasRealIndexedProperty':
+ case 'HasRealNamedCallbackProperty':
+ case 'HasRealNamedProperty':
+ case 'Set':
+ case 'SetAccessor':
+ case 'SetIndexedPropertyHandler':
+ case 'SetNamedPropertyHandler':
+ case 'SetPrototype':
+ return [arguments[groups[11][0] - 2], 'Nan', arguments[groups[11][0]], '(', arguments[groups[11][0] - 1], ', '].join('');
+ default:
+ }
+
+ /* Automatic ToLocalChecked(), take it or leave it */
+ switch (arguments[groups[12][0]]) {
+ case 'Date':
+ case 'String':
+ case 'RegExp':
+ return ['NanNew', arguments[groups[12][0] - 1], arguments[groups[12][0] + 1], '.ToLocalChecked()'].join('');
+ default:
+ }
+
+ /* NanEquals is now required for uniformity */
+ if (arguments[groups[13][0]] === 'Equals') {
+ return [arguments[groups[13][0] - 1], 'NanEquals(', arguments[groups[13][0] - 1], ', ', arguments[groups[13][0] + 1]].join('');
+ }
+
+ /* use method on replacement class instead */
+ if (arguments[groups[14][0]] === 'NanAssignPersistent') {
+ return [arguments[groups[14][0] + 1], '.Reset('].join('');
+ }
+
+ /* args --> info */
+ if (arguments[groups[15][0]] === 'args') {
+ return [arguments[groups[15][0] - 1], 'info', arguments[groups[15][0] + 1]].join('');
+ }
+
+ /* ObjectWrap --> NanObjectWrap */
+ if (arguments[groups[16][0]] === 'ObjectWrap') {
+ return [arguments[groups[16][0] - 1], 'NanObjectWrap', arguments[groups[16][0] + 1]].join('');
+ }
+
+ /* Persistent --> NanPersistent */
+ if (arguments[groups[17][0]] === 'Persistent') {
+ return [arguments[groups[17][0] - 1], 'NanPersistent', arguments[groups[17][0] + 1]].join('');
+ }
+
+ /* This should not happen. A switch is probably missing a case if it does. */
+ throw 'Unhandled match: ' + arguments[0];
+}
+
+/* reads a file, runs replacement and writes it back */
+function processFile(file) {
+ fs.readFile(file, {encoding: 'utf8'}, function (err, data) {
+ if (err) {
+ throw err;
+ }
+
+ /* run replacement twice, might need more runs */
+ fs.writeFile(file, data.replace(master, replace).replace(master, replace), function (err) {
+ if (err) {
+ throw err;
+ }
+ });
+ });
+}
+
+/* process file names from command line and process the identified files */
+for (i = 2, length = process.argv.length; i < length; i++) {
+ glob(process.argv[i], function (err, matches) {
+ if (err) {
+ throw err;
+ }
+ matches.forEach(processFile);
+ });
+}
--- /dev/null
+1to2 naively converts source code files from NAN 1 to NAN 2. There will be erroneous conversions,
+false positives and missed opportunities. The input files are rewritten in place. Make sure that
+you have backups. You will have to manually review the changes afterwards and do some touchups.
+
+```sh
+$ tools/1to2.js
+
+ Usage: 1to2 [options] <file ...>
+
+ Options:
+
+ -h, --help output usage information
+ -V, --version output the version number
+```
--- /dev/null
+{
+ "name": "1to2",
+ "version": "1.0.0",
+ "description": "NAN 1 -> 2 Migration Script",
+ "main": "1to2.js",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/nodejs/nan.git"
+ },
+ "contributors": [
+ "Benjamin Byholm <bbyholm@abo.fi> (https://github.com/kkoopa/)",
+ "Mathias Küsel (https://github.com/mathiask88/)"
+ ],
+ "dependencies": {
+ "glob": "~5.0.10",
+ "commander": "~2.8.1"
+ },
+ "license": "MIT"
+}
--- /dev/null
+sauce_connect: true
+loopback: airtap.local
+browsers:
+ - name: chrome
+ version: latest
+ - name: firefox
+ version: latest
+ - name: safari
+ version: latest
+ - name: microsoftedge
+ version: latest
+ - name: ie
+ version: latest
+ - name: iphone
+ version: latest
--- /dev/null
+language: node_js
+node_js:
+ - lts/*
+addons:
+ sauce_connect: true
+ hosts:
+ - airtap.local
+env:
+ global:
+ - secure: i51rE9rZGHbcZWlL58j3H1qtL23OIV2r0X4TcQKNI3pw2mubdHFJmfPNNO19ItfReu8wwQMxOehKamwaNvqMiKWyHfn/QcThFQysqzgGZ6AgnUbYx9od6XFNDeWd1sVBf7QBAL07y7KWlYGWCwFwWjabSVySzQhEBdisPcskfkI=
+ - secure: BKq6/5z9LK3KDkTjs7BGeBZ1KsWgz+MsAXZ4P64NSeVGFaBdXU45+ww1mwxXFt5l22/mhyOQZfebQl+kGVqRSZ+DEgQeCymkNZ6CD8c6w6cLuOJXiXwuu/cDM2DD0tfGeu2YZC7yEikP7BqEFwH3D324rRzSGLF2RSAAwkOI7bE=
--- /dev/null
+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.
--- /dev/null
+# typedarray-to-buffer [![travis][travis-image]][travis-url] [![npm][npm-image]][npm-url] [![downloads][downloads-image]][downloads-url] [![javascript style guide][standard-image]][standard-url]
+
+[travis-image]: https://img.shields.io/travis/feross/typedarray-to-buffer/master.svg
+[travis-url]: https://travis-ci.org/feross/typedarray-to-buffer
+[npm-image]: https://img.shields.io/npm/v/typedarray-to-buffer.svg
+[npm-url]: https://npmjs.org/package/typedarray-to-buffer
+[downloads-image]: https://img.shields.io/npm/dm/typedarray-to-buffer.svg
+[downloads-url]: https://npmjs.org/package/typedarray-to-buffer
+[standard-image]: https://img.shields.io/badge/code_style-standard-brightgreen.svg
+[standard-url]: https://standardjs.com
+
+#### Convert a typed array to a [Buffer](https://github.com/feross/buffer) without a copy.
+
+[![saucelabs][saucelabs-image]][saucelabs-url]
+
+[saucelabs-image]: https://saucelabs.com/browser-matrix/typedarray-to-buffer.svg
+[saucelabs-url]: https://saucelabs.com/u/typedarray-to-buffer
+
+Say you're using the ['buffer'](https://github.com/feross/buffer) module on npm, or
+[browserify](http://browserify.org/) and you're working with lots of binary data.
+
+Unfortunately, sometimes the browser or someone else's API gives you a typed array like
+`Uint8Array` to work with and you need to convert it to a `Buffer`. What do you do?
+
+Of course: `Buffer.from(uint8array)`
+
+But, alas, every time you do `Buffer.from(uint8array)` **the entire array gets copied**.
+The `Buffer` constructor does a copy; this is
+defined by the [node docs](http://nodejs.org/api/buffer.html) and the 'buffer' module
+matches the node API exactly.
+
+So, how can we avoid this expensive copy in
+[performance critical applications](https://github.com/feross/buffer/issues/22)?
+
+***Simply use this module, of course!***
+
+If you have an `ArrayBuffer`, you don't need this module, because
+`Buffer.from(arrayBuffer)`
+[is already efficient](https://nodejs.org/api/buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length).
+
+## install
+
+```bash
+npm install typedarray-to-buffer
+```
+
+## usage
+
+To convert a typed array to a `Buffer` **without a copy**, do this:
+
+```js
+var toBuffer = require('typedarray-to-buffer')
+
+var arr = new Uint8Array([1, 2, 3])
+arr = toBuffer(arr)
+
+// arr is a buffer now!
+
+arr.toString() // '\u0001\u0002\u0003'
+arr.readUInt16BE(0) // 258
+```
+
+## how it works
+
+If the browser supports typed arrays, then `toBuffer` will **augment the typed array** you
+pass in with the `Buffer` methods and return it. See [how does Buffer
+work?](https://github.com/feross/buffer#how-does-it-work) for more about how augmentation
+works.
+
+This module uses the typed array's underlying `ArrayBuffer` to back the new `Buffer`. This
+respects the "view" on the `ArrayBuffer`, i.e. `byteOffset` and `byteLength`. In other
+words, if you do `toBuffer(new Uint32Array([1, 2, 3]))`, then the new `Buffer` will
+contain `[1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0]`, **not** `[1, 2, 3]`. And it still doesn't
+require a copy.
+
+If the browser doesn't support typed arrays, then `toBuffer` will create a new `Buffer`
+object, copy the data into it, and return it. There's no simple performance optimization
+we can do for old browsers. Oh well.
+
+If this module is used in node, then it will just call `Buffer.from`. This is just for
+the convenience of modules that work in both node and the browser.
+
+## license
+
+MIT. Copyright (C) [Feross Aboukhadijeh](http://feross.org).
--- /dev/null
+/**
+ * Convert a typed array to a Buffer without a copy
+ *
+ * Author: Feross Aboukhadijeh <https://feross.org>
+ * License: MIT
+ *
+ * `npm install typedarray-to-buffer`
+ */
+
+var isTypedArray = require('is-typedarray').strict
+
+module.exports = function typedarrayToBuffer (arr) {
+ if (isTypedArray(arr)) {
+ // To avoid a copy, use the typed array's underlying ArrayBuffer to back new Buffer
+ var buf = Buffer.from(arr.buffer)
+ if (arr.byteLength !== arr.buffer.byteLength) {
+ // Respect the "view", i.e. byteOffset and byteLength, without doing a copy
+ buf = buf.slice(arr.byteOffset, arr.byteOffset + arr.byteLength)
+ }
+ return buf
+ } else {
+ // Pass through all other types to `Buffer.from`
+ return Buffer.from(arr)
+ }
+}
--- /dev/null
+This software is released under the MIT license:
+
+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.
--- /dev/null
+# is-typedarray [![locked](http://badges.github.io/stability-badges/dist/locked.svg)](http://github.com/badges/stability-badges)
+
+Detect whether or not an object is a
+[Typed Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays).
+
+## Usage
+
+[![NPM](https://nodei.co/npm/is-typedarray.png)](https://nodei.co/npm/is-typedarray/)
+
+### isTypedArray(array)
+
+Returns `true` when array is a Typed Array, and `false` when it is not.
+
+## License
+
+MIT. See [LICENSE.md](http://github.com/hughsk/is-typedarray/blob/master/LICENSE.md) for details.
--- /dev/null
+module.exports = isTypedArray
+isTypedArray.strict = isStrictTypedArray
+isTypedArray.loose = isLooseTypedArray
+
+var toString = Object.prototype.toString
+var names = {
+ '[object Int8Array]': true
+ , '[object Int16Array]': true
+ , '[object Int32Array]': true
+ , '[object Uint8Array]': true
+ , '[object Uint8ClampedArray]': true
+ , '[object Uint16Array]': true
+ , '[object Uint32Array]': true
+ , '[object Float32Array]': true
+ , '[object Float64Array]': true
+}
+
+function isTypedArray(arr) {
+ return (
+ isStrictTypedArray(arr)
+ || isLooseTypedArray(arr)
+ )
+}
+
+function isStrictTypedArray(arr) {
+ return (
+ arr instanceof Int8Array
+ || arr instanceof Int16Array
+ || arr instanceof Int32Array
+ || arr instanceof Uint8Array
+ || arr instanceof Uint8ClampedArray
+ || arr instanceof Uint16Array
+ || arr instanceof Uint32Array
+ || arr instanceof Float32Array
+ || arr instanceof Float64Array
+ )
+}
+
+function isLooseTypedArray(arr) {
+ return names[toString.call(arr)]
+}
--- /dev/null
+{
+ "name": "is-typedarray",
+ "version": "1.0.0",
+ "description": "Detect whether or not an object is a Typed Array",
+ "main": "index.js",
+ "scripts": {
+ "test": "node test"
+ },
+ "author": {
+ "name": "Hugh Kennedy",
+ "email": "hughskennedy@gmail.com",
+ "url": "http://hughsk.io/"
+ },
+ "license": "MIT",
+ "dependencies": {},
+ "devDependencies": {
+ "tape": "^2.13.1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/hughsk/is-typedarray.git"
+ },
+ "keywords": [
+ "typed",
+ "array",
+ "detect",
+ "is",
+ "util"
+ ],
+ "bugs": {
+ "url": "https://github.com/hughsk/is-typedarray/issues"
+ },
+ "homepage": "https://github.com/hughsk/is-typedarray",
+ "gitHead": "0617cfa871686cf541af62b144f130488f44f6fe",
+ "_id": "is-typedarray@1.0.0",
+ "_shasum": "e479c80858df0c1b11ddda6940f96011fcda4a9a",
+ "_from": "is-typedarray@^1.0.0",
+ "_npmVersion": "2.7.5",
+ "_nodeVersion": "0.10.36",
+ "_npmUser": {
+ "name": "hughsk",
+ "email": "hughskennedy@gmail.com"
+ },
+ "dist": {
+ "shasum": "e479c80858df0c1b11ddda6940f96011fcda4a9a",
+ "tarball": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
+ },
+ "maintainers": [
+ {
+ "name": "hughsk",
+ "email": "hughskennedy@gmail.com"
+ }
+ ],
+ "directories": {},
+ "_resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
+}
--- /dev/null
+var test = require('tape')
+var ista = require('./')
+
+test('strict', function(t) {
+ t.ok(ista.strict(new Int8Array), 'Int8Array')
+ t.ok(ista.strict(new Int16Array), 'Int16Array')
+ t.ok(ista.strict(new Int32Array), 'Int32Array')
+ t.ok(ista.strict(new Uint8Array), 'Uint8Array')
+ t.ok(ista.strict(new Uint16Array), 'Uint16Array')
+ t.ok(ista.strict(new Uint32Array), 'Uint32Array')
+ t.ok(ista.strict(new Float32Array), 'Float32Array')
+ t.ok(ista.strict(new Float64Array), 'Float64Array')
+
+ t.ok(!ista.strict(new Array), 'Array')
+ t.ok(!ista.strict([]), '[]')
+
+ t.end()
+})
+
+test('loose', function(t) {
+ t.ok(ista.loose(new Int8Array), 'Int8Array')
+ t.ok(ista.loose(new Int16Array), 'Int16Array')
+ t.ok(ista.loose(new Int32Array), 'Int32Array')
+ t.ok(ista.loose(new Uint8Array), 'Uint8Array')
+ t.ok(ista.loose(new Uint16Array), 'Uint16Array')
+ t.ok(ista.loose(new Uint32Array), 'Uint32Array')
+ t.ok(ista.loose(new Float32Array), 'Float32Array')
+ t.ok(ista.loose(new Float64Array), 'Float64Array')
+
+ t.ok(!ista.loose(new Array), 'Array')
+ t.ok(!ista.loose([]), '[]')
+
+ t.end()
+})
--- /dev/null
+{
+ "name": "typedarray-to-buffer",
+ "description": "Convert a typed array to a Buffer without a copy",
+ "version": "3.1.5",
+ "author": {
+ "name": "Feross Aboukhadijeh",
+ "email": "feross@feross.org",
+ "url": "http://feross.org/"
+ },
+ "bugs": {
+ "url": "https://github.com/feross/typedarray-to-buffer/issues"
+ },
+ "dependencies": {
+ "is-typedarray": "^1.0.0"
+ },
+ "devDependencies": {
+ "airtap": "0.0.4",
+ "standard": "*",
+ "tape": "^4.0.0"
+ },
+ "homepage": "http://feross.org",
+ "keywords": [
+ "buffer",
+ "typed array",
+ "convert",
+ "no copy",
+ "uint8array",
+ "uint16array",
+ "uint32array",
+ "int16array",
+ "int32array",
+ "float32array",
+ "float64array",
+ "browser",
+ "arraybuffer",
+ "dataview"
+ ],
+ "license": "MIT",
+ "main": "index.js",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/feross/typedarray-to-buffer.git"
+ },
+ "scripts": {
+ "test": "standard && npm run test-node && npm run test-browser",
+ "test-browser": "airtap -- test/*.js",
+ "test-browser-local": "airtap --local -- test/*.js",
+ "test-node": "tape test/*.js"
+ },
+ "gitHead": "328a952e480a143bdc3fc98a2133490e28e2b3a2",
+ "_id": "typedarray-to-buffer@3.1.5",
+ "_npmVersion": "5.7.1",
+ "_nodeVersion": "8.10.0",
+ "_npmUser": {
+ "name": "feross",
+ "email": "feross@feross.org"
+ },
+ "dist": {
+ "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
+ "shasum": "a97ee7a9ff42691b9f783ff1bc5112fe3fca9080",
+ "tarball": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
+ "fileCount": 7,
+ "unpackedSize": 8835
+ },
+ "maintainers": [
+ {
+ "name": "feross",
+ "email": "feross@feross.org"
+ }
+ ],
+ "directories": {},
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/typedarray-to-buffer_3.1.5_1520537433687_0.8471076032703442"
+ },
+ "_shasum": "a97ee7a9ff42691b9f783ff1bc5112fe3fca9080",
+ "_from": "typedarray-to-buffer@^3.1.5",
+ "_resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz"
+}
--- /dev/null
+var test = require('tape')
+var toBuffer = require('../')
+
+test('convert to buffer from Uint8Array', function (t) {
+ if (typeof Uint8Array !== 'undefined') {
+ var arr = new Uint8Array([1, 2, 3])
+ arr = toBuffer(arr)
+
+ t.deepEqual(arr, Buffer.from([1, 2, 3]), 'contents equal')
+ t.ok(Buffer.isBuffer(arr), 'is buffer')
+ t.equal(arr.readUInt8(0), 1)
+ t.equal(arr.readUInt8(1), 2)
+ t.equal(arr.readUInt8(2), 3)
+ } else {
+ t.pass('browser lacks Uint8Array support, skip test')
+ }
+ t.end()
+})
+
+test('convert to buffer from another arrayview type (Uint32Array)', function (t) {
+ if (typeof Uint32Array !== 'undefined' && Buffer.TYPED_ARRAY_SUPPORT !== false) {
+ var arr = new Uint32Array([1, 2, 3])
+ arr = toBuffer(arr)
+
+ t.deepEqual(arr, Buffer.from([1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0]), 'contents equal')
+ t.ok(Buffer.isBuffer(arr), 'is buffer')
+ t.equal(arr.readUInt32LE(0), 1)
+ t.equal(arr.readUInt32LE(4), 2)
+ t.equal(arr.readUInt32LE(8), 3)
+ t.equal(arr instanceof Uint8Array, true)
+ } else {
+ t.pass('browser lacks Uint32Array support, skip test')
+ }
+ t.end()
+})
+
+test('convert to buffer from ArrayBuffer', function (t) {
+ if (typeof Uint32Array !== 'undefined' && Buffer.TYPED_ARRAY_SUPPORT !== false) {
+ var arr = new Uint32Array([1, 2, 3]).subarray(1, 2)
+ arr = toBuffer(arr)
+
+ t.deepEqual(arr, Buffer.from([2, 0, 0, 0]), 'contents equal')
+ t.ok(Buffer.isBuffer(arr), 'is buffer')
+ t.equal(arr.readUInt32LE(0), 2)
+ t.equal(arr instanceof Uint8Array, true)
+ } else {
+ t.pass('browser lacks ArrayBuffer support, skip test')
+ }
+ t.end()
+})
--- /dev/null
+{
+ "preset": "crockford",
+ "validateIndentation": "\t",
+ "disallowKeywords": ["with"],
+ "disallowDanglingUnderscores": null
+}
--- /dev/null
+{
+ "bitwise": false,
+ "curly": true,
+ "eqeqeq": true,
+ "forin": true,
+ "freeze": true,
+ "latedef": "function",
+ "noarg": true,
+ "nonbsp": true,
+ "nonew": true,
+ "plusplus": false,
+ "undef": true,
+ "unused": true,
+ "strict": false,
+ "maxparams": 6,
+ "maxdepth": 4,
+ "maxstatements": false,
+ "maxlen": 200,
+ "browser": true,
+ "browserify": true,
+ "devel": true,
+ "jquery": false,
+ "mocha": true,
+ "node": false,
+ "shelljs": false,
+ "worker": false
+}
--- /dev/null
+/node_modules/
--- /dev/null
+The MIT License (MIT)
+
+Copyright (c) 2015 Iñaki Baz Castillo, <ibc@aliax.net>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
--- /dev/null
+# yaeti
+
+Yet Another [EventTarget](https://developer.mozilla.org/es/docs/Web/API/EventTarget) Implementation.
+
+The library exposes both the [EventTarget](https://developer.mozilla.org/es/docs/Web/API/EventTarget) interface and the [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event) interface.
+
+
+## Installation
+
+```bash
+$ npm install yaeti --save
+```
+
+
+## Usage
+
+```javascript
+var yaeti = require('yaeti');
+
+
+// Custom class we want to make an EventTarget.
+function Foo() {
+ // Make Foo an EventTarget.
+ yaeti.EventTarget.call(this);
+}
+
+// Create an instance.
+var foo = new Foo();
+
+function listener1() {
+ console.log('listener1');
+}
+
+function listener2() {
+ console.log('listener2');
+}
+
+foo.addEventListener('bar', listener1);
+foo.addEventListener('bar', listener2);
+foo.removeEventListener('bar', listener1);
+
+var event = new yaeti.Event('bar');
+
+foo.dispatchEvent(event);
+
+
+// Output:
+// => "listener2"
+```
+
+
+
+## API
+
+
+#### `yaeti.EventTarget` interface
+
+Implementation of the [EventTarget](https://developer.mozilla.org/es/docs/Web/API/EventTarget) interface.
+
+* Make a custom class inherit from `EventTarget`:
+```javascript
+function Foo() {
+ yaeti.EventTarget.call(this);
+}
+```
+
+* Make an existing object an `EventTarget`:
+```javascript
+yaeti.EventTarget.call(obj);
+```
+
+The interface implements the `addEventListener`, `removeEventListener` and `dispatchEvent` methods as defined by the W3C.
+
+
+##### `listeners` read-only property
+
+Returns an object whose keys are configured event types (String) and whose values are an array of listeners (functions) for those event types.
+
+
+#### `yaeti.Event` interface
+
+Implementation of the [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event) interface.
+
+*NOTE:* Just useful in Node (the browser already exposes the native `Event` interface).
+
+```javascript
+var event = new yaeti.Event('bar');
+```
+
+
+## Author
+
+[Iñaki Baz Castillo](https://github.com/ibc)
+
+
+## License
+
+[MIT](./LICENSE)
--- /dev/null
+var
+ /**
+ * Dependencies.
+ */
+ gulp = require('gulp'),
+ jscs = require('gulp-jscs'),
+ jshint = require('gulp-jshint'),
+ stylish = require('gulp-jscs-stylish');
+
+
+gulp.task('lint', function () {
+ var src = ['gulpfile.js', 'index.js', 'lib/**/*.js'];
+
+ return gulp.src(src)
+ .pipe(jshint('.jshintrc')) // Enforce good practics.
+ .pipe(jscs('.jscsrc')) // Enforce style guide.
+ .pipe(stylish.combineWithHintResults())
+ .pipe(jshint.reporter('jshint-stylish', {verbose: true}))
+ .pipe(jshint.reporter('fail'));
+});
+
+
+gulp.task('default', gulp.task('lint'));
--- /dev/null
+module.exports = {
+ EventTarget : require('./lib/EventTarget'),
+ Event : require('./lib/Event')
+};
--- /dev/null
+/**
+ * In browsers export the native Event interface.
+ */
+
+module.exports = global.Event;
--- /dev/null
+/**
+ * Expose the Event class.
+ */
+module.exports = _Event;
+
+
+function _Event(type) {
+ this.type = type;
+ this.isTrusted = false;
+
+ // Set a flag indicating this is not a DOM Event object
+ this._yaeti = true;
+}
--- /dev/null
+/**
+ * Expose the _EventTarget class.
+ */
+module.exports = _EventTarget;
+
+function _EventTarget() {
+ // Do nothing if called for a native EventTarget object..
+ if (typeof this.addEventListener === 'function') {
+ return;
+ }
+
+ this._listeners = {};
+
+ this.addEventListener = _addEventListener;
+ this.removeEventListener = _removeEventListener;
+ this.dispatchEvent = _dispatchEvent;
+}
+
+Object.defineProperties(_EventTarget.prototype, {
+ listeners: {
+ get: function () {
+ return this._listeners;
+ }
+ }
+});
+
+function _addEventListener(type, newListener) {
+ var
+ listenersType,
+ i, listener;
+
+ if (!type || !newListener) {
+ return;
+ }
+
+ listenersType = this._listeners[type];
+ if (listenersType === undefined) {
+ this._listeners[type] = listenersType = [];
+ }
+
+ for (i = 0; !!(listener = listenersType[i]); i++) {
+ if (listener === newListener) {
+ return;
+ }
+ }
+
+ listenersType.push(newListener);
+}
+
+function _removeEventListener(type, oldListener) {
+ var
+ listenersType,
+ i, listener;
+
+ if (!type || !oldListener) {
+ return;
+ }
+
+ listenersType = this._listeners[type];
+ if (listenersType === undefined) {
+ return;
+ }
+
+ for (i = 0; !!(listener = listenersType[i]); i++) {
+ if (listener === oldListener) {
+ listenersType.splice(i, 1);
+ break;
+ }
+ }
+
+ if (listenersType.length === 0) {
+ delete this._listeners[type];
+ }
+}
+
+function _dispatchEvent(event) {
+ var
+ type,
+ listenersType,
+ dummyListener,
+ stopImmediatePropagation = false,
+ i, listener;
+
+ if (!event || typeof event.type !== 'string') {
+ throw new Error('`event` must have a valid `type` property');
+ }
+
+ // Do some stuff to emulate DOM Event behavior (just if this is not a
+ // DOM Event object)
+ if (event._yaeti) {
+ event.target = this;
+ event.cancelable = true;
+ }
+
+ // Attempt to override the stopImmediatePropagation() method
+ try {
+ event.stopImmediatePropagation = function () {
+ stopImmediatePropagation = true;
+ };
+ } catch (error) {}
+
+ type = event.type;
+ listenersType = (this._listeners[type] || []);
+
+ dummyListener = this['on' + type];
+ if (typeof dummyListener === 'function') {
+ dummyListener.call(this, event);
+ }
+
+ for (i = 0; !!(listener = listenersType[i]); i++) {
+ if (stopImmediatePropagation) {
+ break;
+ }
+
+ listener.call(this, event);
+ }
+
+ return !event.defaultPrevented;
+}
--- /dev/null
+{
+ "name": "yaeti",
+ "version": "0.0.6",
+ "description": "Yet Another EventTarget Implementation",
+ "author": {
+ "name": "Iñaki Baz Castillo",
+ "email": "ibc@aliax.net"
+ },
+ "license": "MIT",
+ "main": "index.js",
+ "browser": {
+ "./lib/Event.js": "./lib/Event.browser.js"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/ibc/yaeti.git"
+ },
+ "devDependencies": {
+ "gulp": "git+https://github.com/gulpjs/gulp.git#4.0",
+ "gulp-jscs": "^1.6.0",
+ "gulp-jscs-stylish": "^1.1.0",
+ "gulp-jshint": "^1.11.2",
+ "jshint-stylish": "~1.0.2"
+ },
+ "engines": {
+ "node": ">=0.10.32"
+ },
+ "gitHead": "5b838a23410b9ed0eb1b74bc3a266c1af204b8f2",
+ "bugs": {
+ "url": "https://github.com/ibc/yaeti/issues"
+ },
+ "homepage": "https://github.com/ibc/yaeti",
+ "_id": "yaeti@0.0.6",
+ "scripts": {},
+ "_shasum": "f26f484d72684cf42bedfb76970aa1608fbf9577",
+ "_from": "yaeti@^0.0.6",
+ "_npmVersion": "2.5.1",
+ "_nodeVersion": "0.12.0",
+ "_npmUser": {
+ "name": "ibc",
+ "email": "ibc@aliax.net"
+ },
+ "dist": {
+ "shasum": "f26f484d72684cf42bedfb76970aa1608fbf9577",
+ "tarball": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz"
+ },
+ "maintainers": [
+ {
+ "name": "ibc",
+ "email": "ibc@aliax.net"
+ }
+ ],
+ "_npmOperationalInternal": {
+ "host": "packages-13-west.internal.npmjs.com",
+ "tmp": "tmp/yaeti-0.0.6.tgz_1458254413403_0.9036164651624858"
+ },
+ "directories": {},
+ "_resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz"
+}
--- /dev/null
+{
+ "name": "websocket",
+ "description": "Websocket Client & Server Library implementing the WebSocket protocol as specified in RFC 6455.",
+ "keywords": [
+ "websocket",
+ "websockets",
+ "socket",
+ "networking",
+ "comet",
+ "push",
+ "RFC-6455",
+ "realtime",
+ "server",
+ "client"
+ ],
+ "author": {
+ "name": "Brian McKelvey",
+ "email": "theturtle32@gmail.com",
+ "url": "https://github.com/theturtle32"
+ },
+ "contributors": [
+ {
+ "name": "Iñaki Baz Castillo",
+ "email": "ibc@aliax.net",
+ "url": "http://dev.sipdoc.net"
+ }
+ ],
+ "version": "1.0.30",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/theturtle32/WebSocket-Node.git"
+ },
+ "homepage": "https://github.com/theturtle32/WebSocket-Node",
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "dependencies": {
+ "debug": "^2.2.0",
+ "nan": "^2.14.0",
+ "typedarray-to-buffer": "^3.1.5",
+ "yaeti": "^0.0.6"
+ },
+ "devDependencies": {
+ "buffer-equal": "^1.0.0",
+ "faucet": "^0.0.1",
+ "gulp": "^4.0.2",
+ "gulp-jshint": "^2.0.4",
+ "jshint-stylish": "^2.2.1",
+ "jshint": "^2.0.0",
+ "tape": "^4.9.1"
+ },
+ "config": {
+ "verbose": false
+ },
+ "scripts": {
+ "install": "(node-gyp rebuild 2> builderror.log) || (exit 0)",
+ "test": "faucet test/unit",
+ "gulp": "gulp"
+ },
+ "main": "index",
+ "directories": {
+ "lib": "./lib"
+ },
+ "browser": "lib/browser.js",
+ "license": "Apache-2.0",
+ "gitHead": "7db960ef47f9e87799a17e5a7ef3f46d3b1b9227",
+ "bugs": {
+ "url": "https://github.com/theturtle32/WebSocket-Node/issues"
+ },
+ "_id": "websocket@1.0.30",
+ "_nodeVersion": "12.9.0",
+ "_npmVersion": "6.10.2",
+ "dist": {
+ "integrity": "sha512-aO6klgaTdSMkhfl5VVJzD5fm+Srhh5jLYbS15+OiI1sN6h/RU/XW6WN9J1uVIpUKNmsTvT3Hs35XAFjn9NMfOw==",
+ "shasum": "91d3bd00c3d43e916f0cf962f8f8c451bb0b2373",
+ "tarball": "https://registry.npmjs.org/websocket/-/websocket-1.0.30.tgz",
+ "fileCount": 29,
+ "unpackedSize": 162651,
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdeopQCRA9TVsSAnZWagAA8iQP/i7CvxHeOFy4J0UOzOoO\nEY/boKZdf4NuASAKRWujz4vUAoMQp48r7cHG/t+VjXu8saeJiZpASaEEgEem\n79x67cyfFNGPGVvln3cwn79ABZZXv0mJjzw/5ZJuz4A2pzS6nEE56J/H1JxX\nN8DMjku5bG3XzJ/xsNuiTwqNFHYF54SI/UkHAI0Ok9ZuLqITLQ2Ub08Ujq5z\nLaW9ePL66aWzUS5hD8hjtUpMw+/MyDIeLUynyUvZB2gnjsLTZjfASsbIgOSk\npW0E0Mp4GVE1jJ39JohY/KHmV8XF2cl9lJz6HiRuPbZwPqpKHZFlUj7mPcQs\nHS1pHQE5mz2Q/GT+UPCLESO/1TmIECoG0K15WdaXLfEGUDpOVbtNM1riSaBG\nTjz9TAPoBiUwoAT6Rr4teaD0An5aXbwbWjs0qdQjr0Ml8Ckn/zhuLq0k2haG\neSb0loKwMoNQPEOwA4lEnodw+lumurlH5cJjY0G7p+mjWnTEHG2X2WxL8Z23\nfvKzZ4JZQ3/aN4QGkfbos4B85tp5m0lXM/uDyu9v8cqEEbnMNsGZIzDPkAk/\nBCQOi/IkwGQNjoJrkhMTCFzeopjGvUqzMqnAMRhh9fi2XBoP/flPAPT+PUsj\nZKgpmCA/f7UX5THnna2hjocDa+4gKvPOKAipGsSrHqS4gQKg+yTkCfx5WtR4\nbLIC\r\n=nkBA\r\n-----END PGP SIGNATURE-----\r\n"
+ },
+ "maintainers": [
+ {
+ "name": "theturtle32",
+ "email": "brian@worlize.com"
+ }
+ ],
+ "_npmUser": {
+ "name": "theturtle32",
+ "email": "theturtle32@gmail.com"
+ },
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/websocket_1.0.30_1568311887357_0.18656696326018363"
+ },
+ "_hasShrinkwrap": false,
+ "_shasum": "91d3bd00c3d43e916f0cf962f8f8c451bb0b2373",
+ "_from": "websocket@",
+ "_resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.30.tgz"
+}
--- /dev/null
+/*!
+ * BufferUtil originally from:
+ * ws: a node.js websocket client
+ * Copyright(c) 2015 Einar Otto Stangvik <einaros@gmail.com>
+ * MIT Licensed
+ */
+
+#include <v8.h>
+#include <node.h>
+#include <node_version.h>
+#include <node_buffer.h>
+#include <node_object_wrap.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <stdio.h>
+#include "nan.h"
+
+using namespace v8;
+using namespace node;
+
+class BufferUtil : public ObjectWrap
+{
+public:
+
+ static void Initialize(v8::Local<v8::Object> target)
+ {
+ Nan::HandleScope scope;
+ Local<FunctionTemplate> t = Nan::New<FunctionTemplate>(New);
+ t->InstanceTemplate()->SetInternalFieldCount(1);
+ Nan::SetMethod(t, "unmask", BufferUtil::Unmask);
+ Nan::SetMethod(t, "mask", BufferUtil::Mask);
+ Nan::SetMethod(t, "merge", BufferUtil::Merge);
+ Nan::Set(target, Nan::New<String>("BufferUtil").ToLocalChecked(), t->GetFunction());
+ }
+
+protected:
+
+ static NAN_METHOD(New)
+ {
+ Nan::HandleScope scope;
+ BufferUtil* bufferUtil = new BufferUtil();
+ bufferUtil->Wrap(info.This());
+ info.GetReturnValue().Set(info.This());
+ }
+
+ static NAN_METHOD(Merge)
+ {
+ Nan::HandleScope scope;
+ Local<Object> bufferObj = info[0]->ToObject();
+ char* buffer = Buffer::Data(bufferObj);
+ Local<Array> array = Local<Array>::Cast(info[1]);
+ unsigned int arrayLength = array->Length();
+ size_t offset = 0;
+ unsigned int i;
+ for (i = 0; i < arrayLength; ++i) {
+ Local<Object> src = array->Get(i)->ToObject();
+ size_t length = Buffer::Length(src);
+ memcpy(buffer + offset, Buffer::Data(src), length);
+ offset += length;
+ }
+ info.GetReturnValue().Set(Nan::True());
+ }
+
+ static NAN_METHOD(Unmask)
+ {
+ Nan::HandleScope scope;
+ Local<Object> buffer_obj = info[0]->ToObject();
+ size_t length = Buffer::Length(buffer_obj);
+ Local<Object> mask_obj = info[1]->ToObject();
+ unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj);
+ unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj);
+ size_t len32 = length / 4;
+ unsigned int i;
+ for (i = 0; i < len32; ++i) *(from + i) ^= *mask;
+ from += i;
+ switch (length % 4) {
+ case 3: *((unsigned char*)from+2) = *((unsigned char*)from+2) ^ ((unsigned char*)mask)[2];
+ case 2: *((unsigned char*)from+1) = *((unsigned char*)from+1) ^ ((unsigned char*)mask)[1];
+ case 1: *((unsigned char*)from ) = *((unsigned char*)from ) ^ ((unsigned char*)mask)[0];
+ case 0:;
+ }
+ info.GetReturnValue().Set(Nan::True());
+ }
+
+ static NAN_METHOD(Mask)
+ {
+ Nan::HandleScope scope;
+ Local<Object> buffer_obj = info[0]->ToObject();
+ Local<Object> mask_obj = info[1]->ToObject();
+ unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj);
+ Local<Object> output_obj = info[2]->ToObject();
+ unsigned int dataOffset = info[3]->Int32Value();
+ unsigned int length = info[4]->Int32Value();
+ unsigned int* to = (unsigned int*)(Buffer::Data(output_obj) + dataOffset);
+ unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj);
+ unsigned int len32 = length / 4;
+ unsigned int i;
+ for (i = 0; i < len32; ++i) *(to + i) = *(from + i) ^ *mask;
+ to += i;
+ from += i;
+ switch (length % 4) {
+ case 3: *((unsigned char*)to+2) = *((unsigned char*)from+2) ^ *((unsigned char*)mask+2);
+ case 2: *((unsigned char*)to+1) = *((unsigned char*)from+1) ^ *((unsigned char*)mask+1);
+ case 1: *((unsigned char*)to ) = *((unsigned char*)from ) ^ *((unsigned char*)mask);
+ case 0:;
+ }
+ info.GetReturnValue().Set(Nan::True());
+ }
+};
+
+#if !NODE_VERSION_AT_LEAST(0,10,0)
+extern "C"
+#endif
+void init (Local<Object> target)
+{
+ Nan::HandleScope scope;
+ BufferUtil::Initialize(target);
+}
+
+NODE_MODULE(bufferutil, init)
--- /dev/null
+/*!
+ * UTF-8 Validation Code originally from:
+ * ws: a node.js websocket client
+ * Copyright(c) 2015 Einar Otto Stangvik <einaros@gmail.com>
+ * MIT Licensed
+ */
+
+#include <v8.h>
+#include <node.h>
+#include <node_version.h>
+#include <node_buffer.h>
+#include <node_object_wrap.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <stdio.h>
+#include "nan.h"
+
+using namespace v8;
+using namespace node;
+
+#define UNI_SUR_HIGH_START (uint32_t) 0xD800
+#define UNI_SUR_LOW_END (uint32_t) 0xDFFF
+#define UNI_REPLACEMENT_CHAR (uint32_t) 0x0000FFFD
+#define UNI_MAX_LEGAL_UTF32 (uint32_t) 0x0010FFFF
+
+static const uint8_t trailingBytesForUTF8[256] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
+};
+
+static const uint32_t offsetsFromUTF8[6] = {
+ 0x00000000, 0x00003080, 0x000E2080,
+ 0x03C82080, 0xFA082080, 0x82082080
+};
+
+static int isLegalUTF8(const uint8_t *source, const int length)
+{
+ uint8_t a;
+ const uint8_t *srcptr = source+length;
+ switch (length) {
+ default: return 0;
+ /* Everything else falls through when "true"... */
+ /* RFC3629 makes 5 & 6 bytes UTF-8 illegal
+ case 6: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
+ case 5: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; */
+ case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
+ case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
+ case 2: if ((a = (*--srcptr)) > 0xBF) return 0;
+ switch (*source) {
+ /* no fall-through in this inner switch */
+ case 0xE0: if (a < 0xA0) return 0; break;
+ case 0xED: if (a > 0x9F) return 0; break;
+ case 0xF0: if (a < 0x90) return 0; break;
+ case 0xF4: if (a > 0x8F) return 0; break;
+ default: if (a < 0x80) return 0;
+ }
+
+ case 1: if (*source >= 0x80 && *source < 0xC2) return 0;
+ }
+ if (*source > 0xF4) return 0;
+ return 1;
+}
+
+int is_valid_utf8 (size_t len, char *value)
+{
+ /* is the string valid UTF-8? */
+ for (unsigned int i = 0; i < len; i++) {
+ uint32_t ch = 0;
+ uint8_t extrabytes = trailingBytesForUTF8[(uint8_t) value[i]];
+
+ if (extrabytes + i >= len)
+ return 0;
+
+ if (isLegalUTF8 ((uint8_t *) (value + i), extrabytes + 1) == 0) return 0;
+
+ switch (extrabytes) {
+ case 5 : ch += (uint8_t) value[i++]; ch <<= 6;
+ case 4 : ch += (uint8_t) value[i++]; ch <<= 6;
+ case 3 : ch += (uint8_t) value[i++]; ch <<= 6;
+ case 2 : ch += (uint8_t) value[i++]; ch <<= 6;
+ case 1 : ch += (uint8_t) value[i++]; ch <<= 6;
+ case 0 : ch += (uint8_t) value[i];
+ }
+
+ ch -= offsetsFromUTF8[extrabytes];
+
+ if (ch <= UNI_MAX_LEGAL_UTF32) {
+ if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
+ return 0;
+ } else {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+class Validation : public ObjectWrap
+{
+public:
+
+ static void Initialize(v8::Local<v8::Object> target)
+ {
+ Nan::HandleScope scope;
+ Local<FunctionTemplate> t = Nan::New<FunctionTemplate>(New);
+ t->InstanceTemplate()->SetInternalFieldCount(1);
+ Nan::SetMethod(t, "isValidUTF8", Validation::IsValidUTF8);
+ Nan::Set(target, Nan::New<String>("Validation").ToLocalChecked(), t->GetFunction());
+ }
+
+protected:
+
+ static NAN_METHOD(New)
+ {
+ Nan::HandleScope scope;
+ Validation* validation = new Validation();
+ validation->Wrap(info.This());
+ info.GetReturnValue().Set(info.This());
+ }
+
+ static NAN_METHOD(IsValidUTF8)
+ {
+ Nan::HandleScope scope;
+ if (!Buffer::HasInstance(info[0])) {
+ return Nan::ThrowTypeError("First argument needs to be a buffer");
+ }
+ Local<Object> buffer_obj = info[0]->ToObject();
+ char *buffer_data = Buffer::Data(buffer_obj);
+ size_t buffer_length = Buffer::Length(buffer_obj);
+ info.GetReturnValue().Set(is_valid_utf8(buffer_length, buffer_data) == 1 ? Nan::True() : Nan::False());
+ }
+};
+#if !NODE_VERSION_AT_LEAST(0,10,0)
+extern "C"
+#endif
+void init (Local<Object> target)
+{
+ Nan::HandleScope scope;
+ Validation::Initialize(target);
+}
+
+NODE_MODULE(validation, init)
--- /dev/null
+// This file was copied from https://github.com/substack/node-bufferlist
+// and modified to be able to copy bytes from the bufferlist directly into
+// a pre-existing fixed-size buffer without an additional memory allocation.
+
+// bufferlist.js
+// Treat a linked list of buffers as a single variable-size buffer.
+var Buffer = require('buffer').Buffer;
+var EventEmitter = require('events').EventEmitter;
+var bufferAllocUnsafe = require('../lib/utils').bufferAllocUnsafe;
+
+module.exports = BufferList;
+module.exports.BufferList = BufferList; // backwards compatibility
+
+function BufferList(opts) {
+ if (!(this instanceof BufferList)) return new BufferList(opts);
+ EventEmitter.call(this);
+ var self = this;
+
+ if (typeof(opts) == 'undefined') opts = {};
+
+ // default encoding to use for take(). Leaving as 'undefined'
+ // makes take() return a Buffer instead.
+ self.encoding = opts.encoding;
+
+ var head = { next : null, buffer : null };
+ var last = { next : null, buffer : null };
+
+ // length can get negative when advanced past the end
+ // and this is the desired behavior
+ var length = 0;
+ self.__defineGetter__('length', function () {
+ return length;
+ });
+
+ // keep an offset of the head to decide when to head = head.next
+ var offset = 0;
+
+ // Write to the bufferlist. Emits 'write'. Always returns true.
+ self.write = function (buf) {
+ if (!head.buffer) {
+ head.buffer = buf;
+ last = head;
+ }
+ else {
+ last.next = { next : null, buffer : buf };
+ last = last.next;
+ }
+ length += buf.length;
+ self.emit('write', buf);
+ return true;
+ };
+
+ self.end = function (buf) {
+ if (Buffer.isBuffer(buf)) self.write(buf);
+ };
+
+ // Push buffers to the end of the linked list. (deprecated)
+ // Return this (self).
+ self.push = function () {
+ var args = [].concat.apply([], arguments);
+ args.forEach(self.write);
+ return self;
+ };
+
+ // For each buffer, perform some action.
+ // If fn's result is a true value, cut out early.
+ // Returns this (self).
+ self.forEach = function (fn) {
+ if (!head.buffer) return bufferAllocUnsafe(0);
+
+ if (head.buffer.length - offset <= 0) return self;
+ var firstBuf = head.buffer.slice(offset);
+
+ var b = { buffer : firstBuf, next : head.next };
+
+ while (b && b.buffer) {
+ var r = fn(b.buffer);
+ if (r) break;
+ b = b.next;
+ }
+
+ return self;
+ };
+
+ // Create a single Buffer out of all the chunks or some subset specified by
+ // start and one-past the end (like slice) in bytes.
+ self.join = function (start, end) {
+ if (!head.buffer) return bufferAllocUnsafe(0);
+ if (start == undefined) start = 0;
+ if (end == undefined) end = self.length;
+
+ var big = bufferAllocUnsafe(end - start);
+ var ix = 0;
+ self.forEach(function (buffer) {
+ if (start < (ix + buffer.length) && ix < end) {
+ // at least partially contained in the range
+ buffer.copy(
+ big,
+ Math.max(0, ix - start),
+ Math.max(0, start - ix),
+ Math.min(buffer.length, end - ix)
+ );
+ }
+ ix += buffer.length;
+ if (ix > end) return true; // stop processing past end
+ });
+
+ return big;
+ };
+
+ self.joinInto = function (targetBuffer, targetStart, sourceStart, sourceEnd) {
+ if (!head.buffer) return new bufferAllocUnsafe(0);
+ if (sourceStart == undefined) sourceStart = 0;
+ if (sourceEnd == undefined) sourceEnd = self.length;
+
+ var big = targetBuffer;
+ if (big.length - targetStart < sourceEnd - sourceStart) {
+ throw new Error("Insufficient space available in target Buffer.");
+ }
+ var ix = 0;
+ self.forEach(function (buffer) {
+ if (sourceStart < (ix + buffer.length) && ix < sourceEnd) {
+ // at least partially contained in the range
+ buffer.copy(
+ big,
+ Math.max(targetStart, targetStart + ix - sourceStart),
+ Math.max(0, sourceStart - ix),
+ Math.min(buffer.length, sourceEnd - ix)
+ );
+ }
+ ix += buffer.length;
+ if (ix > sourceEnd) return true; // stop processing past end
+ });
+
+ return big;
+ };
+
+ // Advance the buffer stream by n bytes.
+ // If n the aggregate advance offset passes the end of the buffer list,
+ // operations such as .take() will return empty strings until enough data is
+ // pushed.
+ // Returns this (self).
+ self.advance = function (n) {
+ offset += n;
+ length -= n;
+ while (head.buffer && offset >= head.buffer.length) {
+ offset -= head.buffer.length;
+ head = head.next
+ ? head.next
+ : { buffer : null, next : null }
+ ;
+ }
+ if (head.buffer === null) last = { next : null, buffer : null };
+ self.emit('advance', n);
+ return self;
+ };
+
+ // Take n bytes from the start of the buffers.
+ // Returns a string.
+ // If there are less than n bytes in all the buffers or n is undefined,
+ // returns the entire concatenated buffer string.
+ self.take = function (n, encoding) {
+ if (n == undefined) n = self.length;
+ else if (typeof n !== 'number') {
+ encoding = n;
+ n = self.length;
+ }
+ var b = head;
+ if (!encoding) encoding = self.encoding;
+ if (encoding) {
+ var acc = '';
+ self.forEach(function (buffer) {
+ if (n <= 0) return true;
+ acc += buffer.toString(
+ encoding, 0, Math.min(n,buffer.length)
+ );
+ n -= buffer.length;
+ });
+ return acc;
+ } else {
+ // If no 'encoding' is specified, then return a Buffer.
+ return self.join(0, n);
+ }
+ };
+
+ // The entire concatenated buffer as a string.
+ self.toString = function () {
+ return self.take('binary');
+ };
+}
+require('util').inherits(BufferList, EventEmitter);
--- /dev/null
+(The MIT License)
+
+Copyright (c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the 'Software'), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
--- /dev/null
+# wscat
+
+WebSocket cat.
+
+## Installation
+
+This module needs to be installed globally so use the `-g` flag when installing:
+
+```
+npm install -g wscat
+```
+
+## Usage
+
+```
+$ wscat -c ws://echo.websocket.org
+connected (press CTRL+C to quit)
+> hi there
+< hi there
+> are you a happy parrot?
+< are you a happy parrot?
+```
+
+## License
+
+MIT
--- /dev/null
+#!/usr/bin/env node
+
+/*!
+ * ws: a node.js websocket client
+ * Copyright(c) 2011 Einar Otto Stangvik <einaros@gmail.com>
+ * MIT Licensed
+ */
+
+const EventEmitter = require('events');
+const fs = require('fs');
+const program = require('commander');
+const read = require('read');
+const readline = require('readline');
+const tty = require('tty');
+const WebSocket = require('ws');
+
+/**
+ * InputReader - processes console input.
+ *
+ * @extends EventEmitter
+ */
+class Console extends EventEmitter {
+ constructor() {
+ super();
+
+ this.stdin = process.stdin;
+ this.stdout = process.stdout;
+
+ this.readlineInterface = readline.createInterface(this.stdin, this.stdout);
+
+ this.readlineInterface
+ .on('line', data => {
+ this.emit('line', data);
+ })
+ .on('close', () => {
+ this.emit('close');
+ });
+
+ this._resetInput = () => {
+ this.clear();
+ };
+ }
+
+ static get Colors() {
+ return {
+ Red: '\u001b[31m',
+ Green: '\u001b[32m',
+ Yellow: '\u001b[33m',
+ Blue: '\u001b[34m',
+ Default: '\u001b[39m'
+ };
+ }
+
+ static get Types() {
+ return {
+ Incoming: '< ',
+ Control: '',
+ Error: 'error: '
+ };
+ }
+
+ prompt() {
+ this.readlineInterface.prompt();
+ }
+
+ print(type, msg, color) {
+ if (tty.isatty(1)) {
+ this.clear();
+
+ if (program.execute) color = type = '';
+ else if (!program.color) color = '';
+
+ this.stdout.write(color + type + msg + Console.Colors.Default + '\n');
+ this.prompt();
+ } else if (type === Console.Types.Incoming) {
+ this.stdout.write(msg + '\n');
+ } else {
+ // is a control message and we're not in a tty... drop it.
+ }
+ }
+
+ clear() {
+ if (tty.isatty(1)) {
+ this.stdout.write('\u001b[2K\u001b[3D');
+ }
+ }
+
+ pause() {
+ this.stdin.on('keypress', this._resetInput);
+ }
+
+ resume() {
+ this.stdin.removeListener('keypress', this._resetInput);
+ }
+}
+
+function collect(val, memo) {
+ memo.push(val);
+ return memo;
+}
+
+function noop() {}
+
+/**
+ * The actual application
+ */
+const version = require('../package.json').version;
+
+program
+ .version(version)
+ .usage('[options] (--listen <port> | --connect <url>)')
+ .option('-l, --listen <port>', 'listen on port')
+ .option('-c, --connect <url>', 'connect to a websocket server')
+ .option('-p, --protocol <version>', 'optional protocol version')
+ .option('-o, --origin <origin>', 'optional origin')
+ .option('-x, --execute <command>', 'execute command after connecting')
+ .option('-w, --wait <seconds>', 'wait given seconds after executing command')
+ .option('--host <host>', 'optional host')
+ .option('-s, --subprotocol <protocol>', 'optional subprotocol', collect, [])
+ .option('-n, --no-check', 'Do not check for unauthorized certificates')
+ .option(
+ '-H, --header <header:value>',
+ 'Set an HTTP header. Repeat to set multiple. (--connect only)',
+ collect,
+ []
+ )
+ .option(
+ '--auth <username:password>',
+ 'Add basic HTTP authentication header. (--connect only)'
+ )
+ .option('--ca <ca>', 'Specify a Certificate Authority (--connect only)')
+ .option('--cert <cert>', 'Specify a Client SSL Certificate (--connect only)')
+ .option(
+ '--key <key>',
+ "Specify a Client SSL Certificate's key (--connect only)"
+ )
+ .option(
+ '--passphrase [passphrase]',
+ "Specify a Client SSL Certificate Key's passphrase (--connect only). " +
+ "If you don't provide a value, it will be prompted for."
+ )
+ .option('--no-color', 'Run without color')
+ .option(
+ '--slash',
+ 'Enable slash commands for control frames ' +
+ '(/ping, /pong, /close [code [, reason]])'
+ )
+ .parse(process.argv);
+
+if (program.listen && program.connect) {
+ console.error('\u001b[33merror: use either --listen or --connect\u001b[39m');
+ process.exit(-1);
+}
+
+if (program.listen) {
+ const wsConsole = new Console();
+ wsConsole.pause();
+
+ let ws = null;
+ const wss = new WebSocket.Server({ port: program.listen }, () => {
+ wsConsole.print(
+ Console.Types.Control,
+ `listening on port ${program.listen} (press CTRL+C to quit)`,
+ Console.Colors.Green
+ );
+ wsConsole.clear();
+ });
+
+ wsConsole.on('close', () => {
+ if (ws) ws.close();
+ process.exit(0);
+ });
+
+ wsConsole.on('line', data => {
+ if (ws) {
+ ws.send(data);
+ wsConsole.prompt();
+ }
+ });
+
+ wss.on('connection', newClient => {
+ if (ws) return newClient.terminate();
+
+ ws = newClient;
+ wsConsole.resume();
+ wsConsole.prompt();
+ wsConsole.print(
+ Console.Types.Control,
+ 'client connected',
+ Console.Colors.Green
+ );
+
+ ws.on('close', code => {
+ wsConsole.print(
+ Console.Types.Control,
+ `disconnected (code: ${code})`,
+ Console.Colors.Green
+ );
+ wsConsole.clear();
+ wsConsole.pause();
+ ws = null;
+ });
+
+ ws.on('error', err => {
+ wsConsole.print(Console.Types.Error, err.message, Console.Colors.Yellow);
+ });
+
+ ws.on('message', data => {
+ wsConsole.print(Console.Types.Incoming, data, Console.Colors.Blue);
+ });
+ });
+
+ wss.on('error', err => {
+ wsConsole.print(Console.Types.Error, err.message, Console.Colors.Yellow);
+ process.exit(-1);
+ });
+} else if (program.connect) {
+ const options = {};
+ const cont = () => {
+ const wsConsole = new Console();
+
+ const headers = program.header.reduce((acc, cur) => {
+ const i = cur.indexOf(':');
+ const key = cur.slice(0, i);
+ const value = cur.slice(i + 1);
+ acc[key] = value;
+ return acc;
+ }, {});
+
+ if (program.auth) {
+ headers.Authorization =
+ 'Basic ' + Buffer.from(program.auth).toString('base64');
+ }
+ if (program.host) headers.Host = program.host;
+ if (program.protocol) options.protocolVersion = +program.protocol;
+ if (program.origin) options.origin = program.origin;
+ if (!program.check) options.rejectUnauthorized = program.check;
+ if (program.ca) options.ca = fs.readFileSync(program.ca);
+ if (program.cert) options.cert = fs.readFileSync(program.cert);
+ if (program.key) options.key = fs.readFileSync(program.key);
+
+ let connectUrl = program.connect;
+ if (!connectUrl.match(/\w+:\/\/.*$/i)) {
+ connectUrl = `ws://${connectUrl}`;
+ }
+
+ options.headers = headers;
+ const ws = new WebSocket(connectUrl, program.subprotocol, options);
+
+ ws.on('open', () => {
+ if (program.execute) {
+ ws.send(program.execute);
+ setTimeout(() => {
+ ws.close();
+ }, program.wait ? program.wait * 1000 : 2000);
+ } else {
+ wsConsole.print(
+ Console.Types.Control,
+ 'connected (press CTRL+C to quit)',
+ Console.Colors.Green
+ );
+
+ wsConsole.on('line', data => {
+ if (program.slash && data[0] === '/') {
+ const toks = data.split(/\s+/);
+ switch (toks[0].substr(1)) {
+ case 'ping':
+ ws.ping(noop);
+ break;
+ case 'pong':
+ ws.pong(noop);
+ break;
+ case 'close': {
+ let closeStatusCode = 1000;
+ let closeReason = '';
+ if (toks.length >= 2) {
+ closeStatusCode = parseInt(toks[1]);
+ }
+ if (toks.length >= 3) {
+ closeReason = toks.slice(2).join(' ');
+ }
+ if (closeReason.length > 0) {
+ ws.close(closeStatusCode, closeReason);
+ } else {
+ ws.close(closeStatusCode);
+ }
+ break;
+ }
+ default:
+ wsConsole.print(
+ Console.Types.Error,
+ 'Unrecognized slash command.',
+ Console.Colors.Yellow
+ );
+ }
+ } else {
+ ws.send(data);
+ }
+ wsConsole.prompt();
+ });
+ }
+ });
+
+ ws.on('close', code => {
+ if (!program.execute) {
+ wsConsole.print(
+ Console.Types.Control,
+ `disconnected (code: ${code})`,
+ Console.Colors.Green
+ );
+ }
+ wsConsole.clear();
+ process.exit();
+ });
+
+ ws.on('error', err => {
+ wsConsole.print(Console.Types.Error, err.message, Console.Colors.Yellow);
+ process.exit(-1);
+ });
+
+ ws.on('message', data => {
+ wsConsole.print(Console.Types.Incoming, data, Console.Colors.Blue);
+ });
+
+ ws.on('ping', () => {
+ wsConsole.print(
+ Console.Types.Incoming,
+ 'Received ping',
+ Console.Colors.Blue
+ );
+ });
+
+ ws.on('pong', () => {
+ wsConsole.print(
+ Console.Types.Incoming,
+ 'Received pong',
+ Console.Colors.Blue
+ );
+ });
+
+ wsConsole.on('close', () => {
+ ws.close();
+ process.exit();
+ });
+ };
+
+ if (program.passphrase === true) {
+ read(
+ {
+ prompt: 'Passphrase: ',
+ silent: true,
+ replace: '*'
+ },
+ (err, passphrase) => {
+ options.passphrase = passphrase;
+ cont();
+ }
+ );
+ } else if (typeof program.passphrase === 'string') {
+ options.passphrase = program.passphrase;
+ cont();
+ } else {
+ cont();
+ }
+} else {
+ program.help();
+}
--- /dev/null
+
+2.15.0 / 2018-03-07
+==================
+
+ * Update downloads badge to point to graph of downloads over time instead of duplicating link to npm
+ * Arguments description
+
+2.14.1 / 2018-02-07
+==================
+
+ * Fix typing of help function
+
+2.14.0 / 2018-02-05
+==================
+
+ * only register the option:version event once
+ * Fixes issue #727: Passing empty string for option on command is set to undefined
+ * enable eqeqeq rule
+ * resolves #754 add linter configuration to project
+ * resolves #560 respect custom name for version option
+ * document how to override the version flag
+ * document using options per command
+
+2.13.0 / 2018-01-09
+==================
+
+ * Do not print default for --no-
+ * remove trailing spaces in command help
+ * Update CI's Node.js to LTS and latest version
+ * typedefs: Command and Option types added to commander namespace
+
+2.12.2 / 2017-11-28
+==================
+
+ * fix: typings are not shipped
+
+2.12.1 / 2017-11-23
+==================
+
+ * Move @types/node to dev dependency
+
+2.12.0 / 2017-11-22
+==================
+
+ * add attributeName() method to Option objects
+ * Documentation updated for options with --no prefix
+ * typings: `outputHelp` takes a string as the first parameter
+ * typings: use overloads
+ * feat(typings): update to match js api
+ * Print default value in option help
+ * Fix translation error
+ * Fail when using same command and alias (#491)
+ * feat(typings): add help callback
+ * fix bug when description is add after command with options (#662)
+ * Format js code
+ * Rename History.md to CHANGELOG.md (#668)
+ * feat(typings): add typings to support TypeScript (#646)
+ * use current node
+
+2.11.0 / 2017-07-03
+==================
+
+ * Fix help section order and padding (#652)
+ * feature: support for signals to subcommands (#632)
+ * Fixed #37, --help should not display first (#447)
+ * Fix translation errors. (#570)
+ * Add package-lock.json
+ * Remove engines
+ * Upgrade package version
+ * Prefix events to prevent conflicts between commands and options (#494)
+ * Removing dependency on graceful-readlink
+ * Support setting name in #name function and make it chainable
+ * Add .vscode directory to .gitignore (Visual Studio Code metadata)
+ * Updated link to ruby commander in readme files
+
+2.10.0 / 2017-06-19
+==================
+
+ * Update .travis.yml. drop support for older node.js versions.
+ * Fix require arguments in README.md
+ * On SemVer you do not start from 0.0.1
+ * Add missing semi colon in readme
+ * Add save param to npm install
+ * node v6 travis test
+ * Update Readme_zh-CN.md
+ * Allow literal '--' to be passed-through as an argument
+ * Test subcommand alias help
+ * link build badge to master branch
+ * Support the alias of Git style sub-command
+ * added keyword commander for better search result on npm
+ * Fix Sub-Subcommands
+ * test node.js stable
+ * Fixes TypeError when a command has an option called `--description`
+ * Update README.md to make it beginner friendly and elaborate on the difference between angled and square brackets.
+ * Add chinese Readme file
+
+2.9.0 / 2015-10-13
+==================
+
+ * Add option `isDefault` to set default subcommand #415 @Qix-
+ * Add callback to allow filtering or post-processing of help text #434 @djulien
+ * Fix `undefined` text in help information close #414 #416 @zhiyelee
+
+2.8.1 / 2015-04-22
+==================
+
+ * Back out `support multiline description` Close #396 #397
+
+2.8.0 / 2015-04-07
+==================
+
+ * Add `process.execArg` support, execution args like `--harmony` will be passed to sub-commands #387 @DigitalIO @zhiyelee
+ * Fix bug in Git-style sub-commands #372 @zhiyelee
+ * Allow commands to be hidden from help #383 @tonylukasavage
+ * When git-style sub-commands are in use, yet none are called, display help #382 @claylo
+ * Add ability to specify arguments syntax for top-level command #258 @rrthomas
+ * Support multiline descriptions #208 @zxqfox
+
+2.7.1 / 2015-03-11
+==================
+
+ * Revert #347 (fix collisions when option and first arg have same name) which causes a bug in #367.
+
+2.7.0 / 2015-03-09
+==================
+
+ * Fix git-style bug when installed globally. Close #335 #349 @zhiyelee
+ * Fix collisions when option and first arg have same name. Close #346 #347 @tonylukasavage
+ * Add support for camelCase on `opts()`. Close #353 @nkzawa
+ * Add node.js 0.12 and io.js to travis.yml
+ * Allow RegEx options. #337 @palanik
+ * Fixes exit code when sub-command failing. Close #260 #332 @pirelenito
+ * git-style `bin` files in $PATH make sense. Close #196 #327 @zhiyelee
+
+2.6.0 / 2014-12-30
+==================
+
+ * added `Command#allowUnknownOption` method. Close #138 #318 @doozr @zhiyelee
+ * Add application description to the help msg. Close #112 @dalssoft
+
+2.5.1 / 2014-12-15
+==================
+
+ * fixed two bugs incurred by variadic arguments. Close #291 @Quentin01 #302 @zhiyelee
+
+2.5.0 / 2014-10-24
+==================
+
+ * add support for variadic arguments. Closes #277 @whitlockjc
+
+2.4.0 / 2014-10-17
+==================
+
+ * fixed a bug on executing the coercion function of subcommands option. Closes #270
+ * added `Command.prototype.name` to retrieve command name. Closes #264 #266 @tonylukasavage
+ * added `Command.prototype.opts` to retrieve all the options as a simple object of key-value pairs. Closes #262 @tonylukasavage
+ * fixed a bug on subcommand name. Closes #248 @jonathandelgado
+ * fixed function normalize doesn’t honor option terminator. Closes #216 @abbr
+
+2.3.0 / 2014-07-16
+==================
+
+ * add command alias'. Closes PR #210
+ * fix: Typos. Closes #99
+ * fix: Unused fs module. Closes #217
+
+2.2.0 / 2014-03-29
+==================
+
+ * add passing of previous option value
+ * fix: support subcommands on windows. Closes #142
+ * Now the defaultValue passed as the second argument of the coercion function.
+
+2.1.0 / 2013-11-21
+==================
+
+ * add: allow cflag style option params, unit test, fixes #174
+
+2.0.0 / 2013-07-18
+==================
+
+ * remove input methods (.prompt, .confirm, etc)
+
+1.3.2 / 2013-07-18
+==================
+
+ * add support for sub-commands to co-exist with the original command
+
+1.3.1 / 2013-07-18
+==================
+
+ * add quick .runningCommand hack so you can opt-out of other logic when running a sub command
+
+1.3.0 / 2013-07-09
+==================
+
+ * add EACCES error handling
+ * fix sub-command --help
+
+1.2.0 / 2013-06-13
+==================
+
+ * allow "-" hyphen as an option argument
+ * support for RegExp coercion
+
+1.1.1 / 2012-11-20
+==================
+
+ * add more sub-command padding
+ * fix .usage() when args are present. Closes #106
+
+1.1.0 / 2012-11-16
+==================
+
+ * add git-style executable subcommand support. Closes #94
+
+1.0.5 / 2012-10-09
+==================
+
+ * fix `--name` clobbering. Closes #92
+ * fix examples/help. Closes #89
+
+1.0.4 / 2012-09-03
+==================
+
+ * add `outputHelp()` method.
+
+1.0.3 / 2012-08-30
+==================
+
+ * remove invalid .version() defaulting
+
+1.0.2 / 2012-08-24
+==================
+
+ * add `--foo=bar` support [arv]
+ * fix password on node 0.8.8. Make backward compatible with 0.6 [focusaurus]
+
+1.0.1 / 2012-08-03
+==================
+
+ * fix issue #56
+ * fix tty.setRawMode(mode) was moved to tty.ReadStream#setRawMode() (i.e. process.stdin.setRawMode())
+
+1.0.0 / 2012-07-05
+==================
+
+ * add support for optional option descriptions
+ * add defaulting of `.version()` to package.json's version
+
+0.6.1 / 2012-06-01
+==================
+
+ * Added: append (yes or no) on confirmation
+ * Added: allow node.js v0.7.x
+
+0.6.0 / 2012-04-10
+==================
+
+ * Added `.prompt(obj, callback)` support. Closes #49
+ * Added default support to .choose(). Closes #41
+ * Fixed the choice example
+
+0.5.1 / 2011-12-20
+==================
+
+ * Fixed `password()` for recent nodes. Closes #36
+
+0.5.0 / 2011-12-04
+==================
+
+ * Added sub-command option support [itay]
+
+0.4.3 / 2011-12-04
+==================
+
+ * Fixed custom help ordering. Closes #32
+
+0.4.2 / 2011-11-24
+==================
+
+ * Added travis support
+ * Fixed: line-buffered input automatically trimmed. Closes #31
+
+0.4.1 / 2011-11-18
+==================
+
+ * Removed listening for "close" on --help
+
+0.4.0 / 2011-11-15
+==================
+
+ * Added support for `--`. Closes #24
+
+0.3.3 / 2011-11-14
+==================
+
+ * Fixed: wait for close event when writing help info [Jerry Hamlet]
+
+0.3.2 / 2011-11-01
+==================
+
+ * Fixed long flag definitions with values [felixge]
+
+0.3.1 / 2011-10-31
+==================
+
+ * Changed `--version` short flag to `-V` from `-v`
+ * Changed `.version()` so it's configurable [felixge]
+
+0.3.0 / 2011-10-31
+==================
+
+ * Added support for long flags only. Closes #18
+
+0.2.1 / 2011-10-24
+==================
+
+ * "node": ">= 0.4.x < 0.7.0". Closes #20
+
+0.2.0 / 2011-09-26
+==================
+
+ * Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs]
+
+0.1.0 / 2011-08-24
+==================
+
+ * Added support for custom `--help` output
+
+0.0.5 / 2011-08-18
+==================
+
+ * Changed: when the user enters nothing prompt for password again
+ * Fixed issue with passwords beginning with numbers [NuckChorris]
+
+0.0.4 / 2011-08-15
+==================
+
+ * Fixed `Commander#args`
+
+0.0.3 / 2011-08-15
+==================
+
+ * Added default option value support
+
+0.0.2 / 2011-08-15
+==================
+
+ * Added mask support to `Command#password(str[, mask], fn)`
+ * Added `Command#password(str, fn)`
+
+0.0.1 / 2010-01-03
+==================
+
+ * Initial release
--- /dev/null
+(The MIT License)
+
+Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--- /dev/null
+# Commander.js
+
+
+[![Build Status](https://api.travis-ci.org/tj/commander.js.svg?branch=master)](http://travis-ci.org/tj/commander.js)
+[![NPM Version](http://img.shields.io/npm/v/commander.svg?style=flat)](https://www.npmjs.org/package/commander)
+[![NPM Downloads](https://img.shields.io/npm/dm/commander.svg?style=flat)](https://npmcharts.com/compare/commander?minimal=true)
+[![Join the chat at https://gitter.im/tj/commander.js](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/tj/commander.js?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+
+ The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/commander-rb/commander).
+ [API documentation](http://tj.github.com/commander.js/)
+
+
+## Installation
+
+ $ npm install commander --save
+
+## Option parsing
+
+Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.
+
+```js
+#!/usr/bin/env node
+
+/**
+ * Module dependencies.
+ */
+
+var program = require('commander');
+
+program
+ .version('0.1.0')
+ .option('-p, --peppers', 'Add peppers')
+ .option('-P, --pineapple', 'Add pineapple')
+ .option('-b, --bbq-sauce', 'Add bbq sauce')
+ .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
+ .parse(process.argv);
+
+console.log('you ordered a pizza with:');
+if (program.peppers) console.log(' - peppers');
+if (program.pineapple) console.log(' - pineapple');
+if (program.bbqSauce) console.log(' - bbq');
+console.log(' - %s cheese', program.cheese);
+```
+
+Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc.
+
+Note that multi-word options starting with `--no` prefix negate the boolean value of the following word. For example, `--no-sauce` sets the value of `program.sauce` to false.
+
+```js
+#!/usr/bin/env node
+
+/**
+ * Module dependencies.
+ */
+
+var program = require('commander');
+
+program
+ .option('--no-sauce', 'Remove sauce')
+ .parse(process.argv);
+
+console.log('you ordered a pizza');
+if (program.sauce) console.log(' with sauce');
+else console.log(' without sauce');
+```
+
+## Version option
+
+Calling the `version` implicitly adds the `-V` and `--version` options to the command.
+When either of these options is present, the command prints the version number and exits.
+
+ $ ./examples/pizza -V
+ 0.0.1
+
+If you want your program to respond to the `-v` option instead of the `-V` option, simply pass custom flags to the `version` method using the same syntax as the `option` method.
+
+```js
+program
+ .version('0.0.1', '-v, --version')
+```
+
+The version flags can be named anything, but the long option is required.
+
+## Command-specific options
+
+You can attach options to a command.
+
+```js
+#!/usr/bin/env node
+
+var program = require('commander');
+
+program
+ .command('rm <dir>')
+ .option('-r, --recursive', 'Remove recursively')
+ .action(function (dir, cmd) {
+ console.log('remove ' + dir + (cmd.recursive ? ' recursively' : ''))
+ })
+
+program.parse(process.argv)
+```
+
+A command's options are validated when the command is used. Any unknown options will be reported as an error. However, if an action-based command does not define an action, then the options are not validated.
+
+## Coercion
+
+```js
+function range(val) {
+ return val.split('..').map(Number);
+}
+
+function list(val) {
+ return val.split(',');
+}
+
+function collect(val, memo) {
+ memo.push(val);
+ return memo;
+}
+
+function increaseVerbosity(v, total) {
+ return total + 1;
+}
+
+program
+ .version('0.1.0')
+ .usage('[options] <file ...>')
+ .option('-i, --integer <n>', 'An integer argument', parseInt)
+ .option('-f, --float <n>', 'A float argument', parseFloat)
+ .option('-r, --range <a>..<b>', 'A range', range)
+ .option('-l, --list <items>', 'A list', list)
+ .option('-o, --optional [value]', 'An optional value')
+ .option('-c, --collect [value]', 'A repeatable value', collect, [])
+ .option('-v, --verbose', 'A value that can be increased', increaseVerbosity, 0)
+ .parse(process.argv);
+
+console.log(' int: %j', program.integer);
+console.log(' float: %j', program.float);
+console.log(' optional: %j', program.optional);
+program.range = program.range || [];
+console.log(' range: %j..%j', program.range[0], program.range[1]);
+console.log(' list: %j', program.list);
+console.log(' collect: %j', program.collect);
+console.log(' verbosity: %j', program.verbose);
+console.log(' args: %j', program.args);
+```
+
+## Regular Expression
+```js
+program
+ .version('0.1.0')
+ .option('-s --size <size>', 'Pizza size', /^(large|medium|small)$/i, 'medium')
+ .option('-d --drink [drink]', 'Drink', /^(coke|pepsi|izze)$/i)
+ .parse(process.argv);
+
+console.log(' size: %j', program.size);
+console.log(' drink: %j', program.drink);
+```
+
+## Variadic arguments
+
+ The last argument of a command can be variadic, and only the last argument. To make an argument variadic you have to
+ append `...` to the argument name. Here is an example:
+
+```js
+#!/usr/bin/env node
+
+/**
+ * Module dependencies.
+ */
+
+var program = require('commander');
+
+program
+ .version('0.1.0')
+ .command('rmdir <dir> [otherDirs...]')
+ .action(function (dir, otherDirs) {
+ console.log('rmdir %s', dir);
+ if (otherDirs) {
+ otherDirs.forEach(function (oDir) {
+ console.log('rmdir %s', oDir);
+ });
+ }
+ });
+
+program.parse(process.argv);
+```
+
+ An `Array` is used for the value of a variadic argument. This applies to `program.args` as well as the argument passed
+ to your action as demonstrated above.
+
+## Specify the argument syntax
+
+```js
+#!/usr/bin/env node
+
+var program = require('commander');
+
+program
+ .version('0.1.0')
+ .arguments('<cmd> [env]')
+ .action(function (cmd, env) {
+ cmdValue = cmd;
+ envValue = env;
+ });
+
+program.parse(process.argv);
+
+if (typeof cmdValue === 'undefined') {
+ console.error('no command given!');
+ process.exit(1);
+}
+console.log('command:', cmdValue);
+console.log('environment:', envValue || "no environment given");
+```
+Angled brackets (e.g. `<cmd>`) indicate required input. Square brackets (e.g. `[env]`) indicate optional input.
+
+## Git-style sub-commands
+
+```js
+// file: ./examples/pm
+var program = require('commander');
+
+program
+ .version('0.1.0')
+ .command('install [name]', 'install one or more packages')
+ .command('search [query]', 'search with optional query')
+ .command('list', 'list packages installed', {isDefault: true})
+ .parse(process.argv);
+```
+
+When `.command()` is invoked with a description argument, no `.action(callback)` should be called to handle sub-commands, otherwise there will be an error. This tells commander that you're going to use separate executables for sub-commands, much like `git(1)` and other popular tools.
+The commander will try to search the executables in the directory of the entry script (like `./examples/pm`) with the name `program-command`, like `pm-install`, `pm-search`.
+
+Options can be passed with the call to `.command()`. Specifying `true` for `opts.noHelp` will remove the option from the generated help output. Specifying `true` for `opts.isDefault` will run the subcommand if no other subcommand is specified.
+
+If the program is designed to be installed globally, make sure the executables have proper modes, like `755`.
+
+### `--harmony`
+
+You can enable `--harmony` option in two ways:
+* Use `#! /usr/bin/env node --harmony` in the sub-commands scripts. Note some os version don’t support this pattern.
+* Use the `--harmony` option when call the command, like `node --harmony examples/pm publish`. The `--harmony` option will be preserved when spawning sub-command process.
+
+## Automated --help
+
+ The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:
+
+```
+ $ ./examples/pizza --help
+
+ Usage: pizza [options]
+
+ An application for pizzas ordering
+
+ Options:
+
+ -h, --help output usage information
+ -V, --version output the version number
+ -p, --peppers Add peppers
+ -P, --pineapple Add pineapple
+ -b, --bbq Add bbq sauce
+ -c, --cheese <type> Add the specified type of cheese [marble]
+ -C, --no-cheese You do not want any cheese
+
+```
+
+## Custom help
+
+ You can display arbitrary `-h, --help` information
+ by listening for "--help". Commander will automatically
+ exit once you are done so that the remainder of your program
+ does not execute causing undesired behaviours, for example
+ in the following executable "stuff" will not output when
+ `--help` is used.
+
+```js
+#!/usr/bin/env node
+
+/**
+ * Module dependencies.
+ */
+
+var program = require('commander');
+
+program
+ .version('0.1.0')
+ .option('-f, --foo', 'enable some foo')
+ .option('-b, --bar', 'enable some bar')
+ .option('-B, --baz', 'enable some baz');
+
+// must be before .parse() since
+// node's emit() is immediate
+
+program.on('--help', function(){
+ console.log(' Examples:');
+ console.log('');
+ console.log(' $ custom-help --help');
+ console.log(' $ custom-help -h');
+ console.log('');
+});
+
+program.parse(process.argv);
+
+console.log('stuff');
+```
+
+Yields the following help output when `node script-name.js -h` or `node script-name.js --help` are run:
+
+```
+
+Usage: custom-help [options]
+
+Options:
+
+ -h, --help output usage information
+ -V, --version output the version number
+ -f, --foo enable some foo
+ -b, --bar enable some bar
+ -B, --baz enable some baz
+
+Examples:
+
+ $ custom-help --help
+ $ custom-help -h
+
+```
+
+## .outputHelp(cb)
+
+Output help information without exiting.
+Optional callback cb allows post-processing of help text before it is displayed.
+
+If you want to display help by default (e.g. if no command was provided), you can use something like:
+
+```js
+var program = require('commander');
+var colors = require('colors');
+
+program
+ .version('0.1.0')
+ .command('getstream [url]', 'get stream URL')
+ .parse(process.argv);
+
+if (!process.argv.slice(2).length) {
+ program.outputHelp(make_red);
+}
+
+function make_red(txt) {
+ return colors.red(txt); //display the help text in red on the console
+}
+```
+
+## .help(cb)
+
+ Output help information and exit immediately.
+ Optional callback cb allows post-processing of help text before it is displayed.
+
+## Examples
+
+```js
+var program = require('commander');
+
+program
+ .version('0.1.0')
+ .option('-C, --chdir <path>', 'change the working directory')
+ .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
+ .option('-T, --no-tests', 'ignore test hook');
+
+program
+ .command('setup [env]')
+ .description('run setup commands for all envs')
+ .option("-s, --setup_mode [mode]", "Which setup mode to use")
+ .action(function(env, options){
+ var mode = options.setup_mode || "normal";
+ env = env || 'all';
+ console.log('setup for %s env(s) with %s mode', env, mode);
+ });
+
+program
+ .command('exec <cmd>')
+ .alias('ex')
+ .description('execute the given remote cmd')
+ .option("-e, --exec_mode <mode>", "Which exec mode to use")
+ .action(function(cmd, options){
+ console.log('exec "%s" using %s mode', cmd, options.exec_mode);
+ }).on('--help', function() {
+ console.log(' Examples:');
+ console.log();
+ console.log(' $ deploy exec sequential');
+ console.log(' $ deploy exec async');
+ console.log();
+ });
+
+program
+ .command('*')
+ .action(function(env){
+ console.log('deploying "%s"', env);
+ });
+
+program.parse(process.argv);
+```
+
+More Demos can be found in the [examples](https://github.com/tj/commander.js/tree/master/examples) directory.
+
+## License
+
+MIT
--- /dev/null
+/**
+ * Module dependencies.
+ */
+
+var EventEmitter = require('events').EventEmitter;
+var spawn = require('child_process').spawn;
+var path = require('path');
+var dirname = path.dirname;
+var basename = path.basename;
+var fs = require('fs');
+
+/**
+ * Inherit `Command` from `EventEmitter.prototype`.
+ */
+
+require('util').inherits(Command, EventEmitter);
+
+/**
+ * Expose the root command.
+ */
+
+exports = module.exports = new Command();
+
+/**
+ * Expose `Command`.
+ */
+
+exports.Command = Command;
+
+/**
+ * Expose `Option`.
+ */
+
+exports.Option = Option;
+
+/**
+ * Initialize a new `Option` with the given `flags` and `description`.
+ *
+ * @param {String} flags
+ * @param {String} description
+ * @api public
+ */
+
+function Option(flags, description) {
+ this.flags = flags;
+ this.required = ~flags.indexOf('<');
+ this.optional = ~flags.indexOf('[');
+ this.bool = !~flags.indexOf('-no-');
+ flags = flags.split(/[ ,|]+/);
+ if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift();
+ this.long = flags.shift();
+ this.description = description || '';
+}
+
+/**
+ * Return option name.
+ *
+ * @return {String}
+ * @api private
+ */
+
+Option.prototype.name = function() {
+ return this.long
+ .replace('--', '')
+ .replace('no-', '');
+};
+
+/**
+ * Return option name, in a camelcase format that can be used
+ * as a object attribute key.
+ *
+ * @return {String}
+ * @api private
+ */
+
+Option.prototype.attributeName = function() {
+ return camelcase(this.name());
+};
+
+/**
+ * Check if `arg` matches the short or long flag.
+ *
+ * @param {String} arg
+ * @return {Boolean}
+ * @api private
+ */
+
+Option.prototype.is = function(arg) {
+ return this.short === arg || this.long === arg;
+};
+
+/**
+ * Initialize a new `Command`.
+ *
+ * @param {String} name
+ * @api public
+ */
+
+function Command(name) {
+ this.commands = [];
+ this.options = [];
+ this._execs = {};
+ this._allowUnknownOption = false;
+ this._args = [];
+ this._name = name || '';
+}
+
+/**
+ * Add command `name`.
+ *
+ * The `.action()` callback is invoked when the
+ * command `name` is specified via __ARGV__,
+ * and the remaining arguments are applied to the
+ * function for access.
+ *
+ * When the `name` is "*" an un-matched command
+ * will be passed as the first arg, followed by
+ * the rest of __ARGV__ remaining.
+ *
+ * Examples:
+ *
+ * program
+ * .version('0.0.1')
+ * .option('-C, --chdir <path>', 'change the working directory')
+ * .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
+ * .option('-T, --no-tests', 'ignore test hook')
+ *
+ * program
+ * .command('setup')
+ * .description('run remote setup commands')
+ * .action(function() {
+ * console.log('setup');
+ * });
+ *
+ * program
+ * .command('exec <cmd>')
+ * .description('run the given remote command')
+ * .action(function(cmd) {
+ * console.log('exec "%s"', cmd);
+ * });
+ *
+ * program
+ * .command('teardown <dir> [otherDirs...]')
+ * .description('run teardown commands')
+ * .action(function(dir, otherDirs) {
+ * console.log('dir "%s"', dir);
+ * if (otherDirs) {
+ * otherDirs.forEach(function (oDir) {
+ * console.log('dir "%s"', oDir);
+ * });
+ * }
+ * });
+ *
+ * program
+ * .command('*')
+ * .description('deploy the given env')
+ * .action(function(env) {
+ * console.log('deploying "%s"', env);
+ * });
+ *
+ * program.parse(process.argv);
+ *
+ * @param {String} name
+ * @param {String} [desc] for git-style sub-commands
+ * @return {Command} the new command
+ * @api public
+ */
+
+Command.prototype.command = function(name, desc, opts) {
+ if (typeof desc === 'object' && desc !== null) {
+ opts = desc;
+ desc = null;
+ }
+ opts = opts || {};
+ var args = name.split(/ +/);
+ var cmd = new Command(args.shift());
+
+ if (desc) {
+ cmd.description(desc);
+ this.executables = true;
+ this._execs[cmd._name] = true;
+ if (opts.isDefault) this.defaultExecutable = cmd._name;
+ }
+ cmd._noHelp = !!opts.noHelp;
+ this.commands.push(cmd);
+ cmd.parseExpectedArgs(args);
+ cmd.parent = this;
+
+ if (desc) return this;
+ return cmd;
+};
+
+/**
+ * Define argument syntax for the top-level command.
+ *
+ * @api public
+ */
+
+Command.prototype.arguments = function(desc) {
+ return this.parseExpectedArgs(desc.split(/ +/));
+};
+
+/**
+ * Add an implicit `help [cmd]` subcommand
+ * which invokes `--help` for the given command.
+ *
+ * @api private
+ */
+
+Command.prototype.addImplicitHelpCommand = function() {
+ this.command('help [cmd]', 'display help for [cmd]');
+};
+
+/**
+ * Parse expected `args`.
+ *
+ * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`.
+ *
+ * @param {Array} args
+ * @return {Command} for chaining
+ * @api public
+ */
+
+Command.prototype.parseExpectedArgs = function(args) {
+ if (!args.length) return;
+ var self = this;
+ args.forEach(function(arg) {
+ var argDetails = {
+ required: false,
+ name: '',
+ variadic: false
+ };
+
+ switch (arg[0]) {
+ case '<':
+ argDetails.required = true;
+ argDetails.name = arg.slice(1, -1);
+ break;
+ case '[':
+ argDetails.name = arg.slice(1, -1);
+ break;
+ }
+
+ if (argDetails.name.length > 3 && argDetails.name.slice(-3) === '...') {
+ argDetails.variadic = true;
+ argDetails.name = argDetails.name.slice(0, -3);
+ }
+ if (argDetails.name) {
+ self._args.push(argDetails);
+ }
+ });
+ return this;
+};
+
+/**
+ * Register callback `fn` for the command.
+ *
+ * Examples:
+ *
+ * program
+ * .command('help')
+ * .description('display verbose help')
+ * .action(function() {
+ * // output help here
+ * });
+ *
+ * @param {Function} fn
+ * @return {Command} for chaining
+ * @api public
+ */
+
+Command.prototype.action = function(fn) {
+ var self = this;
+ var listener = function(args, unknown) {
+ // Parse any so-far unknown options
+ args = args || [];
+ unknown = unknown || [];
+
+ var parsed = self.parseOptions(unknown);
+
+ // Output help if necessary
+ outputHelpIfNecessary(self, parsed.unknown);
+
+ // If there are still any unknown options, then we simply
+ // die, unless someone asked for help, in which case we give it
+ // to them, and then we die.
+ if (parsed.unknown.length > 0) {
+ self.unknownOption(parsed.unknown[0]);
+ }
+
+ // Leftover arguments need to be pushed back. Fixes issue #56
+ if (parsed.args.length) args = parsed.args.concat(args);
+
+ self._args.forEach(function(arg, i) {
+ if (arg.required && args[i] == null) {
+ self.missingArgument(arg.name);
+ } else if (arg.variadic) {
+ if (i !== self._args.length - 1) {
+ self.variadicArgNotLast(arg.name);
+ }
+
+ args[i] = args.splice(i);
+ }
+ });
+
+ // Always append ourselves to the end of the arguments,
+ // to make sure we match the number of arguments the user
+ // expects
+ if (self._args.length) {
+ args[self._args.length] = self;
+ } else {
+ args.push(self);
+ }
+
+ fn.apply(self, args);
+ };
+ var parent = this.parent || this;
+ var name = parent === this ? '*' : this._name;
+ parent.on('command:' + name, listener);
+ if (this._alias) parent.on('command:' + this._alias, listener);
+ return this;
+};
+
+/**
+ * Define option with `flags`, `description` and optional
+ * coercion `fn`.
+ *
+ * The `flags` string should contain both the short and long flags,
+ * separated by comma, a pipe or space. The following are all valid
+ * all will output this way when `--help` is used.
+ *
+ * "-p, --pepper"
+ * "-p|--pepper"
+ * "-p --pepper"
+ *
+ * Examples:
+ *
+ * // simple boolean defaulting to false
+ * program.option('-p, --pepper', 'add pepper');
+ *
+ * --pepper
+ * program.pepper
+ * // => Boolean
+ *
+ * // simple boolean defaulting to true
+ * program.option('-C, --no-cheese', 'remove cheese');
+ *
+ * program.cheese
+ * // => true
+ *
+ * --no-cheese
+ * program.cheese
+ * // => false
+ *
+ * // required argument
+ * program.option('-C, --chdir <path>', 'change the working directory');
+ *
+ * --chdir /tmp
+ * program.chdir
+ * // => "/tmp"
+ *
+ * // optional argument
+ * program.option('-c, --cheese [type]', 'add cheese [marble]');
+ *
+ * @param {String} flags
+ * @param {String} description
+ * @param {Function|*} [fn] or default
+ * @param {*} [defaultValue]
+ * @return {Command} for chaining
+ * @api public
+ */
+
+Command.prototype.option = function(flags, description, fn, defaultValue) {
+ var self = this,
+ option = new Option(flags, description),
+ oname = option.name(),
+ name = option.attributeName();
+
+ // default as 3rd arg
+ if (typeof fn !== 'function') {
+ if (fn instanceof RegExp) {
+ var regex = fn;
+ fn = function(val, def) {
+ var m = regex.exec(val);
+ return m ? m[0] : def;
+ };
+ } else {
+ defaultValue = fn;
+ fn = null;
+ }
+ }
+
+ // preassign default value only for --no-*, [optional], or <required>
+ if (!option.bool || option.optional || option.required) {
+ // when --no-* we make sure default is true
+ if (!option.bool) defaultValue = true;
+ // preassign only if we have a default
+ if (defaultValue !== undefined) {
+ self[name] = defaultValue;
+ option.defaultValue = defaultValue;
+ }
+ }
+
+ // register the option
+ this.options.push(option);
+
+ // when it's passed assign the value
+ // and conditionally invoke the callback
+ this.on('option:' + oname, function(val) {
+ // coercion
+ if (val !== null && fn) {
+ val = fn(val, self[name] === undefined ? defaultValue : self[name]);
+ }
+
+ // unassigned or bool
+ if (typeof self[name] === 'boolean' || typeof self[name] === 'undefined') {
+ // if no value, bool true, and we have a default, then use it!
+ if (val == null) {
+ self[name] = option.bool
+ ? defaultValue || true
+ : false;
+ } else {
+ self[name] = val;
+ }
+ } else if (val !== null) {
+ // reassign
+ self[name] = val;
+ }
+ });
+
+ return this;
+};
+
+/**
+ * Allow unknown options on the command line.
+ *
+ * @param {Boolean} arg if `true` or omitted, no error will be thrown
+ * for unknown options.
+ * @api public
+ */
+Command.prototype.allowUnknownOption = function(arg) {
+ this._allowUnknownOption = arguments.length === 0 || arg;
+ return this;
+};
+
+/**
+ * Parse `argv`, settings options and invoking commands when defined.
+ *
+ * @param {Array} argv
+ * @return {Command} for chaining
+ * @api public
+ */
+
+Command.prototype.parse = function(argv) {
+ // implicit help
+ if (this.executables) this.addImplicitHelpCommand();
+
+ // store raw args
+ this.rawArgs = argv;
+
+ // guess name
+ this._name = this._name || basename(argv[1], '.js');
+
+ // github-style sub-commands with no sub-command
+ if (this.executables && argv.length < 3 && !this.defaultExecutable) {
+ // this user needs help
+ argv.push('--help');
+ }
+
+ // process argv
+ var parsed = this.parseOptions(this.normalize(argv.slice(2)));
+ var args = this.args = parsed.args;
+
+ var result = this.parseArgs(this.args, parsed.unknown);
+
+ // executable sub-commands
+ var name = result.args[0];
+
+ var aliasCommand = null;
+ // check alias of sub commands
+ if (name) {
+ aliasCommand = this.commands.filter(function(command) {
+ return command.alias() === name;
+ })[0];
+ }
+
+ if (this._execs[name] && typeof this._execs[name] !== 'function') {
+ return this.executeSubCommand(argv, args, parsed.unknown);
+ } else if (aliasCommand) {
+ // is alias of a subCommand
+ args[0] = aliasCommand._name;
+ return this.executeSubCommand(argv, args, parsed.unknown);
+ } else if (this.defaultExecutable) {
+ // use the default subcommand
+ args.unshift(this.defaultExecutable);
+ return this.executeSubCommand(argv, args, parsed.unknown);
+ }
+
+ return result;
+};
+
+/**
+ * Execute a sub-command executable.
+ *
+ * @param {Array} argv
+ * @param {Array} args
+ * @param {Array} unknown
+ * @api private
+ */
+
+Command.prototype.executeSubCommand = function(argv, args, unknown) {
+ args = args.concat(unknown);
+
+ if (!args.length) this.help();
+ if (args[0] === 'help' && args.length === 1) this.help();
+
+ // <cmd> --help
+ if (args[0] === 'help') {
+ args[0] = args[1];
+ args[1] = '--help';
+ }
+
+ // executable
+ var f = argv[1];
+ // name of the subcommand, link `pm-install`
+ var bin = basename(f, '.js') + '-' + args[0];
+
+ // In case of globally installed, get the base dir where executable
+ // subcommand file should be located at
+ var baseDir,
+ link = fs.lstatSync(f).isSymbolicLink() ? fs.readlinkSync(f) : f;
+
+ // when symbolink is relative path
+ if (link !== f && link.charAt(0) !== '/') {
+ link = path.join(dirname(f), link);
+ }
+ baseDir = dirname(link);
+
+ // prefer local `./<bin>` to bin in the $PATH
+ var localBin = path.join(baseDir, bin);
+
+ // whether bin file is a js script with explicit `.js` extension
+ var isExplicitJS = false;
+ if (exists(localBin + '.js')) {
+ bin = localBin + '.js';
+ isExplicitJS = true;
+ } else if (exists(localBin)) {
+ bin = localBin;
+ }
+
+ args = args.slice(1);
+
+ var proc;
+ if (process.platform !== 'win32') {
+ if (isExplicitJS) {
+ args.unshift(bin);
+ // add executable arguments to spawn
+ args = (process.execArgv || []).concat(args);
+
+ proc = spawn(process.argv[0], args, { stdio: 'inherit', customFds: [0, 1, 2] });
+ } else {
+ proc = spawn(bin, args, { stdio: 'inherit', customFds: [0, 1, 2] });
+ }
+ } else {
+ args.unshift(bin);
+ proc = spawn(process.execPath, args, { stdio: 'inherit' });
+ }
+
+ var signals = ['SIGUSR1', 'SIGUSR2', 'SIGTERM', 'SIGINT', 'SIGHUP'];
+ signals.forEach(function(signal) {
+ process.on(signal, function() {
+ if (proc.killed === false && proc.exitCode === null) {
+ proc.kill(signal);
+ }
+ });
+ });
+ proc.on('close', process.exit.bind(process));
+ proc.on('error', function(err) {
+ if (err.code === 'ENOENT') {
+ console.error('\n %s(1) does not exist, try --help\n', bin);
+ } else if (err.code === 'EACCES') {
+ console.error('\n %s(1) not executable. try chmod or run with root\n', bin);
+ }
+ process.exit(1);
+ });
+
+ // Store the reference to the child process
+ this.runningCommand = proc;
+};
+
+/**
+ * Normalize `args`, splitting joined short flags. For example
+ * the arg "-abc" is equivalent to "-a -b -c".
+ * This also normalizes equal sign and splits "--abc=def" into "--abc def".
+ *
+ * @param {Array} args
+ * @return {Array}
+ * @api private
+ */
+
+Command.prototype.normalize = function(args) {
+ var ret = [],
+ arg,
+ lastOpt,
+ index;
+
+ for (var i = 0, len = args.length; i < len; ++i) {
+ arg = args[i];
+ if (i > 0) {
+ lastOpt = this.optionFor(args[i - 1]);
+ }
+
+ if (arg === '--') {
+ // Honor option terminator
+ ret = ret.concat(args.slice(i));
+ break;
+ } else if (lastOpt && lastOpt.required) {
+ ret.push(arg);
+ } else if (arg.length > 1 && arg[0] === '-' && arg[1] !== '-') {
+ arg.slice(1).split('').forEach(function(c) {
+ ret.push('-' + c);
+ });
+ } else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) {
+ ret.push(arg.slice(0, index), arg.slice(index + 1));
+ } else {
+ ret.push(arg);
+ }
+ }
+
+ return ret;
+};
+
+/**
+ * Parse command `args`.
+ *
+ * When listener(s) are available those
+ * callbacks are invoked, otherwise the "*"
+ * event is emitted and those actions are invoked.
+ *
+ * @param {Array} args
+ * @return {Command} for chaining
+ * @api private
+ */
+
+Command.prototype.parseArgs = function(args, unknown) {
+ var name;
+
+ if (args.length) {
+ name = args[0];
+ if (this.listeners('command:' + name).length) {
+ this.emit('command:' + args.shift(), args, unknown);
+ } else {
+ this.emit('command:*', args);
+ }
+ } else {
+ outputHelpIfNecessary(this, unknown);
+
+ // If there were no args and we have unknown options,
+ // then they are extraneous and we need to error.
+ if (unknown.length > 0) {
+ this.unknownOption(unknown[0]);
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Return an option matching `arg` if any.
+ *
+ * @param {String} arg
+ * @return {Option}
+ * @api private
+ */
+
+Command.prototype.optionFor = function(arg) {
+ for (var i = 0, len = this.options.length; i < len; ++i) {
+ if (this.options[i].is(arg)) {
+ return this.options[i];
+ }
+ }
+};
+
+/**
+ * Parse options from `argv` returning `argv`
+ * void of these options.
+ *
+ * @param {Array} argv
+ * @return {Array}
+ * @api public
+ */
+
+Command.prototype.parseOptions = function(argv) {
+ var args = [],
+ len = argv.length,
+ literal,
+ option,
+ arg;
+
+ var unknownOptions = [];
+
+ // parse options
+ for (var i = 0; i < len; ++i) {
+ arg = argv[i];
+
+ // literal args after --
+ if (literal) {
+ args.push(arg);
+ continue;
+ }
+
+ if (arg === '--') {
+ literal = true;
+ continue;
+ }
+
+ // find matching Option
+ option = this.optionFor(arg);
+
+ // option is defined
+ if (option) {
+ // requires arg
+ if (option.required) {
+ arg = argv[++i];
+ if (arg == null) return this.optionMissingArgument(option);
+ this.emit('option:' + option.name(), arg);
+ // optional arg
+ } else if (option.optional) {
+ arg = argv[i + 1];
+ if (arg == null || (arg[0] === '-' && arg !== '-')) {
+ arg = null;
+ } else {
+ ++i;
+ }
+ this.emit('option:' + option.name(), arg);
+ // bool
+ } else {
+ this.emit('option:' + option.name());
+ }
+ continue;
+ }
+
+ // looks like an option
+ if (arg.length > 1 && arg[0] === '-') {
+ unknownOptions.push(arg);
+
+ // If the next argument looks like it might be
+ // an argument for this option, we pass it on.
+ // If it isn't, then it'll simply be ignored
+ if ((i + 1) < argv.length && argv[i + 1][0] !== '-') {
+ unknownOptions.push(argv[++i]);
+ }
+ continue;
+ }
+
+ // arg
+ args.push(arg);
+ }
+
+ return { args: args, unknown: unknownOptions };
+};
+
+/**
+ * Return an object containing options as key-value pairs
+ *
+ * @return {Object}
+ * @api public
+ */
+Command.prototype.opts = function() {
+ var result = {},
+ len = this.options.length;
+
+ for (var i = 0; i < len; i++) {
+ var key = this.options[i].attributeName();
+ result[key] = key === this._versionOptionName ? this._version : this[key];
+ }
+ return result;
+};
+
+/**
+ * Argument `name` is missing.
+ *
+ * @param {String} name
+ * @api private
+ */
+
+Command.prototype.missingArgument = function(name) {
+ console.error();
+ console.error(" error: missing required argument `%s'", name);
+ console.error();
+ process.exit(1);
+};
+
+/**
+ * `Option` is missing an argument, but received `flag` or nothing.
+ *
+ * @param {String} option
+ * @param {String} flag
+ * @api private
+ */
+
+Command.prototype.optionMissingArgument = function(option, flag) {
+ console.error();
+ if (flag) {
+ console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag);
+ } else {
+ console.error(" error: option `%s' argument missing", option.flags);
+ }
+ console.error();
+ process.exit(1);
+};
+
+/**
+ * Unknown option `flag`.
+ *
+ * @param {String} flag
+ * @api private
+ */
+
+Command.prototype.unknownOption = function(flag) {
+ if (this._allowUnknownOption) return;
+ console.error();
+ console.error(" error: unknown option `%s'", flag);
+ console.error();
+ process.exit(1);
+};
+
+/**
+ * Variadic argument with `name` is not the last argument as required.
+ *
+ * @param {String} name
+ * @api private
+ */
+
+Command.prototype.variadicArgNotLast = function(name) {
+ console.error();
+ console.error(" error: variadic arguments must be last `%s'", name);
+ console.error();
+ process.exit(1);
+};
+
+/**
+ * Set the program version to `str`.
+ *
+ * This method auto-registers the "-V, --version" flag
+ * which will print the version number when passed.
+ *
+ * @param {String} str
+ * @param {String} [flags]
+ * @return {Command} for chaining
+ * @api public
+ */
+
+Command.prototype.version = function(str, flags) {
+ if (arguments.length === 0) return this._version;
+ this._version = str;
+ flags = flags || '-V, --version';
+ var versionOption = new Option(flags, 'output the version number');
+ this._versionOptionName = versionOption.long.substr(2) || 'version';
+ this.options.push(versionOption);
+ this.on('option:' + this._versionOptionName, function() {
+ process.stdout.write(str + '\n');
+ process.exit(0);
+ });
+ return this;
+};
+
+/**
+ * Set the description to `str`.
+ *
+ * @param {String} str
+ * @param {Object} argsDescription
+ * @return {String|Command}
+ * @api public
+ */
+
+Command.prototype.description = function(str, argsDescription) {
+ if (arguments.length === 0) return this._description;
+ this._description = str;
+ this._argsDescription = argsDescription;
+ return this;
+};
+
+/**
+ * Set an alias for the command
+ *
+ * @param {String} alias
+ * @return {String|Command}
+ * @api public
+ */
+
+Command.prototype.alias = function(alias) {
+ var command = this;
+ if (this.commands.length !== 0) {
+ command = this.commands[this.commands.length - 1];
+ }
+
+ if (arguments.length === 0) return command._alias;
+
+ if (alias === command._name) throw new Error('Command alias can\'t be the same as its name');
+
+ command._alias = alias;
+ return this;
+};
+
+/**
+ * Set / get the command usage `str`.
+ *
+ * @param {String} str
+ * @return {String|Command}
+ * @api public
+ */
+
+Command.prototype.usage = function(str) {
+ var args = this._args.map(function(arg) {
+ return humanReadableArgName(arg);
+ });
+
+ var usage = '[options]' +
+ (this.commands.length ? ' [command]' : '') +
+ (this._args.length ? ' ' + args.join(' ') : '');
+
+ if (arguments.length === 0) return this._usage || usage;
+ this._usage = str;
+
+ return this;
+};
+
+/**
+ * Get or set the name of the command
+ *
+ * @param {String} str
+ * @return {String|Command}
+ * @api public
+ */
+
+Command.prototype.name = function(str) {
+ if (arguments.length === 0) return this._name;
+ this._name = str;
+ return this;
+};
+
+/**
+ * Return prepared commands.
+ *
+ * @return {Array}
+ * @api private
+ */
+
+Command.prototype.prepareCommands = function() {
+ return this.commands.filter(function(cmd) {
+ return !cmd._noHelp;
+ }).map(function(cmd) {
+ var args = cmd._args.map(function(arg) {
+ return humanReadableArgName(arg);
+ }).join(' ');
+
+ return [
+ cmd._name +
+ (cmd._alias ? '|' + cmd._alias : '') +
+ (cmd.options.length ? ' [options]' : '') +
+ (args ? ' ' + args : ''),
+ cmd._description
+ ];
+ });
+};
+
+/**
+ * Return the largest command length.
+ *
+ * @return {Number}
+ * @api private
+ */
+
+Command.prototype.largestCommandLength = function() {
+ var commands = this.prepareCommands();
+ return commands.reduce(function(max, command) {
+ return Math.max(max, command[0].length);
+ }, 0);
+};
+
+/**
+ * Return the largest option length.
+ *
+ * @return {Number}
+ * @api private
+ */
+
+Command.prototype.largestOptionLength = function() {
+ var options = [].slice.call(this.options);
+ options.push({
+ flags: '-h, --help'
+ });
+ return options.reduce(function(max, option) {
+ return Math.max(max, option.flags.length);
+ }, 0);
+};
+
+/**
+ * Return the largest arg length.
+ *
+ * @return {Number}
+ * @api private
+ */
+
+Command.prototype.largestArgLength = function() {
+ return this._args.reduce(function(max, arg) {
+ return Math.max(max, arg.name.length);
+ }, 0);
+};
+
+/**
+ * Return the pad width.
+ *
+ * @return {Number}
+ * @api private
+ */
+
+Command.prototype.padWidth = function() {
+ var width = this.largestOptionLength();
+ if (this._argsDescription && this._args.length) {
+ if (this.largestArgLength() > width) {
+ width = this.largestArgLength();
+ }
+ }
+
+ if (this.commands && this.commands.length) {
+ if (this.largestCommandLength() > width) {
+ width = this.largestCommandLength();
+ }
+ }
+
+ return width;
+};
+
+/**
+ * Return help for options.
+ *
+ * @return {String}
+ * @api private
+ */
+
+Command.prototype.optionHelp = function() {
+ var width = this.padWidth();
+
+ // Append the help information
+ return this.options.map(function(option) {
+ return pad(option.flags, width) + ' ' + option.description +
+ ((option.bool && option.defaultValue !== undefined) ? ' (default: ' + option.defaultValue + ')' : '');
+ }).concat([pad('-h, --help', width) + ' ' + 'output usage information'])
+ .join('\n');
+};
+
+/**
+ * Return command help documentation.
+ *
+ * @return {String}
+ * @api private
+ */
+
+Command.prototype.commandHelp = function() {
+ if (!this.commands.length) return '';
+
+ var commands = this.prepareCommands();
+ var width = this.padWidth();
+
+ return [
+ ' Commands:',
+ '',
+ commands.map(function(cmd) {
+ var desc = cmd[1] ? ' ' + cmd[1] : '';
+ return (desc ? pad(cmd[0], width) : cmd[0]) + desc;
+ }).join('\n').replace(/^/gm, ' '),
+ ''
+ ].join('\n');
+};
+
+/**
+ * Return program help documentation.
+ *
+ * @return {String}
+ * @api private
+ */
+
+Command.prototype.helpInformation = function() {
+ var desc = [];
+ if (this._description) {
+ desc = [
+ ' ' + this._description,
+ ''
+ ];
+
+ var argsDescription = this._argsDescription;
+ if (argsDescription && this._args.length) {
+ var width = this.padWidth();
+ desc.push(' Arguments:');
+ desc.push('');
+ this._args.forEach(function(arg) {
+ desc.push(' ' + pad(arg.name, width) + ' ' + argsDescription[arg.name]);
+ });
+ desc.push('');
+ }
+ }
+
+ var cmdName = this._name;
+ if (this._alias) {
+ cmdName = cmdName + '|' + this._alias;
+ }
+ var usage = [
+ '',
+ ' Usage: ' + cmdName + ' ' + this.usage(),
+ ''
+ ];
+
+ var cmds = [];
+ var commandHelp = this.commandHelp();
+ if (commandHelp) cmds = [commandHelp];
+
+ var options = [
+ ' Options:',
+ '',
+ '' + this.optionHelp().replace(/^/gm, ' '),
+ ''
+ ];
+
+ return usage
+ .concat(desc)
+ .concat(options)
+ .concat(cmds)
+ .join('\n');
+};
+
+/**
+ * Output help information for this command
+ *
+ * @api public
+ */
+
+Command.prototype.outputHelp = function(cb) {
+ if (!cb) {
+ cb = function(passthru) {
+ return passthru;
+ };
+ }
+ process.stdout.write(cb(this.helpInformation()));
+ this.emit('--help');
+};
+
+/**
+ * Output help information and exit.
+ *
+ * @api public
+ */
+
+Command.prototype.help = function(cb) {
+ this.outputHelp(cb);
+ process.exit();
+};
+
+/**
+ * Camel-case the given `flag`
+ *
+ * @param {String} flag
+ * @return {String}
+ * @api private
+ */
+
+function camelcase(flag) {
+ return flag.split('-').reduce(function(str, word) {
+ return str + word[0].toUpperCase() + word.slice(1);
+ });
+}
+
+/**
+ * Pad `str` to `width`.
+ *
+ * @param {String} str
+ * @param {Number} width
+ * @return {String}
+ * @api private
+ */
+
+function pad(str, width) {
+ var len = Math.max(0, width - str.length);
+ return str + Array(len + 1).join(' ');
+}
+
+/**
+ * Output help information if necessary
+ *
+ * @param {Command} command to output help for
+ * @param {Array} array of options to search for -h or --help
+ * @api private
+ */
+
+function outputHelpIfNecessary(cmd, options) {
+ options = options || [];
+ for (var i = 0; i < options.length; i++) {
+ if (options[i] === '--help' || options[i] === '-h') {
+ cmd.outputHelp();
+ process.exit(0);
+ }
+ }
+}
+
+/**
+ * Takes an argument an returns its human readable equivalent for help usage.
+ *
+ * @param {Object} arg
+ * @return {String}
+ * @api private
+ */
+
+function humanReadableArgName(arg) {
+ var nameOutput = arg.name + (arg.variadic === true ? '...' : '');
+
+ return arg.required
+ ? '<' + nameOutput + '>'
+ : '[' + nameOutput + ']';
+}
+
+// for versions before node v0.8 when there weren't `fs.existsSync`
+function exists(file) {
+ try {
+ if (fs.statSync(file).isFile()) {
+ return true;
+ }
+ } catch (e) {
+ return false;
+ }
+}
--- /dev/null
+{
+ "name": "commander",
+ "version": "2.15.1",
+ "description": "the complete solution for node.js command-line programs",
+ "keywords": [
+ "commander",
+ "command",
+ "option",
+ "parser"
+ ],
+ "author": {
+ "name": "TJ Holowaychuk",
+ "email": "tj@vision-media.ca"
+ },
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/tj/commander.js.git"
+ },
+ "scripts": {
+ "lint": "eslint index.js",
+ "test": "make test && npm run test-typings",
+ "test-typings": "node_modules/typescript/bin/tsc -p tsconfig.json"
+ },
+ "main": "index",
+ "files": [
+ "index.js",
+ "typings/index.d.ts"
+ ],
+ "dependencies": {},
+ "devDependencies": {
+ "@types/node": "^7.0.55",
+ "eslint": "^3.19.0",
+ "should": "^11.2.1",
+ "sinon": "^2.4.1",
+ "standard": "^10.0.3",
+ "typescript": "^2.7.2"
+ },
+ "typings": "typings/index.d.ts",
+ "gitHead": "649eaef336ddc7224eb5c73e4a958685e24de25e",
+ "bugs": {
+ "url": "https://github.com/tj/commander.js/issues"
+ },
+ "homepage": "https://github.com/tj/commander.js#readme",
+ "_id": "commander@2.15.1",
+ "_npmVersion": "5.6.0",
+ "_nodeVersion": "9.8.0",
+ "_npmUser": {
+ "name": "abetomo",
+ "email": "abe@enzou.tokyo"
+ },
+ "dist": {
+ "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==",
+ "shasum": "df46e867d0fc2aec66a34662b406a9ccafff5b0f",
+ "tarball": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
+ "fileCount": 6,
+ "unpackedSize": 59781
+ },
+ "maintainers": [
+ {
+ "email": "abe@enzou.tokyo",
+ "name": "abetomo"
+ },
+ {
+ "email": "rkoutnik@gmail.com",
+ "name": "somekittens"
+ },
+ {
+ "email": "tj@vision-media.ca",
+ "name": "tjholowaychuk"
+ },
+ {
+ "email": "romain.vanesyan@gmail.com",
+ "name": "vanesyan"
+ },
+ {
+ "email": "zhiyelee@gmail.com",
+ "name": "zhiyelee"
+ }
+ ],
+ "directories": {},
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/commander_2.15.1_1521510442790_0.20361588610282877"
+ },
+ "_hasShrinkwrap": false,
+ "_shasum": "df46e867d0fc2aec66a34662b406a9ccafff5b0f",
+ "_from": "commander@~2.15.0",
+ "_resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz"
+}
--- /dev/null
+// Type definitions for commander 2.11
+// Project: https://github.com/visionmedia/commander.js
+// Definitions by: Alan Agius <https://github.com/alan-agius4>, Marcelo Dezem <https://github.com/mdezem>, vvakame <https://github.com/vvakame>, Jules Randolph <https://github.com/sveinburne>
+// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
+
+declare namespace local {
+
+ class Option {
+ flags: string;
+ required: boolean;
+ optional: boolean;
+ bool: boolean;
+ short?: string;
+ long: string;
+ description: string;
+
+ /**
+ * Initialize a new `Option` with the given `flags` and `description`.
+ *
+ * @param {string} flags
+ * @param {string} [description]
+ */
+ constructor(flags: string, description?: string);
+ }
+
+ class Command extends NodeJS.EventEmitter {
+ [key: string]: any;
+
+ args: string[];
+
+ /**
+ * Initialize a new `Command`.
+ *
+ * @param {string} [name]
+ */
+ constructor(name?: string);
+
+ /**
+ * Set the program version to `str`.
+ *
+ * This method auto-registers the "-V, --version" flag
+ * which will print the version number when passed.
+ *
+ * @param {string} str
+ * @param {string} [flags]
+ * @returns {Command} for chaining
+ */
+ version(str: string, flags?: string): Command;
+
+ /**
+ * Add command `name`.
+ *
+ * The `.action()` callback is invoked when the
+ * command `name` is specified via __ARGV__,
+ * and the remaining arguments are applied to the
+ * function for access.
+ *
+ * When the `name` is "*" an un-matched command
+ * will be passed as the first arg, followed by
+ * the rest of __ARGV__ remaining.
+ *
+ * @example
+ * program
+ * .version('0.0.1')
+ * .option('-C, --chdir <path>', 'change the working directory')
+ * .option('-c, --config <path>', 'set config path. defaults to ./deploy.conf')
+ * .option('-T, --no-tests', 'ignore test hook')
+ *
+ * program
+ * .command('setup')
+ * .description('run remote setup commands')
+ * .action(function() {
+ * console.log('setup');
+ * });
+ *
+ * program
+ * .command('exec <cmd>')
+ * .description('run the given remote command')
+ * .action(function(cmd) {
+ * console.log('exec "%s"', cmd);
+ * });
+ *
+ * program
+ * .command('teardown <dir> [otherDirs...]')
+ * .description('run teardown commands')
+ * .action(function(dir, otherDirs) {
+ * console.log('dir "%s"', dir);
+ * if (otherDirs) {
+ * otherDirs.forEach(function (oDir) {
+ * console.log('dir "%s"', oDir);
+ * });
+ * }
+ * });
+ *
+ * program
+ * .command('*')
+ * .description('deploy the given env')
+ * .action(function(env) {
+ * console.log('deploying "%s"', env);
+ * });
+ *
+ * program.parse(process.argv);
+ *
+ * @param {string} name
+ * @param {string} [desc] for git-style sub-commands
+ * @param {CommandOptions} [opts] command options
+ * @returns {Command} the new command
+ */
+ command(name: string, desc?: string, opts?: commander.CommandOptions): Command;
+
+ /**
+ * Define argument syntax for the top-level command.
+ *
+ * @param {string} desc
+ * @returns {Command} for chaining
+ */
+ arguments(desc: string): Command;
+
+ /**
+ * Parse expected `args`.
+ *
+ * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`.
+ *
+ * @param {string[]} args
+ * @returns {Command} for chaining
+ */
+ parseExpectedArgs(args: string[]): Command;
+
+ /**
+ * Register callback `fn` for the command.
+ *
+ * @example
+ * program
+ * .command('help')
+ * .description('display verbose help')
+ * .action(function() {
+ * // output help here
+ * });
+ *
+ * @param {(...args: any[]) => void} fn
+ * @returns {Command} for chaining
+ */
+ action(fn: (...args: any[]) => void): Command;
+
+ /**
+ * Define option with `flags`, `description` and optional
+ * coercion `fn`.
+ *
+ * The `flags` string should contain both the short and long flags,
+ * separated by comma, a pipe or space. The following are all valid
+ * all will output this way when `--help` is used.
+ *
+ * "-p, --pepper"
+ * "-p|--pepper"
+ * "-p --pepper"
+ *
+ * @example
+ * // simple boolean defaulting to false
+ * program.option('-p, --pepper', 'add pepper');
+ *
+ * --pepper
+ * program.pepper
+ * // => Boolean
+ *
+ * // simple boolean defaulting to true
+ * program.option('-C, --no-cheese', 'remove cheese');
+ *
+ * program.cheese
+ * // => true
+ *
+ * --no-cheese
+ * program.cheese
+ * // => false
+ *
+ * // required argument
+ * program.option('-C, --chdir <path>', 'change the working directory');
+ *
+ * --chdir /tmp
+ * program.chdir
+ * // => "/tmp"
+ *
+ * // optional argument
+ * program.option('-c, --cheese [type]', 'add cheese [marble]');
+ *
+ * @param {string} flags
+ * @param {string} [description]
+ * @param {((arg1: any, arg2: any) => void) | RegExp} [fn] function or default
+ * @param {*} [defaultValue]
+ * @returns {Command} for chaining
+ */
+ option(flags: string, description?: string, fn?: ((arg1: any, arg2: any) => void) | RegExp, defaultValue?: any): Command;
+ option(flags: string, description?: string, defaultValue?: any): Command;
+
+ /**
+ * Allow unknown options on the command line.
+ *
+ * @param {boolean} [arg] if `true` or omitted, no error will be thrown for unknown options.
+ * @returns {Command} for chaining
+ */
+ allowUnknownOption(arg?: boolean): Command;
+
+ /**
+ * Parse `argv`, settings options and invoking commands when defined.
+ *
+ * @param {string[]} argv
+ * @returns {Command} for chaining
+ */
+ parse(argv: string[]): Command;
+
+ /**
+ * Parse options from `argv` returning `argv` void of these options.
+ *
+ * @param {string[]} argv
+ * @returns {ParseOptionsResult}
+ */
+ parseOptions(argv: string[]): commander.ParseOptionsResult;
+
+ /**
+ * Return an object containing options as key-value pairs
+ *
+ * @returns {{[key: string]: string}}
+ */
+ opts(): { [key: string]: string };
+
+ /**
+ * Set the description to `str`.
+ *
+ * @param {string} str
+ * @return {(Command | string)}
+ */
+ description(str: string): Command;
+ description(): string;
+
+ /**
+ * Set an alias for the command.
+ *
+ * @param {string} alias
+ * @return {(Command | string)}
+ */
+ alias(alias: string): Command;
+ alias(): string;
+
+ /**
+ * Set or get the command usage.
+ *
+ * @param {string} str
+ * @return {(Command | string)}
+ */
+ usage(str: string): Command;
+ usage(): string;
+
+ /**
+ * Set the name of the command.
+ *
+ * @param {string} str
+ * @return {Command}
+ */
+ name(str: string): Command;
+
+ /**
+ * Get the name of the command.
+ *
+ * @return {string}
+ */
+ name(): string;
+
+ /**
+ * Output help information for this command.
+ *
+ * @param {(str: string) => string} [cb]
+ */
+ outputHelp(cb?: (str: string) => string): void;
+
+ /** Output help information and exit.
+ *
+ * @param {(str: string) => string} [cb]
+ */
+ help(cb?: (str: string) => string): void;
+ }
+
+}
+
+declare namespace commander {
+
+ type Command = local.Command
+
+ type Option = local.Option
+
+ interface CommandOptions {
+ noHelp?: boolean;
+ isDefault?: boolean;
+ }
+
+ interface ParseOptionsResult {
+ args: string[];
+ unknown: string[];
+ }
+
+ interface CommanderStatic extends Command {
+ Command: typeof local.Command;
+ Option: typeof local.Option;
+ CommandOptions: CommandOptions;
+ ParseOptionsResult: ParseOptionsResult;
+ }
+
+}
+
+declare const commander: commander.CommanderStatic;
+export = commander;
--- /dev/null
+The ISC License
+
+Copyright (c) Isaac Z. Schlueter and Contributors
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--- /dev/null
+## read
+
+For reading user input from stdin.
+
+Similar to the `readline` builtin's `question()` method, but with a
+few more features.
+
+## USAGE
+
+```javascript
+var read = require("read")
+read(options, callback)
+```
+
+The callback gets called with either the user input, or the default
+specified, or an error, as `callback(error, result, isDefault)`
+node style.
+
+## OPTIONS
+
+Every option is optional.
+
+* `prompt` What to write to stdout before reading input.
+* `silent` Don't echo the output as the user types it.
+* `replace` Replace silenced characters with the supplied character value.
+* `timeout` Number of ms to wait for user input before giving up.
+* `default` The default value if the user enters nothing.
+* `edit` Allow the user to edit the default value.
+* `terminal` Treat the output as a TTY, whether it is or not.
+* `input` Readable stream to get input data from. (default `process.stdin`)
+* `output` Writeable stream to write prompts to. (default: `process.stdout`)
+
+If silent is true, and the input is a TTY, then read will set raw
+mode, and read character by character.
+
+## COMPATIBILITY
+
+This module works sort of with node 0.6. It does not work with node
+versions less than 0.6. It is best on node 0.8.
+
+On node version 0.6, it will remove all listeners on the input
+stream's `data` and `keypress` events, because the readline module did
+not fully clean up after itself in that version of node, and did not
+make it possible to clean up after it in a way that has no potential
+for side effects.
+
+Additionally, some of the readline options (like `terminal`) will not
+function in versions of node before 0.8, because they were not
+implemented in the builtin readline module.
+
+## CONTRIBUTING
+
+Patches welcome.
--- /dev/null
+
+module.exports = read
+
+var readline = require('readline')
+var Mute = require('mute-stream')
+
+function read (opts, cb) {
+ if (opts.num) {
+ throw new Error('read() no longer accepts a char number limit')
+ }
+
+ if (typeof opts.default !== 'undefined' &&
+ typeof opts.default !== 'string' &&
+ typeof opts.default !== 'number') {
+ throw new Error('default value must be string or number')
+ }
+
+ var input = opts.input || process.stdin
+ var output = opts.output || process.stdout
+ var prompt = (opts.prompt || '').trim() + ' '
+ var silent = opts.silent
+ var editDef = false
+ var timeout = opts.timeout
+
+ var def = opts.default || ''
+ if (def) {
+ if (silent) {
+ prompt += '(<default hidden>) '
+ } else if (opts.edit) {
+ editDef = true
+ } else {
+ prompt += '(' + def + ') '
+ }
+ }
+ var terminal = !!(opts.terminal || output.isTTY)
+
+ var m = new Mute({ replace: opts.replace, prompt: prompt })
+ m.pipe(output, {end: false})
+ output = m
+ var rlOpts = { input: input, output: output, terminal: terminal }
+
+ if (process.version.match(/^v0\.6/)) {
+ var rl = readline.createInterface(rlOpts.input, rlOpts.output)
+ } else {
+ var rl = readline.createInterface(rlOpts)
+ }
+
+
+ output.unmute()
+ rl.setPrompt(prompt)
+ rl.prompt()
+ if (silent) {
+ output.mute()
+ } else if (editDef) {
+ rl.line = def
+ rl.cursor = def.length
+ rl._refreshLine()
+ }
+
+ var called = false
+ rl.on('line', onLine)
+ rl.on('error', onError)
+
+ rl.on('SIGINT', function () {
+ rl.close()
+ onError(new Error('canceled'))
+ })
+
+ var timer
+ if (timeout) {
+ timer = setTimeout(function () {
+ onError(new Error('timed out'))
+ }, timeout)
+ }
+
+ function done () {
+ called = true
+ rl.close()
+
+ if (process.version.match(/^v0\.6/)) {
+ rl.input.removeAllListeners('data')
+ rl.input.removeAllListeners('keypress')
+ rl.input.pause()
+ }
+
+ clearTimeout(timer)
+ output.mute()
+ output.end()
+ }
+
+ function onError (er) {
+ if (called) return
+ done()
+ return cb(er)
+ }
+
+ function onLine (line) {
+ if (called) return
+ if (silent && terminal) {
+ output.unmute()
+ output.write('\r\n')
+ }
+ done()
+ // truncate the \n at the end.
+ line = line.replace(/\r?\n$/, '')
+ var isDefault = !!(editDef && line === def)
+ if (def && !line) {
+ isDefault = true
+ line = def
+ }
+ cb(null, line, isDefault)
+ }
+}
--- /dev/null
+The ISC License
+
+Copyright (c) Isaac Z. Schlueter and Contributors
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
--- /dev/null
+# mute-stream
+
+Bytes go in, but they don't come out (when muted).
+
+This is a basic pass-through stream, but when muted, the bytes are
+silently dropped, rather than being passed through.
+
+## Usage
+
+```javascript
+var MuteStream = require('mute-stream')
+
+var ms = new MuteStream(options)
+
+ms.pipe(process.stdout)
+ms.write('foo') // writes 'foo' to stdout
+ms.mute()
+ms.write('bar') // does not write 'bar'
+ms.unmute()
+ms.write('baz') // writes 'baz' to stdout
+
+// can also be used to mute incoming data
+var ms = new MuteStream
+input.pipe(ms)
+
+ms.on('data', function (c) {
+ console.log('data: ' + c)
+})
+
+input.emit('data', 'foo') // logs 'foo'
+ms.mute()
+input.emit('data', 'bar') // does not log 'bar'
+ms.unmute()
+input.emit('data', 'baz') // logs 'baz'
+```
+
+## Options
+
+All options are optional.
+
+* `replace` Set to a string to replace each character with the
+ specified string when muted. (So you can show `****` instead of the
+ password, for example.)
+
+* `prompt` If you are using a replacement char, and also using a
+ prompt with a readline stream (as for a `Password: *****` input),
+ then specify what the prompt is so that backspace will work
+ properly. Otherwise, pressing backspace will overwrite the prompt
+ with the replacement character, which is weird.
+
+## ms.mute()
+
+Set `muted` to `true`. Turns `.write()` into a no-op.
+
+## ms.unmute()
+
+Set `muted` to `false`
+
+## ms.isTTY
+
+True if the pipe destination is a TTY, or if the incoming pipe source is
+a TTY.
+
+## Other stream methods...
+
+The other standard readable and writable stream methods are all
+available. The MuteStream object acts as a facade to its pipe source
+and destination.
--- /dev/null
+var Stream = require('stream')
+
+module.exports = MuteStream
+
+// var out = new MuteStream(process.stdout)
+// argument auto-pipes
+function MuteStream (opts) {
+ Stream.apply(this)
+ opts = opts || {}
+ this.writable = this.readable = true
+ this.muted = false
+ this.on('pipe', this._onpipe)
+ this.replace = opts.replace
+
+ // For readline-type situations
+ // This much at the start of a line being redrawn after a ctrl char
+ // is seen (such as backspace) won't be redrawn as the replacement
+ this._prompt = opts.prompt || null
+ this._hadControl = false
+}
+
+MuteStream.prototype = Object.create(Stream.prototype)
+
+Object.defineProperty(MuteStream.prototype, 'constructor', {
+ value: MuteStream,
+ enumerable: false
+})
+
+MuteStream.prototype.mute = function () {
+ this.muted = true
+}
+
+MuteStream.prototype.unmute = function () {
+ this.muted = false
+}
+
+Object.defineProperty(MuteStream.prototype, '_onpipe', {
+ value: onPipe,
+ enumerable: false,
+ writable: true,
+ configurable: true
+})
+
+function onPipe (src) {
+ this._src = src
+}
+
+Object.defineProperty(MuteStream.prototype, 'isTTY', {
+ get: getIsTTY,
+ set: setIsTTY,
+ enumerable: true,
+ configurable: true
+})
+
+function getIsTTY () {
+ return( (this._dest) ? this._dest.isTTY
+ : (this._src) ? this._src.isTTY
+ : false
+ )
+}
+
+// basically just get replace the getter/setter with a regular value
+function setIsTTY (isTTY) {
+ Object.defineProperty(this, 'isTTY', {
+ value: isTTY,
+ enumerable: true,
+ writable: true,
+ configurable: true
+ })
+}
+
+Object.defineProperty(MuteStream.prototype, 'rows', {
+ get: function () {
+ return( this._dest ? this._dest.rows
+ : this._src ? this._src.rows
+ : undefined )
+ }, enumerable: true, configurable: true })
+
+Object.defineProperty(MuteStream.prototype, 'columns', {
+ get: function () {
+ return( this._dest ? this._dest.columns
+ : this._src ? this._src.columns
+ : undefined )
+ }, enumerable: true, configurable: true })
+
+
+MuteStream.prototype.pipe = function (dest, options) {
+ this._dest = dest
+ return Stream.prototype.pipe.call(this, dest, options)
+}
+
+MuteStream.prototype.pause = function () {
+ if (this._src) return this._src.pause()
+}
+
+MuteStream.prototype.resume = function () {
+ if (this._src) return this._src.resume()
+}
+
+MuteStream.prototype.write = function (c) {
+ if (this.muted) {
+ if (!this.replace) return true
+ if (c.match(/^\u001b/)) {
+ if(c.indexOf(this._prompt) === 0) {
+ c = c.substr(this._prompt.length);
+ c = c.replace(/./g, this.replace);
+ c = this._prompt + c;
+ }
+ this._hadControl = true
+ return this.emit('data', c)
+ } else {
+ if (this._prompt && this._hadControl &&
+ c.indexOf(this._prompt) === 0) {
+ this._hadControl = false
+ this.emit('data', this._prompt)
+ c = c.substr(this._prompt.length)
+ }
+ c = c.toString().replace(/./g, this.replace)
+ }
+ }
+ this.emit('data', c)
+}
+
+MuteStream.prototype.end = function (c) {
+ if (this.muted) {
+ if (c && this.replace) {
+ c = c.toString().replace(/./g, this.replace)
+ } else {
+ c = null
+ }
+ }
+ if (c) this.emit('data', c)
+ this.emit('end')
+}
+
+function proxy (fn) { return function () {
+ var d = this._dest
+ var s = this._src
+ if (d && d[fn]) d[fn].apply(d, arguments)
+ if (s && s[fn]) s[fn].apply(s, arguments)
+}}
+
+MuteStream.prototype.destroy = proxy('destroy')
+MuteStream.prototype.destroySoon = proxy('destroySoon')
+MuteStream.prototype.close = proxy('close')
--- /dev/null
+{
+ "name": "mute-stream",
+ "version": "0.0.8",
+ "main": "mute.js",
+ "directories": {
+ "test": "test"
+ },
+ "devDependencies": {
+ "tap": "^12.1.1"
+ },
+ "scripts": {
+ "test": "tap test/*.js --cov"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/isaacs/mute-stream.git"
+ },
+ "keywords": [
+ "mute",
+ "stream",
+ "pipe"
+ ],
+ "author": {
+ "name": "Isaac Z. Schlueter",
+ "email": "i@izs.me",
+ "url": "http://blog.izs.me/"
+ },
+ "license": "ISC",
+ "description": "Bytes go in, but they don't come out (when muted).",
+ "gitHead": "aa4a4baeaff5eeec83b5717738a44642f6948a9f",
+ "bugs": {
+ "url": "https://github.com/isaacs/mute-stream/issues"
+ },
+ "homepage": "https://github.com/isaacs/mute-stream#readme",
+ "_id": "mute-stream@0.0.8",
+ "_npmVersion": "6.5.0",
+ "_nodeVersion": "10.12.0",
+ "_npmUser": {
+ "name": "isaacs",
+ "email": "i@izs.me"
+ },
+ "dist": {
+ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+ "shasum": "1630c42b2251ff81e2a283de96a5497ea92e5e0d",
+ "tarball": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+ "fileCount": 4,
+ "unpackedSize": 6510,
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcJbNmCRA9TVsSAnZWagAAqWAQAKPRVoWEA71FOyJZI74r\nk9WXeZXrDhrMvS1flnEwZOvZH8h6WcJJ5549mgcVQynEhlQkXW4+UP/sdheG\nBjW7ALN9HCTKqCirBbUyB0hRWIqvNXEsO4D00wu+kcrqOWLc20sNGpmweoow\nrIuwvTD3tdbbZl5HgXsxSVoescg6vRWIU+iNJps9W7bzZXOwGtl1nHHnQ47T\nXuK3OlS6adaBMdtO1LFkDgRdE9Ez5TGSwvAk8siEym7ypVnnUlia43ocAsks\nFvgcq9duPjwJFFwJTzlwX87w4eWY0Y2LVc19iwNXqv49V8pM0JhBXO4OGHFa\nKaRGtbBqN75GlYuzzUNfekPKE1/32tnVxywjFScLzYhruzLHvxhFESDSuptv\ny6ZGWl2v8+TLTRhRpuBPIEuezBS2CdcAvKDLAAsM6mjxyfzfee13cSGzgf/c\nh5Fl179EZE/KnXko9y7GeMXMKsBYzup+pWb2knzFzhR79hb8vjqX/kqffVV7\nz8Igu7YRfzyIRl/ju2MU/mf7HjoIEO+PG6tdiGzr5DnjxFa7A2cWxSInmHyq\nOBqPlWJ7iqRsEv+Ubc+cjdM3oSAlOiizcbwnKAPmDoD8PZsRO7fYNB8pCvBh\nR8/8DIueC5ZN3lrVd+EWhELXVkPWrQHyAzAmtzpF0CrrxXrS1JMjd+ZhbDWF\nWW4l\r\n=SOUD\r\n-----END PGP SIGNATURE-----\r\n"
+ },
+ "maintainers": [
+ {
+ "email": "me@re-becca.org",
+ "name": "iarna"
+ },
+ {
+ "email": "i@izs.me",
+ "name": "isaacs"
+ },
+ {
+ "email": "ogd@aoaioxxysz.net",
+ "name": "othiym23"
+ },
+ {
+ "email": "kzm@sykosomatic.org",
+ "name": "zkat"
+ }
+ ],
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/mute-stream_0.0.8_1545974629018_0.7215891164233619"
+ },
+ "_hasShrinkwrap": false,
+ "_shasum": "1630c42b2251ff81e2a283de96a5497ea92e5e0d",
+ "_from": "mute-stream@~0.0.4",
+ "_resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz"
+}
--- /dev/null
+{
+ "name": "read",
+ "version": "1.0.7",
+ "main": "lib/read.js",
+ "dependencies": {
+ "mute-stream": "~0.0.4"
+ },
+ "devDependencies": {
+ "tap": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=0.8"
+ },
+ "author": {
+ "name": "Isaac Z. Schlueter",
+ "email": "i@izs.me",
+ "url": "http://blog.izs.me/"
+ },
+ "description": "read(1) for node programs",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/isaacs/read.git"
+ },
+ "license": "ISC",
+ "scripts": {
+ "test": "tap test/*.js"
+ },
+ "files": [
+ "lib/read.js"
+ ],
+ "gitHead": "b14516b9236c40140fd0666567f5d0c588a09a62",
+ "bugs": {
+ "url": "https://github.com/isaacs/read/issues"
+ },
+ "homepage": "https://github.com/isaacs/read#readme",
+ "_id": "read@1.0.7",
+ "_shasum": "b3da19bd052431a97671d44a42634adf710b40c4",
+ "_from": "read@~1.0.7",
+ "_npmVersion": "3.2.2",
+ "_nodeVersion": "2.2.1",
+ "_npmUser": {
+ "name": "isaacs",
+ "email": "isaacs@npmjs.com"
+ },
+ "dist": {
+ "shasum": "b3da19bd052431a97671d44a42634adf710b40c4",
+ "tarball": "https://registry.npmjs.org/read/-/read-1.0.7.tgz"
+ },
+ "maintainers": [
+ {
+ "name": "isaacs",
+ "email": "i@izs.me"
+ }
+ ],
+ "directories": {},
+ "_resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz"
+}
--- /dev/null
+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.
--- /dev/null
+# 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: [server][server-report],
+[client][client-report].
+
+**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.
+To make the same code work seamlessly on Node.js and the browser, you can use
+one of the many wrappers available on npm, like
+[isomorphic-ws](https://github.com/heineiuo/isomorphic-ws).
+
+## Table of Contents
+
+* [Protocol support](#protocol-support)
+* [Installing](#installing)
+ + [Opt-in for performance and spec compliance](#opt-in-for-performance-and-spec-compliance)
+* [API docs](#api-docs)
+* [WebSocket compression](#websocket-compression)
+* [Usage examples](#usage-examples)
+ + [Sending and receiving text data](#sending-and-receiving-text-data)
+ + [Sending binary data](#sending-binary-data)
+ + [Simple server](#simple-server)
+ + [External HTTP/S server](#external-https-server)
+ + [Multiple servers sharing a single HTTP/S server](#multiple-servers-sharing-a-single-https-server)
+ + [Server broadcast](#server-broadcast)
+ + [echo.websocket.org demo](#echowebsocketorg-demo)
+ + [Other examples](#other-examples)
+* [Error handling best practices](#error-handling-best-practices)
+* [FAQ](#faq)
+ + [How to get the IP address of the client?](#how-to-get-the-ip-address-of-the-client)
+ + [How to detect and close broken connections?](#how-to-detect-and-close-broken-connections)
+ + [How to connect via a proxy?](#how-to-connect-via-a-proxy)
+* [Changelog](#changelog)
+* [License](#license)
+
+## 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`](./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 disabled by default on the server and enabled by default on
+the client. It adds a significant overhead in terms of performance and memory
+consumption so we suggest to enable it only if it is really needed.
+
+Note that Node.js has a variety of issues with high-performance compression,
+where increased concurrency, especially on Linux, can lead to
+[catastrophic memory fragmentation][node-zlib-bug] and slow performance.
+If you intend to use permessage-deflate in production, it is worthwhile to set
+up a test representative of your workload and ensure Node.js/zlib will handle
+it with acceptable performance and memory usage.
+
+Tuning of permessage-deflate can be done via the options defined below. You can
+also use `zlibDeflateOptions` and `zlibInflateOptions`, which is passed directly
+into the creation of [raw deflate/inflate streams][node-zlib-deflaterawdocs].
+
+See [the docs][ws-server-options] for more options.
+
+```js
+const WebSocket = require('ws');
+
+const wss = new WebSocket.Server({
+ port: 8080,
+ perMessageDeflate: {
+ zlibDeflateOptions: { // See zlib defaults.
+ chunkSize: 1024,
+ memLevel: 7,
+ level: 3,
+ },
+ zlibInflateOptions: {
+ chunkSize: 10 * 1024
+ },
+ // Other options settable:
+ clientNoContextTakeover: true, // Defaults to negotiated value.
+ serverNoContextTakeover: true, // Defaults to negotiated value.
+ clientMaxWindowBits: 10, // Defaults to negotiated value.
+ serverMaxWindowBits: 10, // Defaults to negotiated value.
+ // Below options specified as default values.
+ concurrencyLimit: 10, // Limits zlib concurrency for perf.
+ threshold: 1024, // Size (in bytes) below which messages
+ // should not be compressed.
+ }
+});
+```
+
+The client will only use the extension if it is supported and enabled on the
+server. To always disable the extension on the client set the
+`perMessageDeflate` option to `false`.
+
+```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) {
+ console.log(data);
+});
+```
+
+### 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);
+});
+```
+
+### Simple server
+
+```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');
+});
+```
+
+### External HTTP/S server
+
+```js
+const fs = require('fs');
+const https = require('https');
+const WebSocket = require('ws');
+
+const server = new https.createServer({
+ cert: fs.readFileSync('/path/to/cert.pem'),
+ key: fs.readFileSync('/path/to/key.pem')
+});
+const wss = new WebSocket.Server({ server });
+
+wss.on('connection', function connection(ws) {
+ ws.on('message', function incoming(message) {
+ console.log('received: %s', message);
+ });
+
+ ws.send('something');
+});
+
+server.listen(8080);
+```
+
+### Multiple servers sharing a single HTTP/S server
+
+```js
+const http = require('http');
+const WebSocket = require('ws');
+
+const server = http.createServer();
+const wss1 = new WebSocket.Server({ noServer: true });
+const wss2 = new WebSocket.Server({ noServer: true });
+
+wss1.on('connection', function connection(ws) {
+ // ...
+});
+
+wss2.on('connection', function connection(ws) {
+ // ...
+});
+
+server.on('upgrade', function upgrade(request, socket, head) {
+ const pathname = url.parse(request.url).pathname;
+
+ if (pathname === '/foo') {
+ wss1.handleUpgrade(request, socket, head, function done(ws) {
+ wss1.emit('connection', ws, request);
+ });
+ } else if (pathname === '/bar') {
+ wss2.handleUpgrade(request, socket, head, function done(ws) {
+ wss2.emit('connection', ws, request);
+ });
+ } else {
+ socket.destroy();
+ }
+});
+
+server.listen(8080);
+```
+
+### Server broadcast
+
+```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);
+ }
+ });
+ });
+});
+```
+
+### 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) {
+ console.log(`Roundtrip time: ${Date.now() - data} ms`);
+
+ 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 */ }
+```
+
+## FAQ
+
+### How to get the IP address of the client?
+
+The remote IP address can be obtained from the raw socket.
+
+```js
+const WebSocket = require('ws');
+
+const wss = new WebSocket.Server({ port: 8080 });
+
+wss.on('connection', function connection(ws, req) {
+ const ip = req.connection.remoteAddress;
+});
+```
+
+When the server runs behind a proxy like NGINX, the de-facto standard is to use
+the `X-Forwarded-For` header.
+
+```js
+wss.on('connection', function connection(ws, req) {
+ const ip = req.headers['x-forwarded-for'].split(/\s*,\s*/)[0];
+});
+```
+
+### How to detect and close broken connections?
+
+Sometimes the link between the server and the client can be interrupted in a
+way that keeps both the server and the client unaware of the broken state of the
+connection (e.g. when pulling the cord).
+
+In these cases ping messages can be used as a means to verify that the remote
+endpoint is still responsive.
+
+```js
+const WebSocket = require('ws');
+
+const wss = new WebSocket.Server({ port: 8080 });
+
+function noop() {}
+
+function heartbeat() {
+ this.isAlive = true;
+}
+
+wss.on('connection', function connection(ws) {
+ ws.isAlive = true;
+ ws.on('pong', heartbeat);
+});
+
+const interval = setInterval(function ping() {
+ wss.clients.forEach(function each(ws) {
+ if (ws.isAlive === false) return ws.terminate();
+
+ ws.isAlive = false;
+ ws.ping(noop);
+ });
+}, 30000);
+```
+
+Pong messages are automatically sent in response to ping messages as required
+by the spec.
+
+### How to connect via a proxy?
+
+Use a custom `http.Agent` implementation like [https-proxy-agent][] or
+[socks-proxy-agent][].
+
+## Changelog
+
+We're using the GitHub [releases][changelog] for changelog entries.
+
+## License
+
+[MIT](LICENSE)
+
+[https-proxy-agent]: https://github.com/TooTallNate/node-https-proxy-agent
+[socks-proxy-agent]: https://github.com/TooTallNate/node-socks-proxy-agent
+[client-report]: http://websockets.github.io/ws/autobahn/clients/
+[server-report]: http://websockets.github.io/ws/autobahn/servers/
+[permessage-deflate]: https://tools.ietf.org/html/rfc7692
+[changelog]: https://github.com/websockets/ws/releases
+[node-zlib-bug]: https://github.com/nodejs/node/issues/8871
+[node-zlib-deflaterawdocs]: https://nodejs.org/api/zlib.html#zlib_zlib_createdeflateraw_options
+[ws-server-options]: https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback
--- /dev/null
+'use strict';
+
+const WebSocket = require('./lib/websocket');
+
+WebSocket.Server = require('./lib/websocket-server');
+WebSocket.Receiver = require('./lib/receiver');
+WebSocket.Sender = require('./lib/sender');
+
+module.exports = WebSocket;
--- /dev/null
+'use strict';
+
+/**
+ * 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
+ */
+function 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;
+}
+
+/**
+ * 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
+ */
+function _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
+ */
+function _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];
+ }
+}
+
+try {
+ const bufferUtil = require('bufferutil');
+ const bu = bufferUtil.BufferUtil || bufferUtil;
+
+ module.exports = {
+ mask (source, mask, output, offset, length) {
+ if (length < 48) _mask(source, mask, output, offset, length);
+ else bu.mask(source, mask, output, offset, length);
+ },
+ unmask (buffer, mask) {
+ if (buffer.length < 32) _unmask(buffer, mask);
+ else bu.unmask(buffer, mask);
+ },
+ concat
+ };
+} catch (e) /* istanbul ignore next */ {
+ module.exports = { concat, mask: _mask, unmask: _unmask };
+}
--- /dev/null
+'use strict';
+
+module.exports = {
+ BINARY_TYPES: ['nodebuffer', 'arraybuffer', 'fragments'],
+ GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
+ kStatusCode: Symbol('status-code'),
+ kWebSocket: Symbol('websocket'),
+ EMPTY_BUFFER: Buffer.alloc(0),
+ NOOP: () => {}
+};
--- /dev/null
+'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 {WebSocket} target A reference to the target to which the event was dispatched
+ */
+ constructor (data, target) {
+ super('message', target);
+
+ 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 = target._closeFrameReceived && target._closeFrameSent;
+ this.reason = reason;
+ 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);
+ }
+}
+
+/**
+ * Class representing an error event.
+ *
+ * @extends Event
+ * @private
+ */
+class ErrorEvent extends Event {
+ /**
+ * Create a new `ErrorEvent`.
+ *
+ * @param {Object} error The error that generated this event
+ * @param {WebSocket} target A reference to the target to which the event was dispatched
+ */
+ constructor (error, target) {
+ super('error', target);
+
+ this.message = error.message;
+ this.error = error;
+ }
+}
+
+/**
+ * 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) {
+ listener.call(this, new MessageEvent(data, this));
+ }
+
+ function onClose (code, message) {
+ listener.call(this, new CloseEvent(code, message, this));
+ }
+
+ function onError (error) {
+ listener.call(this, new ErrorEvent(error, this));
+ }
+
+ 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;
--- /dev/null
+'use strict';
+
+//
+// Allowed token characters:
+//
+// '!', '#', '$', '%', '&', ''', '*', '+', '-',
+// '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~'
+//
+// tokenChars[32] === 0 // ' '
+// tokenChars[33] === 1 // '!'
+// tokenChars[34] === 0 // '"'
+// ...
+//
+const tokenChars = [
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31
+ 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127
+];
+
+/**
+ * Adds an offer to the map of extension offers or a parameter to the map of
+ * parameters.
+ *
+ * @param {Object} dest The map of extension offers or parameters
+ * @param {String} name The extension or parameter name
+ * @param {(Object|Boolean|String)} elem The extension parameters or the
+ * parameter value
+ * @private
+ */
+function push (dest, name, elem) {
+ if (Object.prototype.hasOwnProperty.call(dest, name)) dest[name].push(elem);
+ else dest[name] = [elem];
+}
+
+/**
+ * Parses the `Sec-WebSocket-Extensions` header into an object.
+ *
+ * @param {String} header The field value of the header
+ * @return {Object} The parsed object
+ * @public
+ */
+function parse (header) {
+ const offers = {};
+
+ if (header === undefined || header === '') return offers;
+
+ var params = {};
+ var mustUnescape = false;
+ var isEscaping = false;
+ var inQuotes = false;
+ var extensionName;
+ var paramName;
+ var start = -1;
+ var end = -1;
+
+ for (var i = 0; i < header.length; i++) {
+ const code = header.charCodeAt(i);
+
+ if (extensionName === undefined) {
+ if (end === -1 && tokenChars[code] === 1) {
+ if (start === -1) start = i;
+ } else if (code === 0x20/* ' ' */|| code === 0x09/* '\t' */) {
+ if (end === -1 && start !== -1) end = i;
+ } else if (code === 0x3b/* ';' */ || code === 0x2c/* ',' */) {
+ if (start === -1) {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+
+ if (end === -1) end = i;
+ const name = header.slice(start, end);
+ if (code === 0x2c) {
+ push(offers, name, params);
+ params = {};
+ } else {
+ extensionName = name;
+ }
+
+ start = end = -1;
+ } else {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+ } else if (paramName === undefined) {
+ if (end === -1 && tokenChars[code] === 1) {
+ if (start === -1) start = i;
+ } else if (code === 0x20 || code === 0x09) {
+ if (end === -1 && start !== -1) end = i;
+ } else if (code === 0x3b || code === 0x2c) {
+ if (start === -1) {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+
+ if (end === -1) end = i;
+ push(params, header.slice(start, end), true);
+ if (code === 0x2c) {
+ push(offers, extensionName, params);
+ params = {};
+ extensionName = undefined;
+ }
+
+ start = end = -1;
+ } else if (code === 0x3d/* '=' */&& start !== -1 && end === -1) {
+ paramName = header.slice(start, i);
+ start = end = -1;
+ } else {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+ } else {
+ //
+ // The value of a quoted-string after unescaping must conform to the
+ // token ABNF, so only token characters are valid.
+ // Ref: https://tools.ietf.org/html/rfc6455#section-9.1
+ //
+ if (isEscaping) {
+ if (tokenChars[code] !== 1) {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+ if (start === -1) start = i;
+ else if (!mustUnescape) mustUnescape = true;
+ isEscaping = false;
+ } else if (inQuotes) {
+ if (tokenChars[code] === 1) {
+ if (start === -1) start = i;
+ } else if (code === 0x22/* '"' */ && start !== -1) {
+ inQuotes = false;
+ end = i;
+ } else if (code === 0x5c/* '\' */) {
+ isEscaping = true;
+ } else {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+ } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {
+ inQuotes = true;
+ } else if (end === -1 && tokenChars[code] === 1) {
+ if (start === -1) start = i;
+ } else if (start !== -1 && (code === 0x20 || code === 0x09)) {
+ if (end === -1) end = i;
+ } else if (code === 0x3b || code === 0x2c) {
+ if (start === -1) {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+
+ if (end === -1) end = i;
+ var value = header.slice(start, end);
+ if (mustUnescape) {
+ value = value.replace(/\\/g, '');
+ mustUnescape = false;
+ }
+ push(params, paramName, value);
+ if (code === 0x2c) {
+ push(offers, extensionName, params);
+ params = {};
+ extensionName = undefined;
+ }
+
+ paramName = undefined;
+ start = end = -1;
+ } else {
+ throw new SyntaxError(`Unexpected character at index ${i}`);
+ }
+ }
+ }
+
+ if (start === -1 || inQuotes) {
+ throw new SyntaxError('Unexpected end of input');
+ }
+
+ if (end === -1) end = i;
+ const token = header.slice(start, end);
+ if (extensionName === undefined) {
+ push(offers, token, {});
+ } else {
+ if (paramName === undefined) {
+ push(params, token, true);
+ } else if (mustUnescape) {
+ push(params, paramName, token.replace(/\\/g, ''));
+ } else {
+ push(params, paramName, token);
+ }
+ push(offers, extensionName, params);
+ }
+
+ return offers;
+}
+
+/**
+ * Builds the `Sec-WebSocket-Extensions` header field value.
+ *
+ * @param {Object} extensions The map of extensions and parameters to format
+ * @return {String} A string representing the given object
+ * @public
+ */
+function format (extensions) {
+ return Object.keys(extensions).map((extension) => {
+ var configurations = extensions[extension];
+ if (!Array.isArray(configurations)) configurations = [configurations];
+ return configurations.map((params) => {
+ return [extension].concat(Object.keys(params).map((k) => {
+ var values = params[k];
+ if (!Array.isArray(values)) values = [values];
+ return values.map((v) => v === true ? k : `${k}=${v}`).join('; ');
+ })).join('; ');
+ }).join(', ');
+ }).join(', ');
+}
+
+module.exports = { format, parse };
--- /dev/null
+'use strict';
+
+const Limiter = require('async-limiter');
+const zlib = require('zlib');
+
+const bufferUtil = require('./buffer-util');
+const constants = require('./constants');
+
+const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);
+const EMPTY_BLOCK = Buffer.from([0x00]);
+
+const kPerMessageDeflate = Symbol('permessage-deflate');
+const kWriteInProgress = Symbol('write-in-progress');
+const kPendingClose = Symbol('pending-close');
+const kTotalLength = Symbol('total-length');
+const kCallback = Symbol('callback');
+const kBuffers = Symbol('buffers');
+const kError = Symbol('error');
+
+//
+// We limit zlib concurrency, which prevents severe memory fragmentation
+// as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913
+// and https://github.com/websockets/ws/issues/1202
+//
+// Intentionally global; it's the global thread pool that's an issue.
+//
+let zlibLimiter;
+
+/**
+ * permessage-deflate implementation.
+ */
+class PerMessageDeflate {
+ /**
+ * Creates a PerMessageDeflate instance.
+ *
+ * @param {Object} options Configuration options
+ * @param {Boolean} options.serverNoContextTakeover Request/accept disabling
+ * of server context takeover
+ * @param {Boolean} options.clientNoContextTakeover Advertise/acknowledge
+ * disabling of client context takeover
+ * @param {(Boolean|Number)} options.serverMaxWindowBits Request/confirm the
+ * use of a custom server window size
+ * @param {(Boolean|Number)} options.clientMaxWindowBits Advertise support
+ * for, or request, a custom client window size
+ * @param {Object} options.zlibDeflateOptions Options to pass to zlib on deflate
+ * @param {Object} options.zlibInflateOptions Options to pass to zlib on inflate
+ * @param {Number} options.threshold Size (in bytes) below which messages
+ * should not be compressed
+ * @param {Number} options.concurrencyLimit The number of concurrent calls to
+ * zlib
+ * @param {Boolean} isServer Create the instance in either server or client
+ * mode
+ * @param {Number} maxPayload The maximum allowed message length
+ */
+ constructor (options, isServer, maxPayload) {
+ this._maxPayload = maxPayload | 0;
+ this._options = options || {};
+ this._threshold = this._options.threshold !== undefined
+ ? this._options.threshold
+ : 1024;
+ this._isServer = !!isServer;
+ this._deflate = null;
+ this._inflate = null;
+
+ this.params = null;
+
+ if (!zlibLimiter) {
+ const concurrency = this._options.concurrencyLimit !== undefined
+ ? this._options.concurrencyLimit
+ : 10;
+ zlibLimiter = new Limiter({ concurrency });
+ }
+ }
+
+ /**
+ * @type {String}
+ */
+ static get extensionName () {
+ return 'permessage-deflate';
+ }
+
+ /**
+ * Create an extension negotiation 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 an extension negotiation offer/response.
+ *
+ * @param {Array} configurations The extension negotiation offers/reponse
+ * @return {Object} Accepted configuration
+ * @public
+ */
+ accept (configurations) {
+ configurations = this.normalizeParams(configurations);
+
+ this.params = this._isServer
+ ? this.acceptAsServer(configurations)
+ : this.acceptAsClient(configurations);
+
+ return this.params;
+ }
+
+ /**
+ * Releases all resources used by the extension.
+ *
+ * @public
+ */
+ cleanup () {
+ if (this._inflate) {
+ if (this._inflate[kWriteInProgress]) {
+ this._inflate[kPendingClose] = true;
+ } else {
+ this._inflate.close();
+ this._inflate = null;
+ }
+ }
+ if (this._deflate) {
+ if (this._deflate[kWriteInProgress]) {
+ this._deflate[kPendingClose] = true;
+ } else {
+ this._deflate.close();
+ this._deflate = null;
+ }
+ }
+ }
+
+ /**
+ * Accept an extension negotiation offer.
+ *
+ * @param {Array} offers The extension negotiation offers
+ * @return {Object} Accepted configuration
+ * @private
+ */
+ acceptAsServer (offers) {
+ const opts = this._options;
+ const accepted = offers.find((params) => {
+ if (
+ (opts.serverNoContextTakeover === false &&
+ params.server_no_context_takeover) ||
+ (params.server_max_window_bits &&
+ (opts.serverMaxWindowBits === false ||
+ (typeof opts.serverMaxWindowBits === 'number' &&
+ opts.serverMaxWindowBits > params.server_max_window_bits))) ||
+ (typeof opts.clientMaxWindowBits === 'number' &&
+ !params.client_max_window_bits)
+ ) {
+ return false;
+ }
+
+ return true;
+ });
+
+ if (!accepted) {
+ throw new Error('None of the extension offers can be accepted');
+ }
+
+ if (opts.serverNoContextTakeover) {
+ accepted.server_no_context_takeover = true;
+ }
+ if (opts.clientNoContextTakeover) {
+ accepted.client_no_context_takeover = true;
+ }
+ if (typeof opts.serverMaxWindowBits === 'number') {
+ accepted.server_max_window_bits = opts.serverMaxWindowBits;
+ }
+ if (typeof opts.clientMaxWindowBits === 'number') {
+ accepted.client_max_window_bits = opts.clientMaxWindowBits;
+ } else if (
+ accepted.client_max_window_bits === true ||
+ opts.clientMaxWindowBits === false
+ ) {
+ delete accepted.client_max_window_bits;
+ }
+
+ return accepted;
+ }
+
+ /**
+ * Accept the extension negotiation response.
+ *
+ * @param {Array} response The extension negotiation response
+ * @return {Object} Accepted configuration
+ * @private
+ */
+ acceptAsClient (response) {
+ const params = response[0];
+
+ if (
+ this._options.clientNoContextTakeover === false &&
+ params.client_no_context_takeover
+ ) {
+ throw new Error('Unexpected parameter "client_no_context_takeover"');
+ }
+
+ if (!params.client_max_window_bits) {
+ if (typeof this._options.clientMaxWindowBits === 'number') {
+ params.client_max_window_bits = this._options.clientMaxWindowBits;
+ }
+ } else if (
+ this._options.clientMaxWindowBits === false ||
+ (typeof this._options.clientMaxWindowBits === 'number' &&
+ params.client_max_window_bits > this._options.clientMaxWindowBits)
+ ) {
+ throw new Error(
+ 'Unexpected or invalid parameter "client_max_window_bits"'
+ );
+ }
+
+ return params;
+ }
+
+ /**
+ * Normalize parameters.
+ *
+ * @param {Array} configurations The extension negotiation offers/reponse
+ * @return {Array} The offers/response with normalized parameters
+ * @private
+ */
+ normalizeParams (configurations) {
+ configurations.forEach((params) => {
+ Object.keys(params).forEach((key) => {
+ var value = params[key];
+
+ if (value.length > 1) {
+ throw new Error(`Parameter "${key}" must have only a single value`);
+ }
+
+ value = value[0];
+
+ if (key === 'client_max_window_bits') {
+ if (value !== true) {
+ const num = +value;
+ if (!Number.isInteger(num) || num < 8 || num > 15) {
+ throw new TypeError(
+ `Invalid value for parameter "${key}": ${value}`
+ );
+ }
+ value = num;
+ } else if (!this._isServer) {
+ throw new TypeError(
+ `Invalid value for parameter "${key}": ${value}`
+ );
+ }
+ } else if (key === 'server_max_window_bits') {
+ const num = +value;
+ if (!Number.isInteger(num) || num < 8 || num > 15) {
+ throw new TypeError(
+ `Invalid value for parameter "${key}": ${value}`
+ );
+ }
+ value = num;
+ } else if (
+ key === 'client_no_context_takeover' ||
+ key === 'server_no_context_takeover'
+ ) {
+ if (value !== true) {
+ throw new TypeError(
+ `Invalid value for parameter "${key}": ${value}`
+ );
+ }
+ } else {
+ throw new Error(`Unknown parameter "${key}"`);
+ }
+
+ params[key] = value;
+ });
+ });
+
+ return configurations;
+ }
+
+ /**
+ * Decompress data. Concurrency limited by async-limiter.
+ *
+ * @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) {
+ zlibLimiter.push((done) => {
+ this._decompress(data, fin, (err, result) => {
+ done();
+ callback(err, result);
+ });
+ });
+ }
+
+ /**
+ * Compress data. Concurrency limited by async-limiter.
+ *
+ * @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) {
+ zlibLimiter.push((done) => {
+ this._compress(data, fin, (err, result) => {
+ done();
+ callback(err, result);
+ });
+ });
+ }
+
+ /**
+ * Decompress data.
+ *
+ * @param {Buffer} data Compressed data
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
+ * @param {Function} callback Callback
+ * @private
+ */
+ _decompress (data, fin, callback) {
+ const endpoint = this._isServer ? 'client' : 'server';
+
+ if (!this._inflate) {
+ const key = `${endpoint}_max_window_bits`;
+ const windowBits = typeof this.params[key] !== 'number'
+ ? zlib.Z_DEFAULT_WINDOWBITS
+ : this.params[key];
+
+ this._inflate = zlib.createInflateRaw(
+ Object.assign({}, this._options.zlibInflateOptions, { windowBits })
+ );
+ this._inflate[kPerMessageDeflate] = this;
+ this._inflate[kTotalLength] = 0;
+ this._inflate[kBuffers] = [];
+ this._inflate.on('error', inflateOnError);
+ this._inflate.on('data', inflateOnData);
+ }
+
+ this._inflate[kCallback] = callback;
+ this._inflate[kWriteInProgress] = true;
+
+ this._inflate.write(data);
+ if (fin) this._inflate.write(TRAILER);
+
+ this._inflate.flush(() => {
+ const err = this._inflate[kError];
+
+ if (err) {
+ this._inflate.close();
+ this._inflate = null;
+ callback(err);
+ return;
+ }
+
+ const data = bufferUtil.concat(
+ this._inflate[kBuffers],
+ this._inflate[kTotalLength]
+ );
+
+ if (
+ (fin && this.params[`${endpoint}_no_context_takeover`]) ||
+ this._inflate[kPendingClose]
+ ) {
+ this._inflate.close();
+ this._inflate = null;
+ } else {
+ this._inflate[kWriteInProgress] = false;
+ this._inflate[kTotalLength] = 0;
+ this._inflate[kBuffers] = [];
+ }
+
+ callback(null, data);
+ });
+ }
+
+ /**
+ * Compress data.
+ *
+ * @param {Buffer} data Data to compress
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
+ * @param {Function} callback Callback
+ * @private
+ */
+ _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 key = `${endpoint}_max_window_bits`;
+ const windowBits = typeof this.params[key] !== 'number'
+ ? zlib.Z_DEFAULT_WINDOWBITS
+ : this.params[key];
+
+ this._deflate = zlib.createDeflateRaw(
+ Object.assign(
+ // TODO deprecate memLevel/level and recommend zlibDeflateOptions instead
+ {
+ memLevel: this._options.memLevel,
+ level: this._options.level
+ },
+ this._options.zlibDeflateOptions,
+ { windowBits }
+ )
+ );
+
+ this._deflate[kTotalLength] = 0;
+ this._deflate[kBuffers] = [];
+
+ //
+ // `zlib.DeflateRaw` emits an `'error'` event only when an attempt to use
+ // it is made after it has already been closed. This cannot happen here,
+ // so we only add a listener for the `'data'` event.
+ //
+ this._deflate.on('data', deflateOnData);
+ }
+
+ this._deflate[kWriteInProgress] = true;
+
+ this._deflate.write(data);
+ this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {
+ var data = bufferUtil.concat(
+ this._deflate[kBuffers],
+ this._deflate[kTotalLength]
+ );
+
+ if (fin) data = data.slice(0, data.length - 4);
+
+ if (
+ (fin && this.params[`${endpoint}_no_context_takeover`]) ||
+ this._deflate[kPendingClose]
+ ) {
+ this._deflate.close();
+ this._deflate = null;
+ } else {
+ this._deflate[kWriteInProgress] = false;
+ this._deflate[kTotalLength] = 0;
+ this._deflate[kBuffers] = [];
+ }
+
+ callback(null, data);
+ });
+ }
+}
+
+module.exports = PerMessageDeflate;
+
+/**
+ * The listener of the `zlib.DeflateRaw` stream `'data'` event.
+ *
+ * @param {Buffer} chunk A chunk of data
+ * @private
+ */
+function deflateOnData (chunk) {
+ this[kBuffers].push(chunk);
+ this[kTotalLength] += chunk.length;
+}
+
+/**
+ * The listener of the `zlib.InflateRaw` stream `'data'` event.
+ *
+ * @param {Buffer} chunk A chunk of data
+ * @private
+ */
+function inflateOnData (chunk) {
+ this[kTotalLength] += chunk.length;
+
+ if (
+ this[kPerMessageDeflate]._maxPayload < 1 ||
+ this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload
+ ) {
+ this[kBuffers].push(chunk);
+ return;
+ }
+
+ this[kError] = new RangeError('Max payload size exceeded');
+ this[kError][constants.kStatusCode] = 1009;
+ this.removeListener('data', inflateOnData);
+ this.reset();
+}
+
+/**
+ * The listener of the `zlib.InflateRaw` stream `'error'` event.
+ *
+ * @param {Error} err The emitted error
+ * @private
+ */
+function inflateOnError (err) {
+ //
+ // There is no need to call `Zlib#close()` as the handle is automatically
+ // closed when an error is emitted.
+ //
+ this[kPerMessageDeflate]._inflate = null;
+ err[constants.kStatusCode] = 1007;
+ this[kCallback](err);
+}
--- /dev/null
+'use strict';
+
+const stream = require('stream');
+
+const PerMessageDeflate = require('./permessage-deflate');
+const bufferUtil = require('./buffer-util');
+const validation = require('./validation');
+const constants = require('./constants');
+
+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.
+ *
+ * @extends stream.Writable
+ */
+class Receiver extends stream.Writable {
+ /**
+ * Creates a Receiver instance.
+ *
+ * @param {String} binaryType The type for binary data
+ * @param {Object} extensions An object containing the negotiated extensions
+ * @param {Number} maxPayload The maximum allowed message length
+ */
+ constructor (binaryType, extensions, maxPayload) {
+ super();
+
+ this._binaryType = binaryType || constants.BINARY_TYPES[0];
+ this[constants.kWebSocket] = undefined;
+ this._extensions = extensions || {};
+ this._maxPayload = maxPayload | 0;
+
+ this._bufferedBytes = 0;
+ this._buffers = [];
+
+ this._compressed = false;
+ this._payloadLength = 0;
+ this._mask = undefined;
+ this._fragmented = 0;
+ this._masked = false;
+ this._fin = false;
+ this._opcode = 0;
+
+ this._totalPayloadLength = 0;
+ this._messageLength = 0;
+ this._fragments = [];
+
+ this._state = GET_INFO;
+ this._loop = false;
+ }
+
+ /**
+ * Implements `Writable.prototype._write()`.
+ *
+ * @param {Buffer} chunk The chunk of data to write
+ * @param {String} encoding The character encoding of `chunk`
+ * @param {Function} cb Callback
+ */
+ _write (chunk, encoding, cb) {
+ if (this._opcode === 0x08) return cb();
+
+ this._bufferedBytes += chunk.length;
+ this._buffers.push(chunk);
+ this.startLoop(cb);
+ }
+
+ /**
+ * Consumes `n` bytes from the buffered data.
+ *
+ * @param {Number} n The number of bytes to consume
+ * @return {Buffer} The consumed bytes
+ * @private
+ */
+ consume (n) {
+ this._bufferedBytes -= n;
+
+ if (n === this._buffers[0].length) return this._buffers.shift();
+
+ if (n < this._buffers[0].length) {
+ const buf = this._buffers[0];
+ this._buffers[0] = buf.slice(n);
+ return buf.slice(0, n);
+ }
+
+ const dst = Buffer.allocUnsafe(n);
+
+ do {
+ const buf = this._buffers[0];
+
+ if (n >= buf.length) {
+ this._buffers.shift().copy(dst, dst.length - n);
+ } else {
+ buf.copy(dst, dst.length - n, 0, n);
+ this._buffers[0] = buf.slice(n);
+ }
+
+ n -= buf.length;
+ } while (n > 0);
+
+ return dst;
+ }
+
+ /**
+ * Starts the parsing loop.
+ *
+ * @param {Function} cb Callback
+ * @private
+ */
+ startLoop (cb) {
+ var err;
+ this._loop = true;
+
+ do {
+ switch (this._state) {
+ case GET_INFO:
+ err = this.getInfo();
+ break;
+ case GET_PAYLOAD_LENGTH_16:
+ err = this.getPayloadLength16();
+ break;
+ case GET_PAYLOAD_LENGTH_64:
+ err = this.getPayloadLength64();
+ break;
+ case GET_MASK:
+ this.getMask();
+ break;
+ case GET_DATA:
+ err = this.getData(cb);
+ break;
+ default: // `INFLATING`
+ this._loop = false;
+ return;
+ }
+ } while (this._loop);
+
+ cb(err);
+ }
+
+ /**
+ * Reads the first two bytes of a frame.
+ *
+ * @return {(RangeError|undefined)} A possible error
+ * @private
+ */
+ getInfo () {
+ if (this._bufferedBytes < 2) {
+ this._loop = false;
+ return;
+ }
+
+ const buf = this.consume(2);
+
+ if ((buf[0] & 0x30) !== 0x00) {
+ this._loop = false;
+ return error(RangeError, 'RSV2 and RSV3 must be clear', true, 1002);
+ }
+
+ const compressed = (buf[0] & 0x40) === 0x40;
+
+ if (compressed && !this._extensions[PerMessageDeflate.extensionName]) {
+ this._loop = false;
+ return error(RangeError, 'RSV1 must be clear', true, 1002);
+ }
+
+ this._fin = (buf[0] & 0x80) === 0x80;
+ this._opcode = buf[0] & 0x0f;
+ this._payloadLength = buf[1] & 0x7f;
+
+ if (this._opcode === 0x00) {
+ if (compressed) {
+ this._loop = false;
+ return error(RangeError, 'RSV1 must be clear', true, 1002);
+ }
+
+ if (!this._fragmented) {
+ this._loop = false;
+ return error(RangeError, 'invalid opcode 0', true, 1002);
+ }
+
+ this._opcode = this._fragmented;
+ } else if (this._opcode === 0x01 || this._opcode === 0x02) {
+ if (this._fragmented) {
+ this._loop = false;
+ return error(RangeError, `invalid opcode ${this._opcode}`, true, 1002);
+ }
+
+ this._compressed = compressed;
+ } else if (this._opcode > 0x07 && this._opcode < 0x0b) {
+ if (!this._fin) {
+ this._loop = false;
+ return error(RangeError, 'FIN must be set', true, 1002);
+ }
+
+ if (compressed) {
+ this._loop = false;
+ return error(RangeError, 'RSV1 must be clear', true, 1002);
+ }
+
+ if (this._payloadLength > 0x7d) {
+ this._loop = false;
+ return error(
+ RangeError,
+ `invalid payload length ${this._payloadLength}`,
+ true,
+ 1002
+ );
+ }
+ } else {
+ this._loop = false;
+ return error(RangeError, `invalid opcode ${this._opcode}`, true, 1002);
+ }
+
+ 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 return this.haveLength();
+ }
+
+ /**
+ * Gets extended payload length (7+16).
+ *
+ * @return {(RangeError|undefined)} A possible error
+ * @private
+ */
+ getPayloadLength16 () {
+ if (this._bufferedBytes < 2) {
+ this._loop = false;
+ return;
+ }
+
+ this._payloadLength = this.consume(2).readUInt16BE(0);
+ return this.haveLength();
+ }
+
+ /**
+ * Gets extended payload length (7+64).
+ *
+ * @return {(RangeError|undefined)} A possible error
+ * @private
+ */
+ getPayloadLength64 () {
+ if (this._bufferedBytes < 8) {
+ this._loop = false;
+ return;
+ }
+
+ const buf = this.consume(8);
+ const num = buf.readUInt32BE(0);
+
+ //
+ // 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._loop = false;
+ return error(
+ RangeError,
+ 'Unsupported WebSocket frame: payload length > 2^53 - 1',
+ false,
+ 1009
+ );
+ }
+
+ this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);
+ return this.haveLength();
+ }
+
+ /**
+ * Payload length has been read.
+ *
+ * @return {(RangeError|undefined)} A possible error
+ * @private
+ */
+ haveLength () {
+ if (this._payloadLength && this._opcode < 0x08) {
+ this._totalPayloadLength += this._payloadLength;
+ if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {
+ this._loop = false;
+ return error(RangeError, 'Max payload size exceeded', false, 1009);
+ }
+ }
+
+ if (this._masked) this._state = GET_MASK;
+ else this._state = GET_DATA;
+ }
+
+ /**
+ * Reads mask bytes.
+ *
+ * @private
+ */
+ getMask () {
+ if (this._bufferedBytes < 4) {
+ this._loop = false;
+ return;
+ }
+
+ this._mask = this.consume(4);
+ this._state = GET_DATA;
+ }
+
+ /**
+ * Reads data bytes.
+ *
+ * @param {Function} cb Callback
+ * @return {(Error|RangeError|undefined)} A possible error
+ * @private
+ */
+ getData (cb) {
+ var data = constants.EMPTY_BUFFER;
+
+ if (this._payloadLength) {
+ if (this._bufferedBytes < this._payloadLength) {
+ this._loop = false;
+ return;
+ }
+
+ data = this.consume(this._payloadLength);
+ if (this._masked) bufferUtil.unmask(data, this._mask);
+ }
+
+ if (this._opcode > 0x07) return this.controlMessage(data);
+
+ if (this._compressed) {
+ this._state = INFLATING;
+ this.decompress(data, cb);
+ return;
+ }
+
+ if (data.length) {
+ //
+ // This message is not compressed so its lenght is the sum of the payload
+ // length of all fragments.
+ //
+ this._messageLength = this._totalPayloadLength;
+ this._fragments.push(data);
+ }
+
+ return this.dataMessage();
+ }
+
+ /**
+ * Decompresses data.
+ *
+ * @param {Buffer} data Compressed data
+ * @param {Function} cb Callback
+ * @private
+ */
+ decompress (data, cb) {
+ const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
+
+ perMessageDeflate.decompress(data, this._fin, (err, buf) => {
+ if (err) return cb(err);
+
+ if (buf.length) {
+ this._messageLength += buf.length;
+ if (this._messageLength > this._maxPayload && this._maxPayload > 0) {
+ return cb(error(RangeError, 'Max payload size exceeded', false, 1009));
+ }
+
+ this._fragments.push(buf);
+ }
+
+ const er = this.dataMessage();
+ if (er) return cb(er);
+
+ this.startLoop(cb);
+ });
+ }
+
+ /**
+ * Handles a data message.
+ *
+ * @return {(Error|undefined)} A possible error
+ * @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.emit('message', data);
+ } else {
+ const buf = toBuffer(fragments, messageLength);
+
+ if (!validation.isValidUTF8(buf)) {
+ this._loop = false;
+ return error(Error, 'invalid UTF-8 sequence', true, 1007);
+ }
+
+ this.emit('message', buf.toString());
+ }
+ }
+
+ this._state = GET_INFO;
+ }
+
+ /**
+ * Handles a control message.
+ *
+ * @param {Buffer} data Data to handle
+ * @return {(Error|RangeError|undefined)} A possible error
+ * @private
+ */
+ controlMessage (data) {
+ if (this._opcode === 0x08) {
+ this._loop = false;
+
+ if (data.length === 0) {
+ this.emit('conclude', 1005, '');
+ this.end();
+ } else if (data.length === 1) {
+ return error(RangeError, 'invalid payload length 1', true, 1002);
+ } else {
+ const code = data.readUInt16BE(0);
+
+ if (!validation.isValidStatusCode(code)) {
+ return error(RangeError, `invalid status code ${code}`, true, 1002);
+ }
+
+ const buf = data.slice(2);
+
+ if (!validation.isValidUTF8(buf)) {
+ return error(Error, 'invalid UTF-8 sequence', true, 1007);
+ }
+
+ this.emit('conclude', code, buf.toString());
+ this.end();
+ }
+
+ return;
+ }
+
+ if (this._opcode === 0x09) this.emit('ping', data);
+ else this.emit('pong', data);
+
+ this._state = GET_INFO;
+ }
+}
+
+module.exports = Receiver;
+
+/**
+ * Builds an error object.
+ *
+ * @param {(Error|RangeError)} ErrorCtor The error constructor
+ * @param {String} message The error message
+ * @param {Boolean} prefix Specifies whether or not to add a default prefix to
+ * `message`
+ * @param {Number} statusCode The status code
+ * @return {(Error|RangeError)} The error
+ * @private
+ */
+function error (ErrorCtor, message, prefix, statusCode) {
+ const err = new ErrorCtor(
+ prefix ? `Invalid WebSocket frame: ${message}` : message
+ );
+
+ Error.captureStackTrace(err, error);
+ err[constants.kStatusCode] = statusCode;
+ return err;
+}
+
+/**
+ * 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);
+}
--- /dev/null
+'use strict';
+
+const crypto = require('crypto');
+
+const PerMessageDeflate = require('./permessage-deflate');
+const bufferUtil = require('./buffer-util');
+const validation = require('./validation');
+const constants = require('./constants');
+
+/**
+ * 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._extensions = extensions || {};
+ this._socket = socket;
+
+ this._firstFragment = true;
+ this._compress = false;
+
+ this._bufferedBytes = 0;
+ this._deflating = false;
+ this._queue = [];
+ }
+
+ /**
+ * 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);
+ } else if (payloadLength === 127) {
+ target.writeUInt32BE(0, 2);
+ target.writeUInt32BE(data.length, 6);
+ }
+
+ 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) {
+ var buf;
+
+ if (code === undefined) {
+ buf = constants.EMPTY_BUFFER;
+ } else if (typeof code !== 'number' || !validation.isValidStatusCode(code)) {
+ throw new TypeError('First argument must be a valid error code number');
+ } else if (data === undefined || data === '') {
+ buf = Buffer.allocUnsafe(2);
+ buf.writeUInt16BE(code, 0);
+ } else {
+ buf = Buffer.allocUnsafe(2 + Buffer.byteLength(data));
+ buf.writeUInt16BE(code, 0);
+ 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`
+ * @param {Function} cb Callback
+ * @public
+ */
+ ping (data, mask, cb) {
+ 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, cb]);
+ } else {
+ this.doPing(data, mask, readOnly, cb);
+ }
+ }
+
+ /**
+ * 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
+ * @param {Function} cb Callback
+ * @private
+ */
+ doPing (data, mask, readOnly, cb) {
+ this.sendFrame(Sender.frame(data, {
+ fin: true,
+ rsv1: false,
+ opcode: 0x09,
+ mask,
+ readOnly
+ }), cb);
+ }
+
+ /**
+ * Sends a pong message to the other peer.
+ *
+ * @param {*} data The message to send
+ * @param {Boolean} mask Specifies whether or not to mask `data`
+ * @param {Function} cb Callback
+ * @public
+ */
+ pong (data, mask, cb) {
+ 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, cb]);
+ } else {
+ this.doPong(data, mask, readOnly, cb);
+ }
+ }
+
+ /**
+ * 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
+ * @param {Function} cb Callback
+ * @private
+ */
+ doPong (data, mask, readOnly, cb) {
+ this.sendFrame(Sender.frame(data, {
+ fin: true,
+ rsv1: false,
+ opcode: 0x0a,
+ mask,
+ readOnly
+ }), cb);
+ }
+
+ /**
+ * 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;
+ }
+ }
+
+ const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
+
+ if (this._firstFragment) {
+ this._firstFragment = false;
+ if (rsv1 && perMessageDeflate) {
+ rsv1 = data.length >= perMessageDeflate._threshold;
+ }
+ this._compress = rsv1;
+ } else {
+ rsv1 = false;
+ opcode = 0;
+ }
+
+ if (options.fin) this._firstFragment = true;
+
+ if (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;
+ }
+
+ const perMessageDeflate = this._extensions[PerMessageDeflate.extensionName];
+
+ this._deflating = true;
+ perMessageDeflate.compress(data, options.fin, (_, buf) => {
+ 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;
+}
--- /dev/null
+'use strict';
+
+try {
+ const isValidUTF8 = require('utf-8-validate');
+
+ exports.isValidUTF8 = typeof isValidUTF8 === 'object'
+ ? isValidUTF8.Validation.isValidUTF8 // utf-8-validate@<3.0.0
+ : isValidUTF8;
+} catch (e) /* istanbul ignore next */ {
+ exports.isValidUTF8 = () => true;
+}
+
+/**
+ * Checks if a status code is allowed in a close frame.
+ *
+ * @param {Number} code The status code
+ * @return {Boolean} `true` if the status code is valid, else `false`
+ * @public
+ */
+exports.isValidStatusCode = (code) => {
+ return (
+ (code >= 1000 &&
+ code <= 1013 &&
+ code !== 1004 &&
+ code !== 1005 &&
+ code !== 1006) ||
+ (code >= 3000 && code <= 4999)
+ );
+};
--- /dev/null
+'use strict';
+
+const EventEmitter = require('events');
+const crypto = require('crypto');
+const http = require('http');
+const url = require('url');
+
+const PerMessageDeflate = require('./permessage-deflate');
+const extension = require('./extension');
+const constants = require('./constants');
+const WebSocket = require('./websocket');
+
+/**
+ * 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: false,
+ 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(
+ 'One of the "port", "server", or "noServer" options must be specified'
+ );
+ }
+
+ 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.listen(options.port, options.host, options.backlog, callback);
+ } else if (options.server) {
+ this._server = options.server;
+ }
+
+ if (this._server) {
+ this._removeListeners = addListeners(this._server, {
+ listening: this.emit.bind(this, 'listening'),
+ error: this.emit.bind(this, 'error'),
+ upgrade: (req, socket, head) => {
+ this.handleUpgrade(req, socket, head, (ws) => {
+ this.emit('connection', ws, req);
+ });
+ }
+ });
+ }
+
+ if (options.perMessageDeflate === true) options.perMessageDeflate = {};
+ if (options.clientTracking) this.clients = new Set();
+ this.options = options;
+ }
+
+ /**
+ * Returns the bound address, the address family name, and port of the server
+ * as reported by the operating system if listening on an IP socket.
+ * If the server is listening on a pipe or UNIX domain socket, the name is
+ * returned as a string.
+ *
+ * @return {(Object|String|null)} The address of the server
+ * @public
+ */
+ address () {
+ if (this.options.noServer) {
+ throw new Error('The server is operating in "noServer" mode');
+ }
+
+ if (!this._server) return null;
+ return this._server.address();
+ }
+
+ /**
+ * 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._removeListeners();
+ this._removeListeners = 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', socketOnError);
+
+ const version = +req.headers['sec-websocket-version'];
+ const extensions = {};
+
+ if (
+ req.method !== 'GET' || req.headers.upgrade.toLowerCase() !== 'websocket' ||
+ !req.headers['sec-websocket-key'] || (version !== 8 && version !== 13) ||
+ !this.shouldHandle(req)
+ ) {
+ return abortHandshake(socket, 400);
+ }
+
+ if (this.options.perMessageDeflate) {
+ const perMessageDeflate = new PerMessageDeflate(
+ this.options.perMessageDeflate,
+ true,
+ this.options.maxPayload
+ );
+
+ try {
+ const offers = extension.parse(
+ req.headers['sec-websocket-extensions']
+ );
+
+ if (offers[PerMessageDeflate.extensionName]) {
+ perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);
+ extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
+ }
+ } catch (err) {
+ return abortHandshake(socket, 400);
+ }
+ }
+
+ //
+ // 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, headers) => {
+ if (!verified) {
+ return abortHandshake(socket, code || 401, message, headers);
+ }
+
+ this.completeUpgrade(extensions, req, socket, head, cb);
+ });
+ return;
+ }
+
+ if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);
+ }
+
+ this.completeUpgrade(extensions, req, socket, head, cb);
+ }
+
+ /**
+ * Upgrade the connection to WebSocket.
+ *
+ * @param {Object} extensions The accepted extensions
+ * @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 (extensions, 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}`
+ ];
+
+ const ws = new WebSocket(null);
+ var protocol = req.headers['sec-websocket-protocol'];
+
+ if (protocol) {
+ protocol = protocol.trim().split(/ *, */);
+
+ //
+ // Optionally call external protocol selection handler.
+ //
+ if (this.options.handleProtocols) {
+ protocol = this.options.handleProtocols(protocol, req);
+ } else {
+ protocol = protocol[0];
+ }
+
+ if (protocol) {
+ headers.push(`Sec-WebSocket-Protocol: ${protocol}`);
+ ws.protocol = protocol;
+ }
+ }
+
+ if (extensions[PerMessageDeflate.extensionName]) {
+ const params = extensions[PerMessageDeflate.extensionName].params;
+ const value = extension.format({
+ [PerMessageDeflate.extensionName]: [params]
+ });
+ headers.push(`Sec-WebSocket-Extensions: ${value}`);
+ ws._extensions = extensions;
+ }
+
+ //
+ // Allow external modification/inspection of handshake headers.
+ //
+ this.emit('headers', headers, req);
+
+ socket.write(headers.concat('\r\n').join('\r\n'));
+ socket.removeListener('error', socketOnError);
+
+ ws.setSocket(socket, head, this.options.maxPayload);
+
+ if (this.clients) {
+ this.clients.add(ws);
+ ws.on('close', () => this.clients.delete(ws));
+ }
+
+ cb(ws);
+ }
+}
+
+module.exports = WebSocketServer;
+
+/**
+ * Add event listeners on an `EventEmitter` using a map of <event, listener>
+ * pairs.
+ *
+ * @param {EventEmitter} server The event emitter
+ * @param {Object.<String, Function>} map The listeners to add
+ * @return {Function} A function that will remove the added listeners when called
+ * @private
+ */
+function addListeners (server, map) {
+ for (const event of Object.keys(map)) server.on(event, map[event]);
+
+ return function removeListeners () {
+ for (const event of Object.keys(map)) {
+ server.removeListener(event, map[event]);
+ }
+ };
+}
+
+/**
+ * Handle premature socket errors.
+ *
+ * @private
+ */
+function socketOnError () {
+ this.destroy();
+}
+
+/**
+ * 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
+ * @param {Object} [headers] Additional HTTP response headers
+ * @private
+ */
+function abortHandshake (socket, code, message, headers) {
+ if (socket.writable) {
+ message = message || http.STATUS_CODES[code];
+ headers = Object.assign({
+ 'Connection': 'close',
+ 'Content-type': 'text/html',
+ 'Content-Length': Buffer.byteLength(message)
+ }, headers);
+
+ socket.write(
+ `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` +
+ Object.keys(headers).map(h => `${h}: ${headers[h]}`).join('\r\n') +
+ '\r\n\r\n' +
+ message
+ );
+ }
+
+ socket.removeListener('error', socketOnError);
+ socket.destroy();
+}
--- /dev/null
+'use strict';
+
+const EventEmitter = require('events');
+const crypto = require('crypto');
+const https = require('https');
+const http = require('http');
+const net = require('net');
+const tls = require('tls');
+const url = require('url');
+
+const PerMessageDeflate = require('./permessage-deflate');
+const EventTarget = require('./event-target');
+const extension = require('./extension');
+const constants = require('./constants');
+const Receiver = require('./receiver');
+const Sender = require('./sender');
+
+const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
+const kWebSocket = constants.kWebSocket;
+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|url.Url|url.URL)} address The URL to which to connect
+ * @param {(String|String[])} protocols The subprotocols
+ * @param {Object} options Connection options
+ */
+ constructor (address, protocols, options) {
+ super();
+
+ this.readyState = WebSocket.CONNECTING;
+ this.protocol = '';
+
+ this._binaryType = constants.BINARY_TYPES[0];
+ this._closeFrameReceived = false;
+ this._closeFrameSent = false;
+ this._closeMessage = '';
+ this._closeTimer = null;
+ this._closeCode = 1006;
+ this._extensions = {};
+ this._isServer = true;
+ this._receiver = null;
+ this._sender = null;
+ this._socket = null;
+
+ if (address !== null) {
+ if (Array.isArray(protocols)) {
+ protocols = protocols.join(', ');
+ } else if (typeof protocols === 'object' && protocols !== null) {
+ options = protocols;
+ protocols = undefined;
+ }
+
+ 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; }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * @type {Number}
+ */
+ get bufferedAmount () {
+ if (!this._socket) return 0;
+
+ //
+ // `socket.bufferSize` is `undefined` if the socket is closed.
+ //
+ return (this._socket.bufferSize || 0) + this._sender._bufferedBytes;
+ }
+
+ /**
+ * @type {String}
+ */
+ get extensions () {
+ return Object.keys(this._extensions).join();
+ }
+
+ /**
+ * 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
+ * @param {Number} maxPayload The maximum allowed message size
+ * @private
+ */
+ setSocket (socket, head, maxPayload) {
+ const receiver = new Receiver(
+ this._binaryType,
+ this._extensions,
+ maxPayload
+ );
+
+ this._sender = new Sender(socket, this._extensions);
+ this._receiver = receiver;
+ this._socket = socket;
+
+ receiver[kWebSocket] = this;
+ socket[kWebSocket] = this;
+
+ receiver.on('conclude', receiverOnConclude);
+ receiver.on('drain', receiverOnDrain);
+ receiver.on('error', receiverOnError);
+ receiver.on('message', receiverOnMessage);
+ receiver.on('ping', receiverOnPing);
+ receiver.on('pong', receiverOnPong);
+
+ socket.setTimeout(0);
+ socket.setNoDelay();
+
+ if (head.length > 0) socket.unshift(head);
+
+ socket.on('close', socketOnClose);
+ socket.on('data', socketOnData);
+ socket.on('end', socketOnEnd);
+ socket.on('error', socketOnError);
+
+ this.readyState = WebSocket.OPEN;
+ this.emit('open');
+ }
+
+ /**
+ * Emit the `'close'` event.
+ *
+ * @private
+ */
+ emitClose () {
+ this.readyState = WebSocket.CLOSED;
+
+ if (!this._socket) {
+ this.emit('close', this._closeCode, this._closeMessage);
+ return;
+ }
+
+ if (this._extensions[PerMessageDeflate.extensionName]) {
+ this._extensions[PerMessageDeflate.extensionName].cleanup();
+ }
+
+ this._receiver.removeAllListeners();
+ this.emit('close', this._closeCode, this._closeMessage);
+ }
+
+ /**
+ * Start a closing handshake.
+ *
+ * +----------+ +-----------+ +----------+
+ * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -
+ * | +----------+ +-----------+ +----------+ |
+ * +----------+ +-----------+ |
+ * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING
+ * +----------+ +-----------+ |
+ * | | | +---+ |
+ * +------------------------+-->|fin| - - - -
+ * | +---+ | +---+
+ * - - - - -|fin|<---------------------+
+ * +---+
+ *
+ * @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) {
+ const msg = 'WebSocket was closed before the connection was established';
+ return abortHandshake(this, this._req, msg);
+ }
+
+ if (this.readyState === WebSocket.CLOSING) {
+ if (this._closeFrameSent && this._closeFrameReceived) this._socket.end();
+ return;
+ }
+
+ this.readyState = WebSocket.CLOSING;
+ this._sender.close(code, data, !this._isServer, (err) => {
+ //
+ // This error is handled by the `'error'` listener on the socket. We only
+ // want to know if the close frame has been sent here.
+ //
+ if (err) return;
+
+ this._closeFrameSent = true;
+
+ if (this._socket.writable) {
+ if (this._closeFrameReceived) this._socket.end();
+
+ //
+ // Ensure that the connection is closed even if the closing handshake
+ // fails.
+ //
+ this._closeTimer = setTimeout(
+ this._socket.destroy.bind(this._socket),
+ closeTimeout
+ );
+ }
+ });
+ }
+
+ /**
+ * Send a ping.
+ *
+ * @param {*} data The data to send
+ * @param {Boolean} mask Indicates whether or not to mask `data`
+ * @param {Function} cb Callback which is executed when the ping is sent
+ * @public
+ */
+ ping (data, mask, cb) {
+ if (typeof data === 'function') {
+ cb = data;
+ data = mask = undefined;
+ } else if (typeof mask === 'function') {
+ cb = mask;
+ mask = undefined;
+ }
+
+ if (this.readyState !== WebSocket.OPEN) {
+ const err = new Error(
+ `WebSocket is not open: readyState ${this.readyState} ` +
+ `(${readyStates[this.readyState]})`
+ );
+
+ if (cb) return cb(err);
+ throw err;
+ }
+
+ if (typeof data === 'number') data = data.toString();
+ if (mask === undefined) mask = !this._isServer;
+ this._sender.ping(data || constants.EMPTY_BUFFER, mask, cb);
+ }
+
+ /**
+ * Send a pong.
+ *
+ * @param {*} data The data to send
+ * @param {Boolean} mask Indicates whether or not to mask `data`
+ * @param {Function} cb Callback which is executed when the pong is sent
+ * @public
+ */
+ pong (data, mask, cb) {
+ if (typeof data === 'function') {
+ cb = data;
+ data = mask = undefined;
+ } else if (typeof mask === 'function') {
+ cb = mask;
+ mask = undefined;
+ }
+
+ if (this.readyState !== WebSocket.OPEN) {
+ const err = new Error(
+ `WebSocket is not open: readyState ${this.readyState} ` +
+ `(${readyStates[this.readyState]})`
+ );
+
+ if (cb) return cb(err);
+ throw err;
+ }
+
+ if (typeof data === 'number') data = data.toString();
+ if (mask === undefined) mask = !this._isServer;
+ this._sender.pong(data || constants.EMPTY_BUFFER, mask, cb);
+ }
+
+ /**
+ * 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) {
+ const err = new Error(
+ `WebSocket is not open: readyState ${this.readyState} ` +
+ `(${readyStates[this.readyState]})`
+ );
+
+ if (cb) return cb(err);
+ throw err;
+ }
+
+ 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) {
+ const msg = 'WebSocket was closed before the connection was established';
+ return abortHandshake(this, this._req, msg);
+ }
+
+ if (this._socket) {
+ this.readyState = WebSocket.CLOSING;
+ this._socket.destroy();
+ }
+ }
+}
+
+readyStates.forEach((readyState, i) => {
+ WebSocket[readyStates[i]] = i;
+});
+
+//
+// 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 client.
+ *
+ * @param {(String|url.Url|url.URL)} address The URL to which to connect
+ * @param {String} protocols The subprotocols
+ * @param {Object} options Connection options
+ * @param {(Boolean|Object)} options.perMessageDeflate Enable/disable permessage-deflate
+ * @param {Number} options.handshakeTimeout Timeout in milliseconds for the handshake request
+ * @param {Number} options.protocolVersion Value of the `Sec-WebSocket-Version` header
+ * @param {String} options.origin Value of the `Origin` or `Sec-WebSocket-Origin` header
+ * @private
+ */
+function initAsClient (address, protocols, options) {
+ options = Object.assign({
+ protocolVersion: protocolVersions[1],
+ perMessageDeflate: true
+ }, options, {
+ createConnection: undefined,
+ socketPath: undefined,
+ hostname: undefined,
+ protocol: undefined,
+ timeout: undefined,
+ method: undefined,
+ auth: undefined,
+ host: undefined,
+ path: undefined,
+ port: undefined
+ });
+
+ if (protocolVersions.indexOf(options.protocolVersion) === -1) {
+ throw new RangeError(
+ `Unsupported protocol version: ${options.protocolVersion} ` +
+ `(supported versions: ${protocolVersions.join(', ')})`
+ );
+ }
+
+ this._isServer = false;
+
+ var parsedUrl;
+
+ if (typeof address === 'object' && address.href !== undefined) {
+ parsedUrl = address;
+ this.url = address.href;
+ } else {
+ parsedUrl = url.parse(address);
+ this.url = address;
+ }
+
+ const isUnixSocket = parsedUrl.protocol === 'ws+unix:';
+
+ if (!parsedUrl.host && (!isUnixSocket || !parsedUrl.pathname)) {
+ throw new Error(`Invalid URL: ${this.url}`);
+ }
+
+ const isSecure = parsedUrl.protocol === 'wss:' || parsedUrl.protocol === 'https:';
+ const key = crypto.randomBytes(16).toString('base64');
+ const httpObj = isSecure ? https : http;
+ const path = parsedUrl.search
+ ? `${parsedUrl.pathname || '/'}${parsedUrl.search}`
+ : parsedUrl.pathname || '/';
+ var perMessageDeflate;
+
+ options.createConnection = isSecure ? tlsConnect : netConnect;
+ options.port = parsedUrl.port || (isSecure ? 443 : 80);
+ options.host = parsedUrl.hostname.startsWith('[')
+ ? parsedUrl.hostname.slice(1, -1)
+ : parsedUrl.hostname;
+ options.headers = Object.assign({
+ 'Sec-WebSocket-Version': options.protocolVersion,
+ 'Sec-WebSocket-Key': key,
+ 'Connection': 'Upgrade',
+ 'Upgrade': 'websocket'
+ }, options.headers);
+ options.path = path;
+
+ if (options.perMessageDeflate) {
+ perMessageDeflate = new PerMessageDeflate(
+ options.perMessageDeflate !== true ? options.perMessageDeflate : {},
+ false
+ );
+ options.headers['Sec-WebSocket-Extensions'] = extension.format({
+ [PerMessageDeflate.extensionName]: perMessageDeflate.offer()
+ });
+ }
+ if (protocols) {
+ options.headers['Sec-WebSocket-Protocol'] = protocols;
+ }
+ if (options.origin) {
+ if (options.protocolVersion < 13) {
+ options.headers['Sec-WebSocket-Origin'] = options.origin;
+ } else {
+ options.headers.Origin = options.origin;
+ }
+ }
+ if (parsedUrl.auth) {
+ options.auth = parsedUrl.auth;
+ } else if (parsedUrl.username || parsedUrl.password) {
+ options.auth = `${parsedUrl.username}:${parsedUrl.password}`;
+ }
+
+ if (isUnixSocket) {
+ const parts = path.split(':');
+
+ if (options.agent == null && process.versions.modules < 57) {
+ //
+ // Setting `socketPath` in conjunction with `createConnection` without an
+ // agent throws an error on Node.js < 8. Work around the issue by using a
+ // different property.
+ //
+ options._socketPath = parts[0];
+ } else {
+ options.socketPath = parts[0];
+ }
+
+ options.path = parts[1];
+ }
+
+ var req = this._req = httpObj.get(options);
+
+ if (options.handshakeTimeout) {
+ req.setTimeout(
+ options.handshakeTimeout,
+ () => abortHandshake(this, req, 'Opening handshake has timed out')
+ );
+ }
+
+ req.on('error', (err) => {
+ if (this._req.aborted) return;
+
+ req = this._req = null;
+ this.readyState = WebSocket.CLOSING;
+ this.emit('error', err);
+ this.emitClose();
+ });
+
+ req.on('response', (res) => {
+ if (this.emit('unexpected-response', req, res)) return;
+
+ abortHandshake(this, req, `Unexpected server response: ${res.statusCode}`);
+ });
+
+ req.on('upgrade', (res, socket, head) => {
+ this.emit('upgrade', res);
+
+ //
+ // The user may have closed the connection from a listener of the `upgrade`
+ // event.
+ //
+ if (this.readyState !== WebSocket.CONNECTING) return;
+
+ req = this._req = null;
+
+ const digest = crypto.createHash('sha1')
+ .update(key + constants.GUID, 'binary')
+ .digest('base64');
+
+ if (res.headers['sec-websocket-accept'] !== digest) {
+ abortHandshake(this, socket, 'Invalid Sec-WebSocket-Accept header');
+ return;
+ }
+
+ const serverProt = res.headers['sec-websocket-protocol'];
+ const protList = (protocols || '').split(/, */);
+ var protError;
+
+ if (!protocols && serverProt) {
+ protError = 'Server sent a subprotocol but none was requested';
+ } else if (protocols && !serverProt) {
+ protError = 'Server sent no subprotocol';
+ } else if (serverProt && protList.indexOf(serverProt) === -1) {
+ protError = 'Server sent an invalid subprotocol';
+ }
+
+ if (protError) {
+ abortHandshake(this, socket, protError);
+ return;
+ }
+
+ if (serverProt) this.protocol = serverProt;
+
+ if (perMessageDeflate) {
+ try {
+ const extensions = extension.parse(
+ res.headers['sec-websocket-extensions']
+ );
+
+ if (extensions[PerMessageDeflate.extensionName]) {
+ perMessageDeflate.accept(
+ extensions[PerMessageDeflate.extensionName]
+ );
+ this._extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
+ }
+ } catch (err) {
+ abortHandshake(this, socket, 'Invalid Sec-WebSocket-Extensions header');
+ return;
+ }
+ }
+
+ this.setSocket(socket, head, 0);
+ });
+}
+
+/**
+ * Create a `net.Socket` and initiate a connection.
+ *
+ * @param {Object} options Connection options
+ * @return {net.Socket} The newly created socket used to start the connection
+ * @private
+ */
+function netConnect (options) {
+ options.path = options.socketPath || options._socketPath || undefined;
+ return net.connect(options);
+}
+
+/**
+ * Create a `tls.TLSSocket` and initiate a connection.
+ *
+ * @param {Object} options Connection options
+ * @return {tls.TLSSocket} The newly created socket used to start the connection
+ * @private
+ */
+function tlsConnect (options) {
+ options.path = options.socketPath || options._socketPath || undefined;
+ options.servername = options.servername || options.host;
+ return tls.connect(options);
+}
+
+/**
+ * Abort the handshake and emit an error.
+ *
+ * @param {WebSocket} websocket The WebSocket instance
+ * @param {(http.ClientRequest|net.Socket)} stream The request to abort or the
+ * socket to destroy
+ * @param {String} message The error message
+ * @private
+ */
+function abortHandshake (websocket, stream, message) {
+ websocket.readyState = WebSocket.CLOSING;
+
+ const err = new Error(message);
+ Error.captureStackTrace(err, abortHandshake);
+
+ if (stream.setHeader) {
+ stream.abort();
+ stream.once('abort', websocket.emitClose.bind(websocket));
+ websocket.emit('error', err);
+ } else {
+ stream.destroy(err);
+ stream.once('error', websocket.emit.bind(websocket, 'error'));
+ stream.once('close', websocket.emitClose.bind(websocket));
+ }
+}
+
+/**
+ * The listener of the `Receiver` `'conclude'` event.
+ *
+ * @param {Number} code The status code
+ * @param {String} reason The reason for closing
+ * @private
+ */
+function receiverOnConclude (code, reason) {
+ const websocket = this[kWebSocket];
+
+ websocket._socket.removeListener('data', socketOnData);
+ websocket._socket.resume();
+
+ websocket._closeFrameReceived = true;
+ websocket._closeMessage = reason;
+ websocket._closeCode = code;
+
+ if (code === 1005) websocket.close();
+ else websocket.close(code, reason);
+}
+
+/**
+ * The listener of the `Receiver` `'drain'` event.
+ *
+ * @private
+ */
+function receiverOnDrain () {
+ this[kWebSocket]._socket.resume();
+}
+
+/**
+ * The listener of the `Receiver` `'error'` event.
+ *
+ * @param {(RangeError|Error)} err The emitted error
+ * @private
+ */
+function receiverOnError (err) {
+ const websocket = this[kWebSocket];
+
+ websocket._socket.removeListener('data', socketOnData);
+
+ websocket.readyState = WebSocket.CLOSING;
+ websocket._closeCode = err[constants.kStatusCode];
+ websocket.emit('error', err);
+ websocket._socket.destroy();
+}
+
+/**
+ * The listener of the `Receiver` `'finish'` event.
+ *
+ * @private
+ */
+function receiverOnFinish () {
+ this[kWebSocket].emitClose();
+}
+
+/**
+ * The listener of the `Receiver` `'message'` event.
+ *
+ * @param {(String|Buffer|ArrayBuffer|Buffer[])} data The message
+ * @private
+ */
+function receiverOnMessage (data) {
+ this[kWebSocket].emit('message', data);
+}
+
+/**
+ * The listener of the `Receiver` `'ping'` event.
+ *
+ * @param {Buffer} data The data included in the ping frame
+ * @private
+ */
+function receiverOnPing (data) {
+ const websocket = this[kWebSocket];
+
+ websocket.pong(data, !websocket._isServer, constants.NOOP);
+ websocket.emit('ping', data);
+}
+
+/**
+ * The listener of the `Receiver` `'pong'` event.
+ *
+ * @param {Buffer} data The data included in the pong frame
+ * @private
+ */
+function receiverOnPong (data) {
+ this[kWebSocket].emit('pong', data);
+}
+
+/**
+ * The listener of the `net.Socket` `'close'` event.
+ *
+ * @private
+ */
+function socketOnClose () {
+ const websocket = this[kWebSocket];
+
+ this.removeListener('close', socketOnClose);
+ this.removeListener('end', socketOnEnd);
+
+ websocket.readyState = WebSocket.CLOSING;
+
+ //
+ // The close frame might not have been received or the `'end'` event emitted,
+ // for example, if the socket was destroyed due to an error. Ensure that the
+ // `receiver` stream is closed after writing any remaining buffered data to
+ // it. If the readable side of the socket is in flowing mode then there is no
+ // buffered data as everything has been already written and `readable.read()`
+ // will return `null`. If instead, the socket is paused, any possible buffered
+ // data will be read as a single chunk and emitted synchronously in a single
+ // `'data'` event.
+ //
+ websocket._socket.read();
+ websocket._receiver.end();
+
+ this.removeListener('data', socketOnData);
+ this[kWebSocket] = undefined;
+
+ clearTimeout(websocket._closeTimer);
+
+ if (
+ websocket._receiver._writableState.finished ||
+ websocket._receiver._writableState.errorEmitted
+ ) {
+ websocket.emitClose();
+ } else {
+ websocket._receiver.on('error', receiverOnFinish);
+ websocket._receiver.on('finish', receiverOnFinish);
+ }
+}
+
+/**
+ * The listener of the `net.Socket` `'data'` event.
+ *
+ * @param {Buffer} chunk A chunk of data
+ * @private
+ */
+function socketOnData (chunk) {
+ if (!this[kWebSocket]._receiver.write(chunk)) {
+ this.pause();
+ }
+}
+
+/**
+ * The listener of the `net.Socket` `'end'` event.
+ *
+ * @private
+ */
+function socketOnEnd () {
+ const websocket = this[kWebSocket];
+
+ websocket.readyState = WebSocket.CLOSING;
+ websocket._receiver.end();
+ this.end();
+}
+
+/**
+ * The listener of the `net.Socket` `'error'` event.
+ *
+ * @private
+ */
+function socketOnError () {
+ const websocket = this[kWebSocket];
+
+ this.removeListener('error', socketOnError);
+ this.on('error', constants.NOOP);
+
+ if (websocket) {
+ websocket.readyState = WebSocket.CLOSING;
+ this.destroy();
+ }
+}
--- /dev/null
+coverage
+.nyc_output
\ No newline at end of file
--- /dev/null
+{
+ "check-coverage": false,
+ "lines": 99,
+ "statements": 99,
+ "functions": 99,
+ "branches": 99,
+ "include": [
+ "index.js"
+ ]
+}
\ No newline at end of file
--- /dev/null
+language: node_js
+node_js:
+ - "6"
+ - "8"
+ - "10"
+ - "node"
+script: npm run travis
+cache:
+ yarn: true
--- /dev/null
+The MIT License (MIT)
+Copyright (c) 2017 Samuel Reed <samuel.trace.reed@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.
--- /dev/null
+'use strict';
+
+function Queue(options) {
+ if (!(this instanceof Queue)) {
+ return new Queue(options);
+ }
+
+ options = options || {};
+ this.concurrency = options.concurrency || Infinity;
+ this.pending = 0;
+ this.jobs = [];
+ this.cbs = [];
+ this._done = done.bind(this);
+}
+
+var arrayAddMethods = [
+ 'push',
+ 'unshift',
+ 'splice'
+];
+
+arrayAddMethods.forEach(function(method) {
+ Queue.prototype[method] = function() {
+ var methodResult = Array.prototype[method].apply(this.jobs, arguments);
+ this._run();
+ return methodResult;
+ };
+});
+
+Object.defineProperty(Queue.prototype, 'length', {
+ get: function() {
+ return this.pending + this.jobs.length;
+ }
+});
+
+Queue.prototype._run = function() {
+ if (this.pending === this.concurrency) {
+ return;
+ }
+ if (this.jobs.length) {
+ var job = this.jobs.shift();
+ this.pending++;
+ job(this._done);
+ this._run();
+ }
+
+ if (this.pending === 0) {
+ while (this.cbs.length !== 0) {
+ var cb = this.cbs.pop();
+ process.nextTick(cb);
+ }
+ }
+};
+
+Queue.prototype.onDone = function(cb) {
+ if (typeof cb === 'function') {
+ this.cbs.push(cb);
+ this._run();
+ }
+};
+
+function done() {
+ this.pending--;
+ this._run();
+}
+
+module.exports = Queue;
--- /dev/null
+{
+ "name": "async-limiter",
+ "version": "1.0.1",
+ "description": "asynchronous function queue with adjustable concurrency",
+ "keywords": [
+ "throttle",
+ "async",
+ "limiter",
+ "asynchronous",
+ "job",
+ "task",
+ "concurrency",
+ "concurrent"
+ ],
+ "dependencies": {},
+ "devDependencies": {
+ "coveralls": "^3.0.3",
+ "eslint": "^5.16.0",
+ "eslint-plugin-mocha": "^5.3.0",
+ "intelli-espower-loader": "^1.0.1",
+ "mocha": "^6.1.4",
+ "nyc": "^14.1.1",
+ "power-assert": "^1.6.1"
+ },
+ "scripts": {
+ "test": "mocha --require intelli-espower-loader test/",
+ "travis": "npm run lint && npm run test",
+ "coverage": "nyc npm test && nyc report --reporter=text-lcov | coveralls",
+ "example": "node example",
+ "lint": "eslint ."
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/strml/async-limiter.git"
+ },
+ "author": {
+ "name": "Samuel Reed"
+ },
+ "license": "MIT",
+ "gitHead": "f3bb66f26e69a5747a6483e32c775a02632020ee",
+ "bugs": {
+ "url": "https://github.com/strml/async-limiter/issues"
+ },
+ "homepage": "https://github.com/strml/async-limiter#readme",
+ "_id": "async-limiter@1.0.1",
+ "_nodeVersion": "10.16.0",
+ "_npmVersion": "6.9.0",
+ "dist": {
+ "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
+ "shasum": "dd379e94f0db8310b08291f9d64c3209766617fd",
+ "tarball": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
+ "fileCount": 7,
+ "unpackedSize": 6900,
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJdRFo5CRA9TVsSAnZWagAAE8EP/AoamQTvsA8uUcSUKc4L\nL7rKbbH4m5Cv1Z7qeBXLV3KJHI+dhn/mKU2hOpnXHgks5Az4ELlOX9O1vo9j\nLYtN8ZMGEkMIx+k7OcVexaXLcK9ALliEMNoNy4cIVc+exBS4eKFPmaEx5DmD\nNf+eCG6jkA9WY/kYSmFnus7C0B7d2PMdmtBZKdzWya9PAB5BYEoz3/GYhJZG\nEFYHmWKtMDB6LMSZ0FSXwABV6QXWn5kk3fXaPX1NtMHLw+QCT/sWt+0cOnIE\nak2s8WOry7Fsx5wXQmKbd8854LC+yVT1f7RR7eBhKAlTk74nwfNDr84UBJIr\n+0G0RdgISOzLghtRFu3SqYKynXTjdlycZG9vvcHW9oPGI2ZiC2cHuiqc4+K7\ndYX1HGQICjflTmb+RR0vGNXiy3v6YBWgpItdeziPO2K+0uN6SJr1BidQ8oKI\nd49psu/xNvMhdwOo19+/Bt7n7nT4uzej8K7uQO81BJC0ITeNfaC/z9M/4VOg\nFuixwvvzfs+/RABxzXKZqOMVlAnAb4U/PBcliklyUBeZ62PDkqnBxdrOekf5\nacstUU3K5bAaBV8taKHEa1+tqYUjVEcaolDDKgmO0dxD9FlKAMlhck9ildO7\nnjODiNgcSMUlMmHGUZCEvjSt1YptntzC0DHwxWUjszaR4p0Iz0c0AyOYGH7T\nRewy\r\n=MPQY\r\n-----END PGP SIGNATURE-----\r\n"
+ },
+ "maintainers": [
+ {
+ "name": "strml",
+ "email": "samuel.trace.reed@gmail.com"
+ }
+ ],
+ "_npmUser": {
+ "name": "strml",
+ "email": "samuel.trace.reed@gmail.com"
+ },
+ "directories": {},
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/async-limiter_1.0.1_1564760633070_0.6974331182093105"
+ },
+ "_hasShrinkwrap": false,
+ "_shasum": "dd379e94f0db8310b08291f9d64c3209766617fd",
+ "_from": "async-limiter@~1.0.0",
+ "_resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz"
+}
--- /dev/null
+# Async-Limiter
+
+A module for limiting concurrent asynchronous actions in flight. Forked from [queue](https://github.com/jessetane/queue).
+
+[![npm](http://img.shields.io/npm/v/async-limiter.svg?style=flat-square)](http://www.npmjs.org/async-limiter)
+[![tests](https://img.shields.io/travis/STRML/async-limiter.svg?style=flat-square&branch=master)](https://travis-ci.org/STRML/async-limiter)
+[![coverage](https://img.shields.io/coveralls/STRML/async-limiter.svg?style=flat-square&branch=master)](https://coveralls.io/r/STRML/async-limiter)
+
+This module exports a class `Limiter` that implements some of the `Array` API.
+Pass async functions (ones that accept a callback or return a promise) to an instance's additive array methods.
+
+## Motivation
+
+Certain functions, like `zlib`, have [undesirable behavior](https://github.com/nodejs/node/issues/8871#issuecomment-250915913) when
+run at infinite concurrency.
+
+In this case, it is actually faster, and takes far less memory, to limit concurrency.
+
+This module should do the absolute minimum work necessary to queue up functions. PRs are welcome that would
+make this module faster or lighter, but new functionality is not desired.
+
+Style should confirm to nodejs/node style.
+
+## Example
+
+``` javascript
+var Limiter = require('async-limiter')
+
+var t = new Limiter({concurrency: 2});
+var results = []
+
+// add jobs using the familiar Array API
+t.push(function (cb) {
+ results.push('two')
+ cb()
+})
+
+t.push(
+ function (cb) {
+ results.push('four')
+ cb()
+ },
+ function (cb) {
+ results.push('five')
+ cb()
+ }
+)
+
+t.unshift(function (cb) {
+ results.push('one')
+ cb()
+})
+
+t.splice(2, 0, function (cb) {
+ results.push('three')
+ cb()
+})
+
+// Jobs run automatically. If you want a callback when all are done,
+// call 'onDone()'.
+t.onDone(function () {
+ console.log('all done:', results)
+})
+```
+
+## Zlib Example
+
+```js
+const zlib = require('zlib');
+const Limiter = require('async-limiter');
+
+const message = {some: "data"};
+const payload = new Buffer(JSON.stringify(message));
+
+// Try with different concurrency values to see how this actually
+// slows significantly with higher concurrency!
+//
+// 5: 1398.607ms
+// 10: 1375.668ms
+// Infinity: 4423.300ms
+//
+const t = new Limiter({concurrency: 5});
+function deflate(payload, cb) {
+ t.push(function(done) {
+ zlib.deflate(payload, function(err, buffer) {
+ done();
+ cb(err, buffer);
+ });
+ });
+}
+
+console.time('deflate');
+for(let i = 0; i < 30000; ++i) {
+ deflate(payload, function (err, buffer) {});
+}
+t.onDone(function() {
+ console.timeEnd('deflate');
+});
+```
+
+## Install
+
+`npm install async-limiter`
+
+## Test
+
+`npm test`
+
+## API
+
+### `var t = new Limiter([opts])`
+Constructor. `opts` may contain inital values for:
+* `t.concurrency`
+
+## Instance methods
+
+### `t.onDone(fn)`
+`fn` will be called once and only once, when the queue is empty.
+
+## Instance methods mixed in from `Array`
+Mozilla has docs on how these methods work [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array).
+### `t.push(element1, ..., elementN)`
+### `t.unshift(element1, ..., elementN)`
+### `t.splice(index , howMany[, element1[, ...[, elementN]]])`
+
+## Properties
+### `t.concurrency`
+Max number of jobs the queue should process concurrently, defaults to `Infinity`.
+
+### `t.length`
+Jobs pending + jobs to process (readonly).
+
--- /dev/null
+{
+ "name": "ws",
+ "version": "5.2.2",
+ "description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
+ "keywords": [
+ "HyBi",
+ "Push",
+ "RFC-6455",
+ "WebSocket",
+ "WebSockets",
+ "real-time"
+ ],
+ "homepage": "https://github.com/websockets/ws",
+ "bugs": {
+ "url": "https://github.com/websockets/ws/issues"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/websockets/ws.git"
+ },
+ "author": {
+ "name": "Einar Otto Stangvik",
+ "email": "einaros@gmail.com",
+ "url": "http://2x.io"
+ },
+ "license": "MIT",
+ "main": "index.js",
+ "files": [
+ "index.js",
+ "lib"
+ ],
+ "scripts": {
+ "test": "eslint . && nyc --reporter=html --reporter=text mocha test/*.test.js",
+ "integration": "eslint . && mocha test/*.integration.js",
+ "lint": "eslint ."
+ },
+ "dependencies": {
+ "async-limiter": "~1.0.0"
+ },
+ "devDependencies": {
+ "benchmark": "~2.1.2",
+ "bufferutil": "~3.0.0",
+ "eslint": "~4.19.0",
+ "eslint-config-standard": "~11.0.0",
+ "eslint-plugin-import": "~2.12.0",
+ "eslint-plugin-node": "~6.0.0",
+ "eslint-plugin-promise": "~3.8.0",
+ "eslint-plugin-standard": "~3.0.0",
+ "mocha": "~5.2.0",
+ "nyc": "~12.0.2",
+ "utf-8-validate": "~4.0.0"
+ },
+ "gitHead": "5d55e52529167c25f4fec35cb4753294e75bf9f2",
+ "_id": "ws@5.2.2",
+ "_npmVersion": "6.1.0",
+ "_nodeVersion": "10.6.0",
+ "_npmUser": {
+ "name": "lpinca",
+ "email": "luigipinca@gmail.com"
+ },
+ "dist": {
+ "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==",
+ "shasum": "dffef14866b8e8dc9133582514d1befaf96e980f",
+ "tarball": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz",
+ "fileCount": 14,
+ "unpackedSize": 99219,
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbRmFaCRA9TVsSAnZWagAAZH0P/iB0EIYIHqFAJznwT4el\n8xU2FN/na7yK3k+nV0cNYD+gKdOcTphij2IJGnQBM8hG4SlPBf+NBqy7/VBo\na3cmV3Rat395nmI3lhTgb9EDMFgYRQty3ORS3KAf2KEpFFA4QlTjOttjYsCq\nZN/j3GMnsnH47RxToPE9wTyC8d+cgIfdQHLN1k+5YaN5OtBCyKIXGbl+QJli\n2YLGAU1mp+yM+CF8CV+q6aodokoF/89D8LnJ7N5LjIgYGHTohB9c/fY/7v/5\nQLqd35RTo8OXMfiujUy2EhyGP5SyiTUzttAmXuSOxG3KQTtzss0dHMBxFeXJ\nO6ZDh124WW1VJYhdPKwfaHwszfmB6a95K2Gmu7xtvlq48qMq6Rfi9WQ1/rlc\nYyeyXAX1a/ykbEza4mm9oPfZpkPKSYM4s4fYufxyG3sAz3vKaOy4MQNA6gOC\n49sJBGT7kdTlPgHuE832t9T+J8ByCGNl/o2zJDDYLq6RLZqtgaSqAWtIBaFe\neW/yEVklhm2InF8e1yAiHg4au/6OKf4PFfKpcjdKvDbMZO8fFm6VDRYqFlI5\nnF2XzxK7p86sIe+YeFqVAzc4kMGcvYzrD7RhA25n+NBbjHaYChCLibgEDG7E\n2gqUv1T9BU2ihq845gapZ9h1b7/dpfqOKZCf5kvMxZLjp/rL8msRRPd4GIw9\nPXXp\r\n=QnaD\r\n-----END PGP SIGNATURE-----\r\n"
+ },
+ "maintainers": [
+ {
+ "email": "npm@3rd-Eden.com",
+ "name": "3rdeden"
+ },
+ {
+ "email": "einaros@gmail.com",
+ "name": "einaros"
+ },
+ {
+ "email": "luigipinca@gmail.com",
+ "name": "lpinca"
+ },
+ {
+ "email": "npm@3rd-Eden.com",
+ "name": "v1"
+ }
+ ],
+ "directories": {},
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/ws_5.2.2_1531339098131_0.05866997625683701"
+ },
+ "_hasShrinkwrap": false,
+ "_shasum": "dffef14866b8e8dc9133582514d1befaf96e980f",
+ "_from": "ws@~5.2.0",
+ "_resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz"
+}
--- /dev/null
+{
+ "name": "wscat",
+ "version": "2.2.1",
+ "description": "WebSocket cat",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"No test specified\""
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/websockets/wscat.git"
+ },
+ "keywords": [
+ "wscat",
+ "websocket",
+ "cat"
+ ],
+ "author": {
+ "name": "Arnout Kazemier, Einar Otto Stangvik"
+ },
+ "license": "MIT",
+ "dependencies": {
+ "commander": "~2.15.0",
+ "read": "~1.0.7",
+ "ws": "~5.2.0"
+ },
+ "bin": {
+ "wscat": "./bin/wscat"
+ },
+ "gitHead": "60a2e9b1f8fbc8517ac6f787989026891f271cf6",
+ "bugs": {
+ "url": "https://github.com/websockets/wscat/issues"
+ },
+ "homepage": "https://github.com/websockets/wscat#readme",
+ "_id": "wscat@2.2.1",
+ "_npmVersion": "6.1.0",
+ "_nodeVersion": "10.4.1",
+ "_npmUser": {
+ "name": "lpinca",
+ "email": "luigipinca@gmail.com"
+ },
+ "dist": {
+ "integrity": "sha512-8/qT8dpCD8eKm7zS+AowXzwoC6887uhT1yWFGjQpQQXG5/7J+xO42kY/YKZoJT1t/AC3Vd4TxSssdN2+KzPdZg==",
+ "shasum": "c8640db425a1d6f021022af93dc1d4d1b019243c",
+ "tarball": "https://registry.npmjs.org/wscat/-/wscat-2.2.1.tgz",
+ "fileCount": 4,
+ "unpackedSize": 11216,
+ "npm-signature": "-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbKjpBCRA9TVsSAnZWagAAiYEP/RQHxrE8fxG+I0MMYq+N\n+dDvUQx2sV13zWPDQFvpEzO100C25UJXfowa3OqHZYAsz0FlyseEip+2w9HI\nz+N3cDLwG+5PMZv77f/kJB9cQTBOG+jlph69dwMsoUnYafbidv8RGnl6ZQ2f\nvEIKBvgmruuX6AXlQxyITag6IKrw1jMI5VXdQ0hmhSJXLN/GdUbPjsZEQxaS\nska9kDoqHFJBT/m1g7Q6JoGwoqNKVg521j+WYerB678CBGK7LSbs0ob/zYAT\njLumh3nElJ93WB0JaaaMYf7wJnLpndgO49K7DZJrxwJlAGU45AqxStlOypdC\n/Tr9h9XVriJ5mwlHEun1a708RJ4UGTWtaSjM3Np1V/K5e1BS3M/gFXcUJ0Wy\necDyDGmRh85nvqF0hXofigb1lasVqHMnz8qeYqclX0lEfjmOTqqSzmNV0783\n8bcb+WOLsW6sqASG1m4olwwMXHdx84koRjgaIIO65PRkuEw6RLp95NCf3Mg6\ntCoCY0HHr6v5nY73TOpZDrnkt5opFDwl7kfkGYGmNl7wqX76rNKkn2uzl6l6\nHjLXPvE4KQlS3eroBa6rOLSKAZ4izQZ8CWASqM3I5slHi5vUFrbjgNQtSfrC\nillBS4JkX0Zt3EWMGNv2ivrxpWbjajMFJbybqEsVIbKLIu87ZNJBHwcvVevE\nk2LK\r\n=cYEr\r\n-----END PGP SIGNATURE-----\r\n"
+ },
+ "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"
+ }
+ ],
+ "directories": {},
+ "_npmOperationalInternal": {
+ "host": "s3://npm-registry-packages",
+ "tmp": "tmp/wscat_2.2.1_1529494081648_0.8254234584505264"
+ },
+ "_shasum": "c8640db425a1d6f021022af93dc1d4d1b019243c",
+ "_from": "wscat@",
+ "_resolved": "https://registry.npmjs.org/wscat/-/wscat-2.2.1.tgz",
+ "readme": "ERROR: No README data found!"
+}
+++ /dev/null
-0 info it worked if it ends with ok
-1 verbose cli [ '/usr/bin/node', '/usr/bin/npm', 'start' ]
-2 info using npm@1.4.21
-3 info using node@v8.11.1
-4 verbose run-script [ 'prestart', 'start', 'poststart' ]
-5 info prestart web@1.0.0
-6 info start web@1.0.0
-7 verbose unsafe-perm in lifecycle true
-8 info web@1.0.0 Failed to exec start script
-9 error web@1.0.0 start: `node src/index.js`
-9 error Exit status 1
-10 error Failed at the web@1.0.0 start script.
-10 error This is most likely a problem with the web package,
-10 error not with npm itself.
-10 error Tell the author that this fails on your system:
-10 error node src/index.js
-10 error You can get their info via:
-10 error npm owner ls web
-10 error There is likely additional logging output above.
-11 error System Linux 4.19.57-v7+
-12 error command "/usr/bin/node" "/usr/bin/npm" "start"
-13 error cwd /home/pi/VSoRC
-14 error node -v v8.11.1
-15 error npm -v 1.4.21
-16 error code ELIFECYCLE
-17 verbose exit [ 1, true ]
});
});
+
+var WebSocketServer = require('websocket').server;
+var http = require('http');
+
+var server = http.createServer(function(request, response) {
+ // process HTTP request. Since we're writing just WebSockets
+ // server we don't have to implement anything.
+});
+server.listen(1337, function() { });
+
+// create the server
+wsServer = new WebSocketServer({
+ httpServer: server
+});
+
+// WebSocket server
+wsServer.on('request', function(request) {
+ var connection = request.accept(null, request.origin);
+ console.log('Se conecto '+request.origin);
+ // This is the most important callback for us, we'll handle
+ // all messages from users here.
+
+ connection.on('message', function(message) {
+ if (message.type === 'utf8') {
+ // process WebSocket message
+ console.log('Recibido');
+ console.log(message);
+ connection.sendUTF("hola");
+
+ }
+ });
+
+ connection.on('close', function(connection) {
+ // close user connection
+ });
+});
+
+
module.exports = router;
xhr.send();
}
-
function startvsorc() {
let xhr = new XMLHttpRequest();
xhr.open('GET', '/startvsorc', true);
xhr.onload = function() {
if (xhr.status == 200) { //can use this.status instead
//console.log(xhr.responseText);// para ver en la consola
- console.log("vsorc started");
+ console.log("vsorc startedd");
}
}
xhr.send();