!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.eve=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
|
|
exports.Agent = _dereq_('./lib/Agent');
|
|
exports.ServiceManager = _dereq_('./lib/ServiceManager');
|
|
exports.TransportManager = _dereq_('./lib/TransportManager');
|
|
|
|
exports.module = {
|
|
BabbleModule: _dereq_('./lib/module/BabbleModule'),
|
|
PatternModule: _dereq_('./lib/module/PatternModule'),
|
|
RequestModule: _dereq_('./lib/module/RequestModule'),
|
|
RPCModule: _dereq_('./lib/module/RPCModule')
|
|
};
|
|
|
|
exports.transport = {
|
|
Transport: _dereq_('./lib/transport/Transport'),
|
|
AMQPTransport: _dereq_('./lib/transport/amqp/AMQPTransport'),
|
|
DistribusTransport: _dereq_('./lib/transport/distribus/DistribusTransport'),
|
|
HTTPTransport: _dereq_('./lib/transport/http/HTTPTransport'),
|
|
LocalTransport: _dereq_('./lib/transport/local/LocalTransport'),
|
|
PubNubTransport: _dereq_('./lib/transport/pubnub/PubNubTransport'),
|
|
WebSocketTransport: _dereq_('./lib/transport/websocket/WebSocketTransport'),
|
|
|
|
connection: {
|
|
Connection: _dereq_('./lib/transport/Connection'),
|
|
AMQPConnection: _dereq_('./lib/transport/amqp/AMQPConnection'),
|
|
DistribusConnection: _dereq_('./lib/transport/distribus/DistribusConnection'),
|
|
HTTPConnection: _dereq_('./lib/transport/http/HTTPConnection'),
|
|
LocalConnection: _dereq_('./lib/transport/local/LocalConnection'),
|
|
PubNubConnection: _dereq_('./lib/transport/pubnub/PubNubConnection'),
|
|
WebSocketConnection: _dereq_('./lib/transport/websocket/WebSocketConnection')
|
|
}
|
|
};
|
|
|
|
exports.hypertimer = _dereq_('hypertimer');
|
|
exports.util = _dereq_('./lib/util');
|
|
|
|
// register all modules at the Agent
|
|
exports.Agent.registerModule(exports.module.BabbleModule);
|
|
exports.Agent.registerModule(exports.module.PatternModule);
|
|
exports.Agent.registerModule(exports.module.RequestModule);
|
|
exports.Agent.registerModule(exports.module.RPCModule);
|
|
|
|
// register all transports at the TransportManager
|
|
exports.TransportManager.registerType(exports.transport.AMQPTransport);
|
|
exports.TransportManager.registerType(exports.transport.DistribusTransport);
|
|
exports.TransportManager.registerType(exports.transport.HTTPTransport);
|
|
exports.TransportManager.registerType(exports.transport.LocalTransport);
|
|
exports.TransportManager.registerType(exports.transport.PubNubTransport);
|
|
exports.TransportManager.registerType(exports.transport.WebSocketTransport);
|
|
|
|
// load the default ServiceManager, a singleton, initialized with a LocalTransport
|
|
exports.system = new exports.ServiceManager();
|
|
exports.system.transports.add(new exports.transport.LocalTransport());
|
|
|
|
// override Agent.getTransportById in order to support Agent.connect(transportId)
|
|
exports.Agent.getTransportById = function (id) {
|
|
return exports.system.transports.get(id);
|
|
};
|
|
|
|
},{"./lib/Agent":2,"./lib/ServiceManager":3,"./lib/TransportManager":4,"./lib/module/BabbleModule":5,"./lib/module/PatternModule":6,"./lib/module/RPCModule":7,"./lib/module/RequestModule":8,"./lib/transport/Connection":9,"./lib/transport/Transport":10,"./lib/transport/amqp/AMQPConnection":11,"./lib/transport/amqp/AMQPTransport":12,"./lib/transport/distribus/DistribusConnection":13,"./lib/transport/distribus/DistribusTransport":14,"./lib/transport/http/HTTPConnection":15,"./lib/transport/http/HTTPTransport":16,"./lib/transport/local/LocalConnection":17,"./lib/transport/local/LocalTransport":18,"./lib/transport/pubnub/PubNubConnection":19,"./lib/transport/pubnub/PubNubTransport":20,"./lib/transport/websocket/WebSocketConnection":21,"./lib/transport/websocket/WebSocketTransport":22,"./lib/util":23,"hypertimer":110}],2:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Promise = _dereq_('promise');
|
|
var uuid = _dereq_('uuid-v4');
|
|
var util = _dereq_('./util');
|
|
|
|
/**
|
|
* Agent
|
|
* @param {string} [id] Id for the agent. If not provided, the agent
|
|
* will be given a uuid.
|
|
* @constructor
|
|
*/
|
|
function Agent (id) {
|
|
this.id = id ? id.toString() : uuid();
|
|
|
|
// a list with all connected transports
|
|
this.connections = [];
|
|
this.defaultConnection = null;
|
|
this.ready = Promise.resolve([]);
|
|
}
|
|
|
|
// an object with modules which can be used to extend the agent
|
|
Agent.modules = {};
|
|
|
|
/**
|
|
* Register a new type of module. This module can then be loaded via
|
|
* Agent.extend() and Agent.loadModule().
|
|
* @param {Function} constructor A module constructor
|
|
*/
|
|
Agent.registerModule = function (constructor) {
|
|
var type = constructor.prototype.type;
|
|
if (typeof constructor !== 'function') {
|
|
throw new Error('Constructor function expected');
|
|
}
|
|
if (!type) {
|
|
throw new Error('Field "prototype.type" missing in transport constructor');
|
|
}
|
|
if (type in Agent.modules) {
|
|
if (Agent.modules[type] !== constructor) {
|
|
throw new Error('Module of type "' + type + '" already exists');
|
|
}
|
|
}
|
|
|
|
Agent.modules[type] = constructor;
|
|
};
|
|
|
|
/**
|
|
* Get a transport by id.
|
|
* This static method can be overloaded for example by the get function of
|
|
* a singleton TransportManager.
|
|
* @param {string} id
|
|
* @return {Transport}
|
|
*/
|
|
Agent.getTransportById = function (id) {
|
|
throw new Error('Transport with id "' + id + '" not found');
|
|
};
|
|
|
|
/**
|
|
* Extend an agent with modules (mixins).
|
|
* The modules new functions are added to the Agent itself.
|
|
* See also function `loadModule`.
|
|
* @param {string | string[]} module A module name or an Array with module
|
|
* names. Available modules:
|
|
* 'pattern', 'request', 'babble'
|
|
* @param {Object} [options] Additional options for loading the module
|
|
* @return {Agent} Returns the agent itself
|
|
*/
|
|
Agent.prototype.extend = function (module, options) {
|
|
if (Array.isArray(module)) {
|
|
var modules = [].concat(module);
|
|
|
|
// order the modules such that 'pattern' comes first, this module must be
|
|
// loaded before other modules ('request' specifically)
|
|
modules.sort(function (a, b) {
|
|
if (a == 'pattern') return -1;
|
|
if (b == 'pattern') return 1;
|
|
return 0;
|
|
});
|
|
|
|
// an array with module names
|
|
for (var i = 0; i < modules.length; i++) {
|
|
this.extend(modules[i], options)
|
|
}
|
|
}
|
|
else {
|
|
// a single module name
|
|
var constructor = _getModuleConstructor(module);
|
|
var instance = new constructor(this, options);
|
|
var mixin = instance.mixin();
|
|
|
|
// check for conflicts in the modules mixin functions
|
|
var me = this;
|
|
Object.keys(mixin).forEach(function (name) {
|
|
if (me[name] !== undefined && name !== '_receive') {
|
|
throw new Error('Conflict: agent already has a property "' + prop + '"');
|
|
}
|
|
});
|
|
|
|
// extend the agent with all mixin functions provided by the module
|
|
Object.keys(mixin).forEach(function (name) {
|
|
me[name] = mixin[name];
|
|
});
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Load a module onto an agent.
|
|
* See also function `extend`.
|
|
* @param {string | string[]} module A module name or an Array with module
|
|
* names. Available modules:
|
|
* 'pattern', 'request', 'babble'
|
|
* @param {Object} [options] Additional options for loading the module
|
|
* @return {Object} Returns the created module
|
|
*/
|
|
Agent.prototype.loadModule = function (module, options) {
|
|
var _options = options !== undefined ? Object.create(options) : {};
|
|
_options.extend = false;
|
|
|
|
var constructor = _getModuleConstructor(module);
|
|
var instance = new constructor(this, options);
|
|
var mixin = instance.mixin();
|
|
|
|
// only replace the _receive function, do not add other mixin functions
|
|
this._receive = mixin._receive;
|
|
|
|
return instance;
|
|
};
|
|
|
|
/**
|
|
* Get a module constructor by it's name.
|
|
* Throws an error when the module is not found.
|
|
* @param {string} name
|
|
* @return {function} Returns the modules constructor function
|
|
* @private
|
|
*/
|
|
function _getModuleConstructor(name) {
|
|
var constructor = Agent.modules[name];
|
|
if (!constructor) {
|
|
throw new Error('Unknown module "' + name + '". ' +
|
|
'Choose from: ' + Object.keys(Agent.modules).map(JSON.stringify).join(', '));
|
|
}
|
|
return constructor;
|
|
}
|
|
|
|
/**
|
|
* Send a message to an agent
|
|
* @param {string} to
|
|
* to is either:
|
|
* - A string "agentId", the id of the recipient. Will be send
|
|
* via the default transport or when there is no default
|
|
* transport via the first connected transport.
|
|
* - A string "agentId@transportId" Only usable locally, not
|
|
* for sharing an address with remote agents.
|
|
* - A string "protocol://networkId/agentId". This is a sharable
|
|
* identifier for an agent.
|
|
* @param {*} message Message to be send
|
|
* @return {Promise} Returns a promise which resolves when the message as
|
|
* successfully been sent, or rejected when sending the
|
|
* message failed
|
|
*/
|
|
Agent.prototype.send = function(to, message) {
|
|
var colon = to.indexOf('://');
|
|
if (colon !== -1) {
|
|
// to is an url like "protocol://networkId/agentId"
|
|
var url = util.parseUrl(to);
|
|
if (url.protocol == 'http' || url.protocol == 'ws' || url.protocol == 'https') { // TODO: ugly fixed listing here...
|
|
return this._sendByProtocol(url.protocol, to, message);
|
|
}
|
|
else {
|
|
return this._sendByNetworkId(url.domain, url.path, message);
|
|
}
|
|
}
|
|
|
|
// TODO: deprecate this notation "agentId@transportId"?
|
|
var at = to.indexOf('@');
|
|
if (at != -1) {
|
|
// to is an id like "agentId@transportId"
|
|
var _to = to.substring(0, at);
|
|
var _transportId = to.substring(at + 1);
|
|
return this._sendByTransportId(_transportId, _to, message);
|
|
}
|
|
|
|
// to is an id like "agentId". Send via the default transport
|
|
var conn = this.defaultConnection;
|
|
if (conn) {
|
|
return conn.send(to, message);
|
|
}
|
|
else {
|
|
return Promise.reject(new Error('No transport found'));
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Send a transport to an agent given a networkId
|
|
* @param {string} networkId A network id
|
|
* @param {string} to An agents id
|
|
* @param {string} message Message to be send
|
|
* @return {Promise} Returns a promise which resolves when the message as
|
|
* successfully been sent, or rejected when sending the
|
|
* message failed
|
|
* @private
|
|
*/
|
|
Agent.prototype._sendByNetworkId = function(networkId, to, message) {
|
|
// TODO: change this.connections to a map with networkId as keys, much faster
|
|
for (var i = 0; i < this.connections.length; i++) {
|
|
var connection = this.connections[i];
|
|
if (connection.transport.networkId == networkId) {
|
|
return connection.send(to, message);
|
|
}
|
|
}
|
|
|
|
return Promise.reject(new Error('No transport found with networkId "' + networkId + '"'));
|
|
};
|
|
|
|
/**
|
|
* Send a message by a transport by protocol.
|
|
* The message will be send via the first found transport having the specified
|
|
* protocol.
|
|
* @param {string} protocol A protocol, for example 'http' or 'ws'
|
|
* @param {string} to An agents id
|
|
* @param {string} message Message to be send
|
|
* @return {Promise} Returns a promise which resolves when the message as
|
|
* successfully been sent, or rejected when sending the
|
|
* message failed
|
|
* @private
|
|
*/
|
|
Agent.prototype._sendByProtocol = function(protocol, to, message) {
|
|
for (var i = 0; i < this.connections.length; i++) {
|
|
var connection = this.connections[i];
|
|
if (connection.transport.type == protocol) {
|
|
return connection.send(to, message);
|
|
}
|
|
}
|
|
|
|
return Promise.reject(new Error('No transport found for protocol "' + protocol + '"'));
|
|
};
|
|
|
|
/**
|
|
* Send a transport to an agent via a specific transport
|
|
* @param {string} transportId The configured id of a transport.
|
|
* @param {string} to An agents id
|
|
* @param {string} message Message to be send
|
|
* @return {Promise} Returns a promise which resolves when the message as
|
|
* successfully been sent, or rejected when sending the
|
|
* message failed
|
|
* @private
|
|
*/
|
|
Agent.prototype._sendByTransportId = function(transportId, to, message) {
|
|
for (var i = 0; i < this.connections.length; i++) {
|
|
var connection = this.connections[i];
|
|
if (connection.transport.id == transportId) {
|
|
return connection.send(to, message);
|
|
}
|
|
}
|
|
|
|
return Promise.reject(new Error('No transport found with id "' + transportId + '"'));
|
|
};
|
|
|
|
/**
|
|
* Receive a message.
|
|
* @param {string} from Id of sender
|
|
* @param {*} message Received message, a JSON object (often a string)
|
|
*/
|
|
Agent.prototype.receive = function(from, message) {
|
|
// ... to be overloaded
|
|
};
|
|
|
|
/**
|
|
* The method _receive is overloaded in a cascaded way by modules, and calls
|
|
* the public method Agent.receive at the end of the chain.
|
|
* @param {string} from Id of sender
|
|
* @param {*} message Received message, a JSON object (often a string)
|
|
* @returns {*} Returns the return value of Agent.receive
|
|
* @private
|
|
*/
|
|
Agent.prototype._receive = function (from, message) {
|
|
return this.receive(from, message);
|
|
};
|
|
|
|
/**
|
|
* Connect to a transport. The agent will subscribe itself to
|
|
* messages sent to his id.
|
|
* @param {string | Transport | Transport[] | string[]} transport
|
|
* A Transport instance, or the id of a
|
|
* transport loaded in eve.system.
|
|
* @param {string} [id] An optional alternative id to be used
|
|
* for the connection. By default, the agents
|
|
* own id is used.
|
|
* @return {Connection | Connection[]} Returns a connection or, in case of
|
|
* multiple transports, returns an
|
|
* array with connections. The connections
|
|
* have a promise .ready which resolves
|
|
* as soon as the connection is ready for
|
|
* use.
|
|
*/
|
|
Agent.prototype.connect = function(transport, id) {
|
|
if (Array.isArray(transport)) {
|
|
var me = this;
|
|
return transport.map(function (_transport) {
|
|
return me._connect(_transport, id);
|
|
});
|
|
}
|
|
else if (typeof transport === 'string') {
|
|
// get transport by id
|
|
return this._connect(Agent.getTransportById(transport), id);
|
|
}
|
|
else {
|
|
// a transport instance
|
|
return this._connect(transport, id);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Connect to a transport
|
|
* @param {Transport} transport A Transport instance
|
|
* @param {string} [id] An optional alternative id to be used
|
|
* for the connection. By default, the agents
|
|
* own id is used.
|
|
* @return {Connection} Returns a connection.
|
|
* @private
|
|
*/
|
|
Agent.prototype._connect = function (transport, id) {
|
|
// create a receive function which is bound to the _receive function.
|
|
// the _receive function can be replaced in by modules in a cascaded way,
|
|
// and in the end calls this.receive of the agent.
|
|
// note: we don't do receive = this._receive.bind(this) as the _receive
|
|
// function can be overloaded after a connection is made.
|
|
var me = this;
|
|
var receive = function (from, message) {
|
|
return me._receive(from, message);
|
|
};
|
|
var connection = transport.connect(id || this.id, receive);
|
|
this.connections.push(connection);
|
|
|
|
// set or replace the defaultConnection
|
|
if (!this.defaultConnection) {
|
|
this.defaultConnection = connection;
|
|
}
|
|
else if (transport['default']) {
|
|
if (this.defaultConnection['default']) {
|
|
throw new Error('Cannot connect to a second default transport');
|
|
}
|
|
this.defaultConnection = connection;
|
|
}
|
|
|
|
this._updateReady();
|
|
|
|
return connection;
|
|
};
|
|
|
|
/**
|
|
* Disconnect from one or multiple transports
|
|
* @param {string | Transport | string[] | Transport[]} [transport]
|
|
* A transport or an array with transports.
|
|
* parameter transport can be an instance of a Transport, or the
|
|
* id of a transport.
|
|
* When transport is undefined, the agent will be disconnected
|
|
* from all connected transports.
|
|
*/
|
|
Agent.prototype.disconnect = function(transport) {
|
|
var i, connection;
|
|
|
|
if (!transport) {
|
|
// disconnect all transports
|
|
while (connection = this.connections[0]) {
|
|
this._disconnect(connection);
|
|
}
|
|
}
|
|
else if (Array.isArray(transport)) {
|
|
// an array with transports
|
|
i = 0;
|
|
while (i < this.connections.length) {
|
|
connection = this.connections[i];
|
|
if (transport.indexOf(connection.transport) !== -1) {
|
|
this._disconnect(connection);
|
|
}
|
|
else {
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
else if (typeof transport === 'string') {
|
|
// transport by id
|
|
this.disconnect(Agent.getTransportById(transport));
|
|
}
|
|
else {
|
|
// a single transport
|
|
for (i = 0; i < this.connections.length; i++) {
|
|
connection = this.connections[i];
|
|
if (connection.transport === transport) {
|
|
this._disconnect(connection);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Close a connection
|
|
* @param {Connection} connection
|
|
* @private
|
|
*/
|
|
Agent.prototype._disconnect = function (connection) {
|
|
// find the connection
|
|
var index = this.connections.indexOf(connection);
|
|
if (index !== -1) {
|
|
// close the connection
|
|
connection.close();
|
|
|
|
// remove from the list with connections
|
|
this.connections.splice(index, 1);
|
|
|
|
// replace the defaultConnection if needed
|
|
if (this.defaultConnection === connection) {
|
|
this.defaultConnection = this.connections[this.connections.length - 1] || null;
|
|
}
|
|
}
|
|
|
|
this._updateReady();
|
|
};
|
|
|
|
/**
|
|
* Update the ready state of the agent
|
|
* @private
|
|
*/
|
|
Agent.prototype._updateReady = function () {
|
|
// FIXME: we should not replace with a new Promise,
|
|
// we have a problem when this.ready is requested before ready,
|
|
// and another connection is opened before ready
|
|
this.ready = Promise.all(this.connections.map(function (connection) {
|
|
return connection.ready;
|
|
}));
|
|
};
|
|
|
|
module.exports = Agent;
|
|
|
|
},{"./util":23,"promise":114,"uuid-v4":125}],3:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var seed = _dereq_('seed-random');
|
|
var hypertimer = _dereq_('hypertimer');
|
|
var TransportManager = _dereq_('./TransportManager');
|
|
|
|
// map with known configuration properties
|
|
var KNOWN_PROPERTIES = {
|
|
transports: true,
|
|
timer: true,
|
|
random: true
|
|
};
|
|
|
|
function ServiceManager(config) {
|
|
this.transports = new TransportManager();
|
|
|
|
this.timer = hypertimer();
|
|
|
|
this.random = Math.random;
|
|
|
|
this.init(config);
|
|
}
|
|
|
|
/**
|
|
* Initialize the service manager with services loaded from a configuration
|
|
* object. All current services are unloaded and removed.
|
|
* @param {Object} config
|
|
*/
|
|
ServiceManager.prototype.init = function (config) {
|
|
this.transports.clear();
|
|
|
|
if (config) {
|
|
if (config.transports) {
|
|
this.transports.load(config.transports);
|
|
}
|
|
|
|
if (config.timer) {
|
|
this.timer.config(config.timer);
|
|
}
|
|
|
|
if (config.random) {
|
|
if (config.random.deterministic) {
|
|
var key = config.random.seed || 'random seed';
|
|
this.random = seed(key, config.random);
|
|
}
|
|
else {
|
|
this.random = Math.random;
|
|
}
|
|
}
|
|
|
|
for (var prop in config) {
|
|
if (config.hasOwnProperty(prop) && !KNOWN_PROPERTIES[prop]) {
|
|
// TODO: should log this warning via a configured logger
|
|
console.log('WARNING: Unknown configuration option "' + prop + '"')
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Clear all configured services
|
|
*/
|
|
ServiceManager.prototype.clear = function () {
|
|
this.transports.clear();
|
|
};
|
|
|
|
module.exports = ServiceManager;
|
|
|
|
},{"./TransportManager":4,"hypertimer":110,"seed-random":124}],4:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
/**
|
|
* A manager for loading and finding transports.
|
|
* @param {Array} [config] Optional array containing configuration objects
|
|
* for transports.
|
|
* @constructor
|
|
*/
|
|
function TransportManager(config) {
|
|
this.transports = [];
|
|
|
|
if (config) {
|
|
this.load(config);
|
|
}
|
|
}
|
|
|
|
// map with all registered types of transports
|
|
// each transport must register itself at the TransportManager using registerType.
|
|
TransportManager.types = {};
|
|
|
|
/**
|
|
* Register a new type of transport. This transport can then be loaded via
|
|
* configuration.
|
|
* @param {Transport.prototype} constructor A transport constructor
|
|
*/
|
|
TransportManager.registerType = function (constructor) {
|
|
var type = constructor.prototype.type;
|
|
if (typeof constructor !== 'function') {
|
|
throw new Error('Constructor function expected');
|
|
}
|
|
if (!type) {
|
|
throw new Error('Field "prototype.type" missing in transport constructor');
|
|
}
|
|
if (type in TransportManager.types) {
|
|
if (TransportManager.types[type] !== constructor) {
|
|
throw new Error('Transport type "' + type + '" already exists');
|
|
}
|
|
}
|
|
|
|
TransportManager.types[type] = constructor;
|
|
};
|
|
|
|
/**
|
|
* Add a loaded transport to the manager
|
|
* @param {Transport} transport
|
|
* @return {Transport} returns the transport itself
|
|
*/
|
|
TransportManager.prototype.add = function (transport) {
|
|
this.transports.push(transport);
|
|
return transport;
|
|
};
|
|
|
|
/**
|
|
* Load one or multiple transports based on JSON configuration.
|
|
* New transports will be appended to current transports.
|
|
* @param {Object | Array} config
|
|
* @return {Transport | Transport[]} Returns the loaded transport(s)
|
|
*/
|
|
TransportManager.prototype.load = function (config) {
|
|
if (Array.isArray(config)) {
|
|
return config.map(this.load.bind(this));
|
|
}
|
|
|
|
var type = config.type;
|
|
if (!type) {
|
|
throw new Error('Property "type" missing');
|
|
}
|
|
|
|
var constructor = TransportManager.types[type];
|
|
if (!constructor) {
|
|
throw new Error('Unknown type of transport "' + type + '". ' +
|
|
'Choose from: ' + Object.keys(TransportManager.types).join(','))
|
|
}
|
|
|
|
var transport = new constructor(config);
|
|
this.transports.push(transport);
|
|
return transport;
|
|
};
|
|
|
|
/**
|
|
* Unload a transport.
|
|
* @param {Transport | Transport[] | string | string[]} transport
|
|
* A Transport instance or the id of a transport, or an Array
|
|
* with transports or transport ids.
|
|
*/
|
|
TransportManager.prototype.unload = function (transport) {
|
|
var _transport;
|
|
if (typeof transport === 'string') {
|
|
_transport = this.get(transport);
|
|
}
|
|
else if (Array.isArray(transport)) {
|
|
for (var i = 0; i < transport.length; i++) {
|
|
this.unload(transport[i]);
|
|
}
|
|
}
|
|
else {
|
|
_transport = transport;
|
|
}
|
|
|
|
if (_transport) {
|
|
_transport.close();
|
|
|
|
var index = this.transports.indexOf(_transport);
|
|
if (index !== -1) {
|
|
this.transports.splice(index, 1);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get a transport by its id. The transport must have been created with an id
|
|
* @param {string} [id] The id of a transport
|
|
* @return {Transport} Returns the transport when found. Throws an error
|
|
* when not found.
|
|
*/
|
|
TransportManager.prototype.get = function (id) {
|
|
for (var i = 0; i < this.transports.length; i++) {
|
|
var transport = this.transports[i];
|
|
if (transport.id === id) {
|
|
return transport;
|
|
}
|
|
}
|
|
|
|
throw new Error('Transport with id "' + id + '" not found');
|
|
};
|
|
|
|
/**
|
|
* Get all transports.
|
|
* @return {Transport[]} Returns an array with all loaded transports.
|
|
*/
|
|
TransportManager.prototype.getAll = function () {
|
|
return this.transports.concat([]);
|
|
};
|
|
|
|
/**
|
|
* Find transports by type.
|
|
* @param {string} [type] Type of the transport. Choose from 'amqp',
|
|
* 'distribus', 'local', 'pubnub'.
|
|
* @return {Transport[]} When type is defined, the all transports of this
|
|
* type are returned. When undefined, all transports
|
|
* are returned.
|
|
*/
|
|
TransportManager.prototype.getByType = function (type) {
|
|
if (type) {
|
|
if (!(type in TransportManager.types)) {
|
|
throw new Error('Unknown type of transport "' + type + '". ' +
|
|
'Choose from: ' + Object.keys(TransportManager.types).join(','))
|
|
}
|
|
|
|
return this.transports.filter(function (transport) {
|
|
return transport.type === type;
|
|
});
|
|
}
|
|
else {
|
|
return [].concat(this.transports);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Close all configured transports and remove them from the manager.
|
|
*/
|
|
TransportManager.prototype.clear = function () {
|
|
this.transports.forEach(function (transport) {
|
|
transport.close();
|
|
});
|
|
this.transports = [];
|
|
};
|
|
|
|
module.exports = TransportManager;
|
|
|
|
},{}],5:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var babble = _dereq_('babble');
|
|
|
|
/**
|
|
* Create a Babble module for an agent.
|
|
* The agents _receive function is wrapped into a new handler.
|
|
* Creates a Babble instance with function `ask`, `tell`, `listen`, `listenOnce`
|
|
* @param {Agent} agent
|
|
* @param {Object} [options] Optional parameters. Not applicable for BabbleModule
|
|
* @constructor
|
|
*/
|
|
function BabbleModule(agent, options) {
|
|
// create a new babbler
|
|
var babbler = babble.babbler(agent.id);
|
|
babbler.connect({
|
|
connect: function (params) {},
|
|
disconnect: function(token) {},
|
|
send: function (to, message) {
|
|
agent.send(to, message);
|
|
}
|
|
});
|
|
this.babbler = babbler;
|
|
|
|
// create a receive function for the agent
|
|
var receiveOriginal = agent._receive;
|
|
this._receive = function (from, message) {
|
|
babbler._receive(message);
|
|
// TODO: only propagate to receiveOriginal if the message is not handled by the babbler
|
|
return receiveOriginal.call(agent, from, message);
|
|
};
|
|
}
|
|
|
|
BabbleModule.prototype.type = 'babble';
|
|
|
|
/**
|
|
* Get a map with mixin functions
|
|
* @return {{_receive: function, ask: function, tell: function, listen: function, listenOnce: function}}
|
|
* Returns mixin function, which can be used to extend the agent.
|
|
*/
|
|
BabbleModule.prototype.mixin = function () {
|
|
var babbler = this.babbler;
|
|
return {
|
|
_receive: this._receive,
|
|
ask: babbler.ask.bind(babbler),
|
|
tell: babbler.tell.bind(babbler),
|
|
listen: babbler.listen.bind(babbler),
|
|
listenOnce: babbler.listenOnce.bind(babbler)
|
|
}
|
|
};
|
|
|
|
module.exports = BabbleModule;
|
|
|
|
},{"babble":40}],6:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
/**
|
|
* Create a pattern listener onto an Agent.
|
|
* A new handler is added to the agents _receiver function.
|
|
* Creates a Pattern instance with functions `listen` and `unlisten`.
|
|
* @param {Agent} agent
|
|
* @param {Object} [options] Optional parameters. Can contain properties:
|
|
* - stopPropagation: boolean
|
|
* When false (default), a message
|
|
* will be delivered at all
|
|
* matching pattern listeners.
|
|
* When true, a message will be
|
|
* be delivered at the first
|
|
* matching pattern listener only.
|
|
*/
|
|
function PatternModule(agent, options) {
|
|
this.agent = agent;
|
|
this.stopPropagation = options && options.stopPropagation || false;
|
|
this.receiveOriginal = agent._receive;
|
|
this.listeners = [];
|
|
}
|
|
|
|
PatternModule.prototype.type = 'pattern';
|
|
|
|
/**
|
|
* Receive a message.
|
|
* All pattern listeners will be checked against their patterns, and if there
|
|
* is a match, the pattern listeners callback function is invoked.
|
|
* @param {string} from Id of sender
|
|
* @param {*} message Received message, a JSON object (often a string)
|
|
*/
|
|
PatternModule.prototype.receive = function(from, message) {
|
|
var response;
|
|
var responses = [];
|
|
for (var i = 0, ii = this.listeners.length; i < ii; i++) {
|
|
var listener = this.listeners[i];
|
|
var pattern = listener.pattern;
|
|
var match = (pattern instanceof Function && pattern(message)) ||
|
|
(pattern instanceof RegExp && pattern.test(message)) ||
|
|
(pattern == message);
|
|
|
|
if (match) {
|
|
response = listener.callback.call(this.agent, from, message);
|
|
responses.push(response);
|
|
if (this.stopPropagation) {
|
|
return responses[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
response = this.receiveOriginal.call(this.agent, from, message);
|
|
responses.push(response);
|
|
return responses[0];
|
|
};
|
|
|
|
/**
|
|
* Add a pattern listener for incoming messages
|
|
* @param {string | RegExp | Function} pattern Message pattern
|
|
* @param {Function} callback Callback function invoked when
|
|
* a message matching the pattern
|
|
* is received.
|
|
* Invoked as callback(from, message)
|
|
*/
|
|
PatternModule.prototype.listen = function(pattern, callback) {
|
|
this.listeners.push({
|
|
pattern: pattern,
|
|
callback: callback
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Remove a pattern listener for incoming messages
|
|
* @param {string | RegExp | Function} pattern Message pattern
|
|
* @param {Function} callback
|
|
*/
|
|
PatternModule.prototype.unlisten = function(pattern, callback) {
|
|
for (var i = 0, ii = this.listeners.length; i < ii; i++) {
|
|
var listener = this.listeners[i];
|
|
if (listener.pattern === pattern && listener.callback === callback) {
|
|
this.listeners.splice(i, 1);
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get a map with mixin functions
|
|
* @return {{_receive: function, listen: function, unlisten: function}}
|
|
* Returns mixin function, which can be used to extend the agent.
|
|
*/
|
|
PatternModule.prototype.mixin = function () {
|
|
return {
|
|
_receive: this.receive.bind(this),
|
|
listen: this.listen.bind(this),
|
|
unlisten: this.unlisten.bind(this)
|
|
}
|
|
};
|
|
|
|
module.exports = PatternModule;
|
|
|
|
},{}],7:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var uuid = _dereq_('uuid-v4');
|
|
var Promise = _dereq_('promise');
|
|
var util = _dereq_('../util');
|
|
|
|
|
|
/**
|
|
*
|
|
* @param {Agent} agent
|
|
* @param {Object} availableFunctions
|
|
* @constructor
|
|
*/
|
|
function RPCModule(agent, availableFunctions) {
|
|
this.agent = agent;
|
|
this.receiveOriginal = agent._receive;
|
|
this.queue = {};
|
|
this.promiseTimeout = 1500; // 1 second
|
|
|
|
// check the available functions
|
|
if (availableFunctions instanceof Array) {
|
|
this.functionsFromArray(availableFunctions);
|
|
}
|
|
else if (availableFunctions instanceof Object) {
|
|
this.availableFunctions = availableFunctions;
|
|
}
|
|
else {
|
|
console.log('cannot use RPC with the supplied functions', availableFunctions);
|
|
}
|
|
}
|
|
|
|
RPCModule.prototype.type = 'rpc';
|
|
|
|
/**
|
|
*
|
|
* @param availableFunctions
|
|
*/
|
|
RPCModule.prototype.functionsFromArray = function (availableFunctions) {
|
|
this.availableFunctions = {};
|
|
for (var i = 0; i < availableFunctions.length; i++) {
|
|
var fn = availableFunctions[i];
|
|
this.availableFunctions[fn] = this.agent[fn];
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
*
|
|
* @param to
|
|
* @param message
|
|
* @returns {Promise}
|
|
*/
|
|
RPCModule.prototype.request = function (to, message) {
|
|
var me = this;
|
|
return new Promise(function (resolve, reject) {
|
|
// prepare the envelope
|
|
if (typeof message != 'object' ) {reject(new TypeError('Message must be an object'));}
|
|
if (message.jsonrpc !== '2.0' ) {message.jsonrpc = '2.0';}
|
|
if (message.id === undefined) {message.id = uuid();}
|
|
if (message.method === undefined) {reject(new Error('Property "method" expected'));}
|
|
if (message.params === undefined) {message.params = {};}
|
|
|
|
// add the request to the list with requests in progress
|
|
me.queue[message.id] = {
|
|
resolve: resolve,
|
|
reject: reject,
|
|
timeout: setTimeout(function () {
|
|
delete me.queue[message.id];
|
|
reject(new Error('Timeout'));
|
|
}, me.promiseTimeout)
|
|
};
|
|
var sendRequest = me.agent.send(to, message);
|
|
if (util.isPromise(sendRequest) == true) {
|
|
sendRequest.catch(function (err) {reject(err);});
|
|
}
|
|
});
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
*
|
|
* @param from
|
|
* @param message
|
|
* @returns {*}
|
|
*/
|
|
RPCModule.prototype.receive = function (from, message) {
|
|
if (typeof message == 'object') {
|
|
if (message.jsonrpc == '2.0') {
|
|
this._receive(from, message);
|
|
}
|
|
else {
|
|
this.receiveOriginal.call(this.agent, from, message);
|
|
}
|
|
}
|
|
else {
|
|
this.receiveOriginal.call(this.agent, from, message);
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
*
|
|
* @param from
|
|
* @param message
|
|
* @returns {*}
|
|
* @private
|
|
*/
|
|
RPCModule.prototype._receive = function (from, message) {
|
|
// define structure of return message
|
|
var returnMessage = {jsonrpc:'2.0', id:message.id};
|
|
|
|
// check if this is a request
|
|
if (message.method !== undefined) {
|
|
// check is method is available for this agent
|
|
var method = this.availableFunctions[message.method];
|
|
if (method !== undefined) {
|
|
var response = method.call(this.agent, message.params, from) || null;
|
|
// check if response is a promise
|
|
if (util.isPromise(response)) {
|
|
var me = this;
|
|
response
|
|
.then(function (result) {
|
|
returnMessage.result = result;
|
|
me.agent.send(from, returnMessage)
|
|
})
|
|
.catch(function (error) {
|
|
returnMessage.error = error.message || error.toString();
|
|
me.agent.send(from, returnMessage);
|
|
})
|
|
}
|
|
else {
|
|
returnMessage.result = response;
|
|
this.agent.send(from, returnMessage);
|
|
}
|
|
}
|
|
else {
|
|
var error = new Error('Cannot find function: ' + message.method);
|
|
returnMessage.error = error.message || error.toString();
|
|
this.agent.send(from, returnMessage);
|
|
}
|
|
}
|
|
// check if this is a response
|
|
else if (message.result !== undefined || message.error !== undefined) {
|
|
var request = this.queue[message.id];
|
|
if (request !== undefined) {
|
|
// if an error is defined, reject promise
|
|
if (message.error != undefined) { // null or undefined
|
|
// FIXME: returned error should be an object {code: number, message: string}
|
|
request.reject(new Error(message.error));
|
|
}
|
|
else {
|
|
request.resolve(message.result);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// send error back to sender.
|
|
var error = new Error('No method or result defined. Message:' + JSON.stringify(message));
|
|
returnMessage.error = error.message || error.toString();
|
|
// FIXME: returned error should be an object {code: number, message: string}
|
|
this.agent.send(from, returnMessage);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get a map with mixin functions
|
|
* @return {{_receive: function, request: function}}
|
|
* Returns mixin function, which can be used to extend the agent.
|
|
*/
|
|
RPCModule.prototype.mixin = function () {
|
|
return {
|
|
_receive: this.receive.bind(this),
|
|
request: this.request.bind(this)
|
|
}
|
|
};
|
|
|
|
module.exports = RPCModule;
|
|
},{"../util":23,"promise":114,"uuid-v4":125}],8:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var uuid = _dereq_('uuid-v4');
|
|
var Promise = _dereq_('promise');
|
|
var util = _dereq_('../util');
|
|
|
|
var TIMEOUT = 60000; // ms
|
|
|
|
/**
|
|
* Create a Request module.
|
|
* The module attaches a handler to the agents _receive function.
|
|
* Creates a Request instance with function `request`.
|
|
* @param {Agent} agent
|
|
* @param {Object} [options] Optional parameters. Can contain properties:
|
|
* - timeout: number A timeout for responses in
|
|
* milliseconds. 60000 ms by
|
|
* default.
|
|
*/
|
|
function RequestModule(agent, options) {
|
|
this.agent = agent;
|
|
this.receiveOriginal = agent._receive;
|
|
this.timeout = options && options.timeout || TIMEOUT;
|
|
this.queue = [];
|
|
}
|
|
|
|
RequestModule.prototype.type = 'request';
|
|
|
|
/**
|
|
* Event handler, handles incoming messages
|
|
* @param {String} from Id of the sender
|
|
* @param {*} message
|
|
* @return {boolean} Returns true when a message is handled, else returns false
|
|
*/
|
|
RequestModule.prototype.receive = function (from, message) {
|
|
var agent = this.agent;
|
|
|
|
if (typeof message === 'object') {
|
|
var envelope = message;
|
|
|
|
// match the request from the id in the response
|
|
var request = this.queue[envelope.id];
|
|
if (request) {
|
|
// remove the request from the queue
|
|
clearTimeout(request.timeout);
|
|
delete this.queue[envelope.id];
|
|
|
|
// resolve the requests promise with the response message
|
|
if (envelope.error) {
|
|
// TODO: turn this into an Error instance again
|
|
request.reject(new Error(envelope.error));
|
|
}
|
|
else {
|
|
request.resolve(envelope.message);
|
|
}
|
|
return true;
|
|
}
|
|
else if (message.type == 'request') {
|
|
try {
|
|
var response = this.receiveOriginal.call(agent, from, message.message);
|
|
if (util.isPromise(response)) {
|
|
// wait until the promise resolves
|
|
response
|
|
.then(function (result) {
|
|
agent.send(from, {type: 'request', id: message.id, message: result});
|
|
})
|
|
.catch(function (err) {
|
|
agent.send(from, {type: 'request', id: message.id, error: err.message || err.toString()});
|
|
});
|
|
}
|
|
else {
|
|
// immediately send a result
|
|
agent.send(from, {type: 'request', id: message.id, message: response });
|
|
}
|
|
}
|
|
catch (err) {
|
|
agent.send(from, {type: 'request', id: message.id, error: err.message || err.toString()});
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (this.receiveOriginal) {
|
|
this.receiveOriginal.call(agent, from, message);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Send a request
|
|
* @param {string} to Id of the recipient
|
|
* @param {*} message
|
|
* @returns {Promise.<*, Error>} Returns a promise resolving with the response message
|
|
*/
|
|
RequestModule.prototype.request = function (to, message) {
|
|
var me = this;
|
|
return new Promise(function (resolve, reject) {
|
|
// put the data in an envelope with id
|
|
var id = uuid();
|
|
var envelope = {
|
|
type: 'request',
|
|
id: id,
|
|
message: message
|
|
};
|
|
|
|
// add the request to the list with requests in progress
|
|
me.queue[id] = {
|
|
resolve: resolve,
|
|
reject: reject,
|
|
timeout: setTimeout(function () {
|
|
delete me.queue[id];
|
|
reject(new Error('Timeout'));
|
|
}, me.timeout)
|
|
};
|
|
|
|
me.agent.send(to, envelope)
|
|
.catch(function (err) {
|
|
reject(err);
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Get a map with mixin functions
|
|
* @return {{_receive: function, request: function}}
|
|
* Returns mixin function, which can be used to extend the agent.
|
|
*/
|
|
RequestModule.prototype.mixin = function () {
|
|
return {
|
|
_receive: this.receive.bind(this),
|
|
request: this.request.bind(this)
|
|
}
|
|
};
|
|
|
|
module.exports = RequestModule;
|
|
|
|
},{"../util":23,"promise":114,"uuid-v4":125}],9:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Promise = _dereq_('promise');
|
|
|
|
/**
|
|
* An abstract Transport connection
|
|
* @param {Transport} transport
|
|
* @param {string} id
|
|
* @param {function} receive
|
|
* @constructor
|
|
* @abstract
|
|
*/
|
|
function Connection (transport, id, receive) {
|
|
throw new Error('Cannot create an abstract Connection');
|
|
}
|
|
|
|
Connection.prototype.ready = Promise.reject(new Error('Cannot get abstract property ready'));
|
|
|
|
/**
|
|
* Send a message to an agent.
|
|
* @param {string} to
|
|
* @param {*} message
|
|
* @return {Promise} returns a promise which resolves when the message has been sent
|
|
*/
|
|
Connection.prototype.send = function (to, message) {
|
|
throw new Error('Cannot call abstract function send');
|
|
};
|
|
|
|
/**
|
|
* Close the connection, disconnect from the transport.
|
|
*/
|
|
Connection.prototype.close = function () {
|
|
throw new Error('Cannot call abstract function "close"');
|
|
};
|
|
|
|
module.exports = Connection;
|
|
|
|
},{"promise":114}],10:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
/**
|
|
* Abstract prototype of a transport
|
|
* @param {Object} [config]
|
|
* @constructor
|
|
*/
|
|
function Transport(config) {
|
|
this.id = config && config.id || null;
|
|
this['default'] = config && config['default'] || false;
|
|
}
|
|
|
|
Transport.prototype.type = null;
|
|
|
|
/**
|
|
* Connect an agent
|
|
* @param {String} id
|
|
* @param {Function} receive Invoked as receive(from, message)
|
|
* @return {Connection} Returns a connection
|
|
*/
|
|
Transport.prototype.connect = function(id, receive) {
|
|
throw new Error('Cannot invoke abstract function "connect"');
|
|
};
|
|
|
|
/**
|
|
* Close the transport
|
|
*/
|
|
Transport.prototype.close = function() {
|
|
throw new Error('Cannot invoke abstract function "close"');
|
|
};
|
|
|
|
module.exports = Transport;
|
|
|
|
},{}],11:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Promise = _dereq_('promise');
|
|
var Connection = _dereq_('../Connection');
|
|
|
|
/**
|
|
* A local connection.
|
|
* @param {AMQPTransport} transport
|
|
* @param {string | number} id
|
|
* @param {function} receive
|
|
* @constructor
|
|
*/
|
|
function AMQPConnection(transport, id, receive) {
|
|
this.transport = transport;
|
|
this.id = id;
|
|
|
|
// ready state
|
|
this.ready = this.transport._connect(id, receive);
|
|
}
|
|
|
|
/**
|
|
* Send a message to an agent.
|
|
* @param {string} to
|
|
* @param {*} message
|
|
* @return {Promise} returns a promise which resolves when the message has been sent
|
|
*/
|
|
AMQPConnection.prototype.send = function (to, message) {
|
|
var me = this;
|
|
return new Promise(function (resolve, reject) {
|
|
var msg = {
|
|
body: {
|
|
from: me.id,
|
|
to: to,
|
|
message: message
|
|
}
|
|
};
|
|
var options = {
|
|
//immediate: true
|
|
};
|
|
|
|
me.transport.exchange.publish(to, msg, options, function () {
|
|
// FIXME: callback is not called.
|
|
//console.log('sent', arguments)
|
|
});
|
|
|
|
resolve();
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Close the connection
|
|
*/
|
|
AMQPConnection.prototype.close = function () {
|
|
this.transport._close(this.id);
|
|
};
|
|
|
|
module.exports = AMQPConnection;
|
|
|
|
},{"../Connection":9,"promise":114}],12:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Promise = _dereq_('promise');
|
|
var Transport = _dereq_('./../Transport');
|
|
var AMQPConnection = _dereq_('./AMQPConnection');
|
|
|
|
/**
|
|
* Use AMQP as transport
|
|
* @param {Object} config Config can contain the following properties:
|
|
* - `id: string`
|
|
* - `url: string`
|
|
* - `host: string`
|
|
* The config must contain either `url` or `host`.
|
|
* For example: {url: 'amqp://localhost'} or
|
|
* {host: 'dev.rabbitmq.com'}
|
|
* @constructor
|
|
*/
|
|
function AMQPTransport(config) {
|
|
this.id = config.id || null;
|
|
this.networkId = config.url || config.host || null;
|
|
this['default'] = config['default'] || false;
|
|
|
|
this.config = config;
|
|
this.connection = null;
|
|
this.exchange = null;
|
|
|
|
this.subscriptions = [];
|
|
}
|
|
|
|
AMQPTransport.prototype = new Transport();
|
|
|
|
AMQPTransport.prototype.type = 'amqp';
|
|
|
|
/**
|
|
* Connect an agent
|
|
* @param {String} id
|
|
* @param {Function} receive Invoked as receive(from, message)
|
|
* @return {AMQPConnection} Returns a connection.
|
|
*/
|
|
AMQPTransport.prototype.connect = function(id, receive) {
|
|
return new AMQPConnection(this, id, receive);
|
|
};
|
|
|
|
/**
|
|
* Get an AMQP connection. If there is not yet a connection, a connection will
|
|
* be made.
|
|
* @param {Function} callback Invoked as callback(connection)
|
|
* @private
|
|
*/
|
|
AMQPTransport.prototype._getConnection = function(callback) {
|
|
var me = this;
|
|
|
|
if (this.connection) {
|
|
// connection is available
|
|
callback(this.connection);
|
|
}
|
|
else {
|
|
if (this._onConnected) {
|
|
// connection is being opened but not yet ready
|
|
this._onConnected.push(callback);
|
|
}
|
|
else {
|
|
// no connection, create one
|
|
this._onConnected = [callback];
|
|
|
|
var amqp = _dereq_('amqp'); // lazy load the amqp library
|
|
var connection = amqp.createConnection(this.config);
|
|
connection.on('ready', function () {
|
|
var exchange = connection.exchange('', {confirm: true}, function () {
|
|
var _onConnected = me._onConnected;
|
|
delete me._onConnected;
|
|
|
|
me.connection = connection;
|
|
me.exchange = exchange;
|
|
|
|
_onConnected.forEach(function (callback) {
|
|
callback(me.connection);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Open a connection
|
|
* @param {string} id
|
|
* @param {Function} receive Invoked as receive(from, message)
|
|
*/
|
|
AMQPTransport.prototype._connect = function(id, receive) {
|
|
var me = this;
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
function subscribe(connection) {
|
|
var queue = connection.queue(id, {}, function() {
|
|
queue
|
|
.subscribe(function(message) {
|
|
var body = message.body;
|
|
receive(body.from, body.message);
|
|
})
|
|
.addCallback(function (ok) {
|
|
// register this subscription
|
|
me.subscriptions.push({
|
|
id: id,
|
|
consumerTag: ok.consumerTag
|
|
});
|
|
|
|
resolve(me);
|
|
});
|
|
});
|
|
}
|
|
|
|
me._getConnection(subscribe);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Close a connection an agent by its id
|
|
* @param {String} id
|
|
*/
|
|
AMQPTransport.prototype._close = function(id) {
|
|
var i = 0;
|
|
while (i < this.subscriptions.length) {
|
|
var subscription = this.subscriptions[i];
|
|
if (subscription.id == id) {
|
|
// remove this entry
|
|
this.subscriptions.splice(i, 1);
|
|
}
|
|
else {
|
|
i++;
|
|
}
|
|
}
|
|
|
|
if (this.subscriptions.length == 0) {
|
|
// fully disconnect if there are no subscribers left
|
|
this.exchange.destroy();
|
|
this.connection.disconnect();
|
|
|
|
this.connection = null;
|
|
this.exchange = null;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Close the transport.
|
|
*/
|
|
AMQPTransport.prototype.close = function() {
|
|
this.connection.destroy();
|
|
this.connection = null;
|
|
};
|
|
|
|
module.exports = AMQPTransport;
|
|
|
|
},{"./../Transport":10,"./AMQPConnection":11,"amqp":24,"promise":114}],13:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Promise = _dereq_('promise');
|
|
var Connection = _dereq_('../Connection');
|
|
|
|
/**
|
|
* A local connection.
|
|
* @param {DistribusTransport} transport
|
|
* @param {string | number} id
|
|
* @param {function} receive
|
|
* @constructor
|
|
*/
|
|
function DistribusConnection(transport, id, receive) {
|
|
this.transport = transport;
|
|
this.id = id;
|
|
|
|
// create a peer
|
|
var peer = this.transport.host.create(id);
|
|
peer.on('message', receive);
|
|
|
|
// ready state
|
|
this.ready = Promise.resolve(this);
|
|
}
|
|
|
|
/**
|
|
* Send a message to an agent.
|
|
* @param {string} to
|
|
* @param {*} message
|
|
* @return {Promise} returns a promise which resolves when the message has been sent
|
|
*/
|
|
DistribusConnection.prototype.send = function (to, message) {
|
|
return this.transport.host.send(this.id, to, message);
|
|
};
|
|
|
|
/**
|
|
* Close the connection
|
|
*/
|
|
DistribusConnection.prototype.close = function () {
|
|
this.transport.host.remove(this.id);
|
|
};
|
|
|
|
module.exports = DistribusConnection;
|
|
|
|
},{"../Connection":9,"promise":114}],14:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var distribus = _dereq_('distribus');
|
|
var Transport = _dereq_('./../Transport');
|
|
var DistribusConnection = _dereq_('./DistribusConnection');
|
|
|
|
/**
|
|
* Use distribus as transport
|
|
* @param {Object} config Config can contain the following properties:
|
|
* - `id: string`. Optional
|
|
* - `host: distribus.Host`. Optional
|
|
* If `host` is not provided,
|
|
* a new local distribus Host is created.
|
|
* @constructor
|
|
*/
|
|
function DistribusTransport(config) {
|
|
this.id = config && config.id || null;
|
|
this['default'] = config && config['default'] || false;
|
|
this.host = config && config.host || new distribus.Host(config);
|
|
|
|
this.networkId = this.host.networkId; // FIXME: networkId can change when host connects to another host.
|
|
}
|
|
|
|
DistribusTransport.prototype = new Transport();
|
|
|
|
DistribusTransport.prototype.type = 'distribus';
|
|
|
|
/**
|
|
* Connect an agent
|
|
* @param {String} id
|
|
* @param {Function} receive Invoked as receive(from, message)
|
|
* @return {DistribusConnection} Returns a connection.
|
|
*/
|
|
DistribusTransport.prototype.connect = function(id, receive) {
|
|
return new DistribusConnection(this, id, receive);
|
|
};
|
|
|
|
/**
|
|
* Close the transport.
|
|
*/
|
|
DistribusTransport.prototype.close = function() {
|
|
this.host.close();
|
|
this.host = null;
|
|
};
|
|
|
|
module.exports = DistribusTransport;
|
|
|
|
},{"./../Transport":10,"./DistribusConnection":13,"distribus":67}],15:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Promise = _dereq_('promise');
|
|
var Connection = _dereq_('../Connection');
|
|
|
|
/**
|
|
* A HTTP connection.
|
|
* @param {HTTPTransport} transport
|
|
* @param {string | number} id
|
|
* @param {function} receive
|
|
* @constructor
|
|
*/
|
|
function HTTPConnection(transport, id, receive) {
|
|
this.transport = transport;
|
|
this.id = id;
|
|
|
|
// register the agents receive function
|
|
if (this.id in this.transport.agents) {
|
|
throw new Error('Agent with id ' + id + ' already exists');
|
|
}
|
|
this.transport.agents[this.id] = receive;
|
|
|
|
// ready state
|
|
this.ready = Promise.resolve(this);
|
|
}
|
|
|
|
/**
|
|
* Send a message to an agent.
|
|
* @param {string} to
|
|
* @param {*} message
|
|
*/
|
|
HTTPConnection.prototype.send = function (to, message) {
|
|
var fromURL = this.transport.url.replace(':id', this.id);
|
|
|
|
var isURL = to.indexOf('://') !== -1;
|
|
var toURL;
|
|
if (isURL) {
|
|
toURL = to;
|
|
}
|
|
else {
|
|
if (this.transport.remoteUrl !== undefined) {
|
|
toURL = this.transport.remoteUrl.replace(':id', to);
|
|
}
|
|
else {
|
|
console.log('ERROR: no remote URL specified. Cannot send over HTTP.', to);
|
|
}
|
|
}
|
|
|
|
return this.transport.send(fromURL, toURL, message);
|
|
};
|
|
|
|
/**
|
|
* Close the connection
|
|
*/
|
|
HTTPConnection.prototype.close = function () {
|
|
delete this.transport.agents[this.id];
|
|
};
|
|
|
|
module.exports = HTTPConnection;
|
|
|
|
},{"../Connection":9,"promise":114}],16:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var http = _dereq_('http');
|
|
var Promise = _dereq_('promise');
|
|
var Transport = _dereq_('./../Transport');
|
|
var HTTPConnection = _dereq_('./HTTPConnection');
|
|
var uuid = _dereq_('uuid-v4');
|
|
|
|
/**
|
|
* HTTP Transport layer:
|
|
*
|
|
* Supported Options:
|
|
*
|
|
* {Number} config.port Port to listen on.
|
|
* {String} config.path Path, with or without leading and trailing slash (/)
|
|
* {Boolean} config.localShortcut If the agentId exists locally, use local transport. (local)
|
|
*
|
|
* Address: http://127.0.0.1:PORTNUMBER/PATH
|
|
*/
|
|
function HTTPTransport(config) {
|
|
this.id = config && config.id || null;
|
|
this.networkId = null;
|
|
|
|
this.agents = {};
|
|
this.outstandingRequests = {}; // these are received messages that are expecting a response
|
|
this.outstandingMessages = {};
|
|
|
|
this.url = config && config.url || "http://127.0.0.1:3000/agents/:id";
|
|
this.remoteUrl = config && config.remoteUrl;
|
|
this.localShortcut = (config && config.localShortcut === false) ? false : true;
|
|
|
|
this.httpTimeout = config && config.httpTimeout || 2000; // 1 second - timeout to send message
|
|
this.httpResponseTimeout = config && config.httpResponseTimeout || 200; // 0.5 second - timeout to expect reply after delivering request
|
|
this.regexHosts = /[http]{4}s?:\/\/([a-z\-\.A-Z0-9]*):?([0-9]*)(\/[a-z\/:A-Z0-9._\-% \\\(\)\*\+\.\^\$]*)/;
|
|
this.urlHostData = this.regexHosts.exec(this.url);
|
|
|
|
this.regexPath = this.getRegEx(this.urlHostData[3]);
|
|
this.port = config && config.port || this.urlHostData[2] || 3000;
|
|
this.path = this.urlHostData[3].replace(':id', '');
|
|
}
|
|
|
|
HTTPTransport.prototype = new Transport();
|
|
HTTPTransport.prototype.type = 'http';
|
|
|
|
HTTPTransport.prototype.getRegEx = function(url) {
|
|
return new RegExp(url.replace(/[\\\(\)\*\+\.\^\$]/g,function(match) {return '\\' + match;}).replace(':id','([:a-zA-Z_0-9]*)'));
|
|
};
|
|
|
|
|
|
function askAgent(url,method,params,callback, async) {
|
|
if (async === undefined) {
|
|
async = true;
|
|
}
|
|
// create post request
|
|
var POSTrequest = JSON.stringify({"id":0, "method": method, "params": params});
|
|
|
|
// create XMLHttpRequest object to send the POST request
|
|
var http = new XMLHttpRequest();
|
|
|
|
// insert the callback function. This is called when the message has been delivered and a response has been received
|
|
http.onreadystatechange = function () {
|
|
if (http.readyState == 4 && http.status == 200) {
|
|
if (callback === undefined || callback === null) {
|
|
}
|
|
else {
|
|
// launch callback function
|
|
callback(JSON.parse(http.responseText));
|
|
}
|
|
}
|
|
else if (http.readyState == 4 && http.status != 200) {
|
|
console.log("Make sure that the Node server has started.");
|
|
}
|
|
};
|
|
|
|
// open an asynchronous POST connection
|
|
http.open("POST", url, async);
|
|
// include header so the receiving code knows its a JSON object
|
|
http.setRequestHeader("Content-type", "application/json");
|
|
// send
|
|
http.send(POSTrequest);
|
|
}
|
|
|
|
|
|
/**
|
|
* Connect an agent
|
|
* @param {String} id
|
|
* @param {Function} receive Invoked as receive(from, message)
|
|
* @return {HTTPConnection} Returns a connection.
|
|
*/
|
|
HTTPTransport.prototype.connect = function(id, receive) {
|
|
if (this.server === undefined) {
|
|
this.initiateServer();
|
|
}
|
|
this.outstandingRequests[id] = {};
|
|
this.outstandingMessages[id] = {};
|
|
return new HTTPConnection(this, id, receive);
|
|
};
|
|
|
|
/**
|
|
* Send a message to an agent
|
|
* @param {String} from Id of sender
|
|
* @param {String} to Id of addressed peer
|
|
* @param {String} message
|
|
*/
|
|
HTTPTransport.prototype.send = function(from, to, message) {
|
|
var me = this;
|
|
return new Promise(function (resolve,reject) {
|
|
var hostData = me.regexHosts.exec(to);
|
|
var fromRegexpCheck = me.regexPath.exec(from);
|
|
var fromAgentId = fromRegexpCheck[1];
|
|
var outstandingMessageID = uuid();
|
|
|
|
// check for local shortcut possibility
|
|
if (me.localShortcut == true) {
|
|
var toRegexpCheck = me.regexPath.exec(to);
|
|
var toAgentId = toRegexpCheck[1];
|
|
var toPath = hostData[3].replace(toAgentId,"");
|
|
|
|
// check if the "to" address is on the same URL, port and path as the "from"
|
|
if ((hostData[1] == '127.0.0.1' && hostData[2] == me.urlHostData[2] && toPath == me.path) ||
|
|
(me.urlHostData[1] == hostData[1] && hostData[2] == me.urlHostData[2] && toPath == me.path)) {
|
|
// by definition true but check anyway
|
|
if (me.agents[toAgentId] !== undefined) {
|
|
me.agents[toAgentId](fromAgentId, message);
|
|
resolve();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// stringify the message. If the message is an object, it can have an ID so it may be part of a req/rep.
|
|
if (typeof message == 'object') {
|
|
|
|
// check if the send is a reply to an outstanding request and if so, deliver
|
|
var outstanding = me.outstandingRequests[fromAgentId];
|
|
if (outstanding[message.id] !== undefined) {
|
|
var callback = outstanding[message.id];
|
|
callback.response.end(JSON.stringify(message));
|
|
clearTimeout(callback.timeout);
|
|
delete outstanding[message.id];
|
|
resolve();
|
|
return;
|
|
}
|
|
// stringify the message.
|
|
message = JSON.stringify(message)
|
|
}
|
|
|
|
// all post options
|
|
var options = {
|
|
host: hostData[1],
|
|
port: hostData[2],
|
|
path: hostData[3],
|
|
method: 'POST',
|
|
headers: {
|
|
'x-eve-senderurl' : from, // used to get senderID
|
|
'Content-type' : 'text/plain'
|
|
}
|
|
};
|
|
var request = http.request(options, function(res) {
|
|
res.setEncoding('utf8');
|
|
// message was delivered, clear the cannot deliver timeout.
|
|
clearTimeout(me.outstandingMessages[fromAgentId][outstandingMessageID].timeout);
|
|
// listen to incoming data
|
|
res.on('data', function (response) {
|
|
var parsedResponse;
|
|
try {parsedResponse = JSON.parse(response);} catch (err) {parsedResponse = response;}
|
|
if (typeof parsedResponse == 'object') {
|
|
if (parsedResponse.__httpError__ !== undefined) {
|
|
reject(new Error(parsedResponse.__httpError__));
|
|
return;
|
|
}
|
|
}
|
|
me.agents[fromAgentId](to, parsedResponse);
|
|
resolve();
|
|
});
|
|
});
|
|
|
|
me.outstandingMessages[fromAgentId][outstandingMessageID] = {
|
|
timeout: setTimeout(function () {
|
|
request.abort();
|
|
reject(new Error("Cannot connect to " + to))
|
|
}, me.httpTimeout),
|
|
reject: reject
|
|
};
|
|
|
|
request.on('error', function(e) {
|
|
reject(e);
|
|
});
|
|
|
|
// write data to request body
|
|
request.write(message);
|
|
request.end();
|
|
});
|
|
};
|
|
|
|
|
|
/**
|
|
* This is the HTTP equivalent of receiveMessage.
|
|
*
|
|
* @param request
|
|
* @param response
|
|
*/
|
|
HTTPTransport.prototype.processRequest = function(request, response) {
|
|
var url = request.url;
|
|
|
|
// define headers
|
|
var headers = {};
|
|
headers['Access-Control-Allow-Origin'] = '*';
|
|
headers['Access-Control-Allow-Credentials'] = true;
|
|
headers['Content-Type'] = 'text/plain';
|
|
|
|
var regexpCheck = this.regexPath.exec(url);
|
|
if (regexpCheck !== null) {
|
|
var agentId = regexpCheck[1];
|
|
var senderId = 'unknown';
|
|
if (request.headers['x-eve-senderurl'] !== undefined) {
|
|
senderId = request.headers['x-eve-senderurl'];
|
|
}
|
|
var body = '';
|
|
request.on('data', function (data) {
|
|
body += data;
|
|
if (body.length > 1e6) { // 1e6 == 1MB
|
|
request.connection.destroy(); // FLOOD ATTACK OR FAULTY CLIENT, NUKE REQUEST
|
|
}
|
|
});
|
|
|
|
|
|
var me = this;
|
|
request.on('end', function () {
|
|
var expectReply = false;
|
|
var message;
|
|
try {message = JSON.parse(body);} catch (err) {message = body;}
|
|
|
|
// check if JSON RPC
|
|
expectReply = message.jsonrpc && message.jsonrpc == '2.0' || expectReply;
|
|
// check if type == 'request'
|
|
expectReply = message.type && message.type == 'request' || expectReply;
|
|
|
|
response.writeHead(200, headers);
|
|
// construct callback
|
|
var callback = me.agents[agentId];
|
|
if (callback === undefined) {
|
|
var error = new Error('Agent: "' + agentId + '" does not exist.');
|
|
response.end(JSON.stringify({__httpError__:error.message || error.toString()}));
|
|
}
|
|
else {
|
|
if (expectReply == true) {
|
|
me.outstandingRequests[agentId][message.id] = {
|
|
response: response,
|
|
timeout: setTimeout(function () {
|
|
response.end("timeout");
|
|
delete me.outstandingRequests[agentId][message.id];
|
|
}, me.httpResponseTimeout)
|
|
};
|
|
callback(senderId, message);
|
|
}
|
|
else {
|
|
// if we're not expecting a response, we first close the connection, then receive the message
|
|
response.end('');
|
|
if (callback !== undefined) {
|
|
callback(senderId, message);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Configure a HTTP server listener
|
|
*/
|
|
HTTPTransport.prototype.initiateServer = function() {
|
|
if (this.server === undefined) {
|
|
var me = this;
|
|
this.server = http.createServer(function (request, response) {
|
|
if (request.method == 'OPTIONS') {
|
|
var headers = {};
|
|
headers['Access-Control-Allow-Origin'] = '*';
|
|
headers['Access-Control-Allow-Methods'] = 'POST, OPTIONS';
|
|
headers['Access-Control-Allow-Credentials'] = true;
|
|
headers['Access-Control-Max-Age'] = '86400'; // 24 hours
|
|
headers['Access-Control-Allow-Headers'] = 'X-Requested-With, Access-Control-Allow-Origin, X-HTTP-Method-Override, Content-Type, Authorization, Accept';
|
|
// respond to the request
|
|
response.writeHead(200, headers);
|
|
response.end();
|
|
}
|
|
else if (request.method == 'POST') {
|
|
me.processRequest(request, response);
|
|
}
|
|
});
|
|
|
|
this.server.on('error', function(err) {
|
|
if (err.code == 'EADDRINUSE') {
|
|
throw new Error('ERROR: Could not start HTTP server. Port ' + me.port + ' is occupied.');
|
|
}
|
|
else {
|
|
throw new Error(err);
|
|
}
|
|
});
|
|
|
|
// Listen on port (default: 3000), IP defaults to 127.0.0.1
|
|
this.server.listen(this.port, function() {
|
|
// Put a friendly message on the terminal
|
|
console.log('Server listening at ', me.url);
|
|
});
|
|
|
|
|
|
}
|
|
else {
|
|
this.server.close();
|
|
this.server = undefined;
|
|
this.initiateServer();
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Close the HTTP server
|
|
*/
|
|
HTTPTransport.prototype.close = function() {
|
|
// close all open connections
|
|
for (var agentId in this.outstandingRequests) {
|
|
if (this.outstandingRequests.hasOwnProperty(agentId)) {
|
|
var agentRequests = this.outstandingRequests[agentId];
|
|
for (var messageId in agentRequests) {
|
|
if (agentRequests.hasOwnProperty(messageId)) {
|
|
var openMessage = agentRequests[messageId];
|
|
var error = new Error('Server shutting down.');
|
|
openMessage.response.end(JSON.stringify({__httpError__:error.message || error.toString()}));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// close server
|
|
if (this.server) {
|
|
this.server.close();
|
|
}
|
|
this.server = null;
|
|
};
|
|
|
|
|
|
module.exports = HTTPTransport;
|
|
|
|
|
|
},{"./../Transport":10,"./HTTPConnection":15,"http":138,"promise":114,"uuid-v4":125}],17:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Promise = _dereq_('promise');
|
|
var Connection = _dereq_('../Connection');
|
|
|
|
/**
|
|
* A local connection.
|
|
* @param {LocalTransport} transport
|
|
* @param {string | number} id
|
|
* @param {function} receive
|
|
* @constructor
|
|
*/
|
|
function LocalConnection(transport, id, receive) {
|
|
this.transport = transport;
|
|
this.id = id;
|
|
|
|
// register the agents receive function
|
|
if (this.id in this.transport.agents) {
|
|
throw new Error('Agent with id ' + id + ' already exists');
|
|
}
|
|
this.transport.agents[this.id] = receive;
|
|
|
|
// ready state
|
|
this.ready = Promise.resolve(this);
|
|
}
|
|
|
|
/**
|
|
* Send a message to an agent.
|
|
* @param {string} to
|
|
* @param {*} message
|
|
* @return {Promise} returns a promise which resolves when the message has been sent
|
|
*/
|
|
LocalConnection.prototype.send = function (to, message) {
|
|
var callback = this.transport.agents[to];
|
|
if (!callback) {
|
|
throw new Error('Agent with id ' + to + ' not found');
|
|
}
|
|
|
|
// invoke the agents receiver as callback(from, message)
|
|
callback(this.id, message);
|
|
|
|
return Promise.resolve();
|
|
};
|
|
|
|
/**
|
|
* Close the connection
|
|
*/
|
|
LocalConnection.prototype.close = function () {
|
|
delete this.transport.agents[this.id];
|
|
};
|
|
|
|
module.exports = LocalConnection;
|
|
|
|
},{"../Connection":9,"promise":114}],18:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Transport = _dereq_('./../Transport');
|
|
var LocalConnection = _dereq_('./LocalConnection');
|
|
|
|
/**
|
|
* Create a local transport.
|
|
* @param {Object} config Config can contain the following properties:
|
|
* - `id: string`. Optional
|
|
* @constructor
|
|
*/
|
|
function LocalTransport(config) {
|
|
this.id = config && config.id || null;
|
|
this.networkId = this.id || null;
|
|
this['default'] = config && config['default'] || false;
|
|
this.agents = {};
|
|
}
|
|
|
|
LocalTransport.prototype = new Transport();
|
|
|
|
LocalTransport.prototype.type = 'local';
|
|
|
|
/**
|
|
* Connect an agent
|
|
* @param {String} id
|
|
* @param {Function} receive Invoked as receive(from, message)
|
|
* @return {LocalConnection} Returns a promise which resolves when
|
|
* connected.
|
|
*/
|
|
LocalTransport.prototype.connect = function(id, receive) {
|
|
return new LocalConnection(this, id, receive);
|
|
};
|
|
|
|
/**
|
|
* Close the transport. Removes all agent connections.
|
|
*/
|
|
LocalTransport.prototype.close = function() {
|
|
this.agents = {};
|
|
};
|
|
|
|
module.exports = LocalTransport;
|
|
|
|
},{"./../Transport":10,"./LocalConnection":17}],19:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Promise = _dereq_('promise');
|
|
var Connection = _dereq_('../Connection');
|
|
|
|
/**
|
|
* A connection. The connection is ready when the property .ready resolves.
|
|
* @param {PubNubTransport} transport
|
|
* @param {string | number} id
|
|
* @param {function} receive
|
|
* @constructor
|
|
*/
|
|
function PubNubConnection(transport, id, receive) {
|
|
this.id = id;
|
|
this.transport = transport;
|
|
|
|
// ready state
|
|
var me = this;
|
|
this.ready = new Promise(function (resolve, reject) {
|
|
transport.pubnub.subscribe({
|
|
channel: id,
|
|
message: function (message) {
|
|
receive(message.from, message.message);
|
|
},
|
|
connect: function () {
|
|
resolve(me);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Send a message to an agent.
|
|
* @param {string} to
|
|
* @param {*} message
|
|
* @return {Promise} returns a promise which resolves when the message has been sent
|
|
*/
|
|
PubNubConnection.prototype.send = function (to, message) {
|
|
var me = this;
|
|
return new Promise(function (resolve, reject) {
|
|
me.transport.pubnub.publish({
|
|
channel: to,
|
|
message: {
|
|
from: me.id,
|
|
to: to,
|
|
message: message
|
|
},
|
|
callback: resolve,
|
|
error: reject
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Close the connection
|
|
*/
|
|
PubNubConnection.prototype.close = function () {
|
|
this.transport.pubnub.unsubscribe({
|
|
channel: this.id
|
|
});
|
|
};
|
|
|
|
module.exports = PubNubConnection;
|
|
|
|
},{"../Connection":9,"promise":114}],20:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Transport = _dereq_('./../Transport');
|
|
var PubNubConnection = _dereq_('./PubNubConnection');
|
|
|
|
/**
|
|
* Use pubnub as transport
|
|
* @param {Object} config Config can contain the following properties:
|
|
* - `id: string`. Optional
|
|
* - `publish_key: string`. Required
|
|
* - `subscribe_key: string`. Required
|
|
* @constructor
|
|
*/
|
|
function PubNubTransport(config) {
|
|
this.id = config.id || null;
|
|
this.networkId = config.publish_key || null;
|
|
this['default'] = config['default'] || false;
|
|
this.pubnub = PUBNUB().init(config);
|
|
}
|
|
|
|
PubNubTransport.prototype = new Transport();
|
|
|
|
PubNubTransport.prototype.type = 'pubnub';
|
|
|
|
/**
|
|
* Connect an agent
|
|
* @param {String} id
|
|
* @param {Function} receive Invoked as receive(from, message)
|
|
* @return {PubNubConnection} Returns a connection
|
|
*/
|
|
PubNubTransport.prototype.connect = function(id, receive) {
|
|
return new PubNubConnection(this, id, receive)
|
|
};
|
|
|
|
/**
|
|
* Close the transport.
|
|
*/
|
|
PubNubTransport.prototype.close = function() {
|
|
// FIXME: how to correctly close a pubnub connection?
|
|
this.pubnub = null;
|
|
};
|
|
|
|
/**
|
|
* Load the PubNub library
|
|
* @returns {Object} PUBNUB
|
|
*/
|
|
function PUBNUB() {
|
|
if (typeof window !== 'undefined') {
|
|
// browser
|
|
if (typeof window['PUBNUB'] === 'undefined') {
|
|
throw new Error('Please load pubnub first in the browser');
|
|
}
|
|
return window['PUBNUB'];
|
|
}
|
|
else {
|
|
// node.js
|
|
return _dereq_('pubnub');
|
|
}
|
|
}
|
|
|
|
module.exports = PubNubTransport;
|
|
|
|
},{"./../Transport":10,"./PubNubConnection":19,"pubnub":123}],21:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var uuid = _dereq_('uuid-v4');
|
|
var Promise = _dereq_('promise');
|
|
var WebSocket = (typeof window !== 'undefined' && typeof window.WebSocket !== 'undefined') ?
|
|
window.WebSocket :
|
|
_dereq_('ws');
|
|
|
|
var util = _dereq_('../../util');
|
|
var Connection = _dereq_('../Connection');
|
|
|
|
/**
|
|
* A websocket connection.
|
|
* @param {WebSocketTransport} transport
|
|
* @param {string | number | null} url The url of the agent. The url must match
|
|
* the url of the WebSocket server.
|
|
* If url is null, a UUID id is generated as url.
|
|
* @param {function} receive
|
|
* @constructor
|
|
*/
|
|
function WebSocketConnection(transport, url, receive) {
|
|
this.transport = transport;
|
|
this.url = url ? util.normalizeURL(url) : uuid();
|
|
this.receive = receive;
|
|
|
|
this.sockets = {};
|
|
this.closed = false;
|
|
this.reconnectTimers = {};
|
|
|
|
// ready state
|
|
this.ready = Promise.resolve(this);
|
|
}
|
|
|
|
/**
|
|
* Send a message to an agent.
|
|
* @param {string} to The WebSocket url of the receiver
|
|
* @param {*} message
|
|
* @return {Promise} Returns a promise which resolves when the message is sent,
|
|
* and rejects when sending the message failed
|
|
*/
|
|
WebSocketConnection.prototype.send = function (to, message) {
|
|
//console.log('send', this.url, to, message); // TODO: cleanup
|
|
|
|
// deliver locally when possible
|
|
if (this.transport.localShortcut) {
|
|
var agent = this.transport.agents[to];
|
|
if (agent) {
|
|
try {
|
|
agent.receive(this.url, message);
|
|
return Promise.resolve();
|
|
}
|
|
catch (err) {
|
|
return Promise.reject(err);
|
|
}
|
|
}
|
|
}
|
|
|
|
// get or create a connection
|
|
var conn = this.sockets[to];
|
|
if (conn) {
|
|
try {
|
|
if (conn.readyState == conn.CONNECTING) {
|
|
// the connection is still opening
|
|
return new Promise(function (resolve, reject) {
|
|
conn.onopen.callback.push(function () {
|
|
conn.send(JSON.stringify(message));
|
|
resolve();
|
|
})
|
|
});
|
|
}
|
|
else if (conn.readyState == conn.OPEN) {
|
|
conn.send(JSON.stringify(message));
|
|
return Promise.resolve();
|
|
}
|
|
else {
|
|
// remove the connection
|
|
conn = null;
|
|
}
|
|
}
|
|
catch (err) {
|
|
return Promise.reject(err);
|
|
}
|
|
}
|
|
|
|
if (!conn) {
|
|
// try to open a connection
|
|
var me = this;
|
|
return new Promise(function (resolve, reject) {
|
|
me._connect(to, function (conn) {
|
|
conn.send(JSON.stringify(message));
|
|
resolve();
|
|
}, function (err) {
|
|
reject(new Error('Failed to connect to agent "' + to + '"'));
|
|
});
|
|
})
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Open a websocket connection to an other agent. No messages are sent.
|
|
* @param {string} to Url of the remote agent.
|
|
* @returns {Promise.<WebSocketConnection, Error>}
|
|
* Returns a promise which resolves when the connection is
|
|
* established and rejects in case of an error.
|
|
*/
|
|
WebSocketConnection.prototype.connect = function (to) {
|
|
var me = this;
|
|
return new Promise(function (resolve, reject) {
|
|
me._connect(to, function () {
|
|
resolve(me);
|
|
}, reject);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Open a websocket connection
|
|
* @param {String} to Url of the remote agent
|
|
* @param {function} [callback]
|
|
* @param {function} [errback]
|
|
* @param {boolean} [doReconnect=false]
|
|
* @returns {WebSocket}
|
|
* @private
|
|
*/
|
|
WebSocketConnection.prototype._connect = function (to, callback, errback, doReconnect) {
|
|
var me = this;
|
|
var conn = new WebSocket(to + '?id=' + this.url);
|
|
|
|
// register the new socket
|
|
me.sockets[to] = conn;
|
|
|
|
conn.onopen = function () {
|
|
// Change doReconnect to true as soon as we have had an open connection
|
|
doReconnect = true;
|
|
|
|
conn.onopen.callbacks.forEach(function (cb) {
|
|
cb(conn);
|
|
});
|
|
conn.onopen.callbacks = [];
|
|
};
|
|
conn.onopen.callbacks = callback ? [callback] : [];
|
|
|
|
conn.onmessage = function (event) {
|
|
me.receive(to, JSON.parse(event.data));
|
|
};
|
|
|
|
conn.onclose = function () {
|
|
delete me.sockets[to];
|
|
if (doReconnect) {
|
|
me._reconnect(to);
|
|
}
|
|
};
|
|
|
|
conn.onerror = function (err) {
|
|
delete me.sockets[to];
|
|
if (errback) {
|
|
errback(err);
|
|
}
|
|
};
|
|
|
|
return conn;
|
|
};
|
|
|
|
/**
|
|
* Auto reconnect a broken connection
|
|
* @param {String} to Url of the remote agent
|
|
* @private
|
|
*/
|
|
WebSocketConnection.prototype._reconnect = function (to) {
|
|
var me = this;
|
|
var doReconnect = true;
|
|
if (me.closed == false && me.reconnectTimers[to] == null) {
|
|
me.reconnectTimers[to] = setTimeout(function () {
|
|
delete me.reconnectTimers[to];
|
|
me._connect(to, null, null, doReconnect);
|
|
}, me.transport.reconnectDelay);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Register a websocket connection
|
|
* @param {String} from Url of the remote agent
|
|
* @param {WebSocket} conn WebSocket connection
|
|
* @returns {WebSocket} Returns the websocket itself
|
|
* @private
|
|
*/
|
|
WebSocketConnection.prototype._onConnection = function (from, conn) {
|
|
var me = this;
|
|
|
|
conn.onmessage = function (event) {
|
|
me.receive(from, JSON.parse(event.data));
|
|
};
|
|
|
|
conn.onclose = function () {
|
|
// remove this connection from the sockets list
|
|
delete me.sockets[from];
|
|
};
|
|
|
|
conn.onerror = function (err) {
|
|
// TODO: what to do with errors?
|
|
delete me.sockets[from];
|
|
};
|
|
|
|
if (this.sockets[from]) {
|
|
// there is already a connection open with remote agent
|
|
// TODO: what to do with overwriting existing sockets?
|
|
this.sockets[from].close();
|
|
}
|
|
|
|
// register new connection
|
|
this.sockets[from] = conn;
|
|
|
|
return conn;
|
|
};
|
|
|
|
/**
|
|
* Get a list with all open sockets
|
|
* @return {String[]} Returns all open sockets
|
|
*/
|
|
WebSocketConnection.prototype.list = function () {
|
|
return Object.keys(this.sockets);
|
|
};
|
|
|
|
/**
|
|
* Close the connection. All open sockets will be closed and the agent will
|
|
* be unregistered from the WebSocketTransport.
|
|
*/
|
|
WebSocketConnection.prototype.close = function () {
|
|
this.closed = true;
|
|
|
|
// close all connections
|
|
for (var id in this.sockets) {
|
|
if (this.sockets.hasOwnProperty(id)) {
|
|
this.sockets[id].close();
|
|
}
|
|
}
|
|
this.sockets = {};
|
|
|
|
delete this.transport.agents[this.url];
|
|
};
|
|
|
|
module.exports = WebSocketConnection;
|
|
|
|
},{"../../util":23,"../Connection":9,"promise":114,"uuid-v4":125,"ws":126}],22:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var urlModule = _dereq_('url');
|
|
var uuid = _dereq_('uuid-v4');
|
|
var Promise = _dereq_('promise');
|
|
var WebSocketServer = _dereq_('ws').Server;
|
|
|
|
var util = _dereq_('../../util');
|
|
var Transport = _dereq_('../Transport');
|
|
var WebSocketConnection = _dereq_('./WebSocketConnection');
|
|
|
|
/**
|
|
* Create a web socket transport.
|
|
* @param {Object} config Config can contain the following properties:
|
|
* - `id: string`. Optional
|
|
* - `default: boolean`. Optional
|
|
* - `url: string`. Optional. If provided,
|
|
* A WebSocket server is started on given
|
|
* url.
|
|
* - `localShortcut: boolean`. Optional. If true
|
|
* (default), messages to local agents are not
|
|
* send via WebSocket but delivered immediately
|
|
* - `reconnectDelay: number` Optional. Delay in
|
|
* milliseconds for reconnecting a broken
|
|
* connection. 10000 ms by default. Connections
|
|
* are only automatically reconnected after
|
|
* there has been an established connection.
|
|
* @constructor
|
|
*/
|
|
function WebSocketTransport(config) {
|
|
this.id = config && config.id || null;
|
|
this.networkId = this.id || null;
|
|
this['default'] = config && config['default'] || false;
|
|
this.localShortcut = (config && config.localShortcut === false) ? false : true;
|
|
this.reconnectDelay = config && config.reconnectDelay || 10000;
|
|
|
|
this.url = config && config.url || null;
|
|
this.server = null;
|
|
|
|
if (this.url != null) {
|
|
var urlParts = urlModule.parse(this.url);
|
|
|
|
if (urlParts.protocol != 'ws:') throw new Error('Invalid protocol, "ws:" expected');
|
|
if (this.url.indexOf(':id') == -1) throw new Error('":id" placeholder missing in url');
|
|
|
|
this.address = urlParts.protocol + '//' + urlParts.host; // the url without path, for example 'ws://localhost:3000'
|
|
this.ready = this._initServer(this.url);
|
|
}
|
|
else {
|
|
this.address = null;
|
|
this.ready = Promise.resolve(this);
|
|
}
|
|
|
|
this.agents = {}; // WebSocketConnections of all registered agents. The keys are the urls of the agents
|
|
}
|
|
|
|
WebSocketTransport.prototype = new Transport();
|
|
|
|
WebSocketTransport.prototype.type = 'ws';
|
|
|
|
/**
|
|
* Build an url for given id. Example:
|
|
* var url = getUrl('agent1'); // 'ws://localhost:3000/agents/agent1'
|
|
* @param {String} id
|
|
* @return {String} Returns the url, or returns null when no url placeholder
|
|
* is defined.
|
|
*/
|
|
WebSocketTransport.prototype.getUrl = function (id) {
|
|
return this.url ? this.url.replace(':id', id) : null;
|
|
};
|
|
|
|
/**
|
|
* Initialize a server on given url
|
|
* @param {String} url For example 'http://localhost:3000'
|
|
* @return {Promise} Returns a promise which resolves when the server is up
|
|
* and running
|
|
* @private
|
|
*/
|
|
WebSocketTransport.prototype._initServer = function (url) {
|
|
var urlParts = urlModule.parse(url);
|
|
var port = urlParts.port || 80;
|
|
|
|
var me = this;
|
|
return new Promise(function (resolve, reject) {
|
|
me.server = new WebSocketServer({port: port}, function () {
|
|
resolve(me);
|
|
});
|
|
|
|
me.server.on('connection', me._onConnection.bind(me));
|
|
|
|
me.server.on('error', function (err) {
|
|
reject(err)
|
|
});
|
|
})
|
|
};
|
|
|
|
/**
|
|
* Handle a new connection. The connection is added to the addressed agent.
|
|
* @param {WebSocket} conn
|
|
* @private
|
|
*/
|
|
WebSocketTransport.prototype._onConnection = function (conn) {
|
|
var url = conn.upgradeReq.url;
|
|
var urlParts = urlModule.parse(url, true);
|
|
var toPath = urlParts.pathname;
|
|
var to = util.normalizeURL(this.address + toPath);
|
|
|
|
// read sender id from query parameters or generate a random uuid
|
|
var queryParams = urlParts.query;
|
|
var from = queryParams.id || uuid();
|
|
// TODO: make a config option to allow/disallow anonymous connections?
|
|
//console.log('onConnection, to=', to, ', from=', from, ', agents:', Object.keys(this.agents)); // TODO: cleanup
|
|
|
|
var agent = this.agents[to];
|
|
if (agent) {
|
|
agent._onConnection(from, conn);
|
|
}
|
|
else {
|
|
// reject the connection
|
|
// conn.send('Error: Agent with id "' + to + '" not found'); // TODO: can we send back a message before closing?
|
|
conn.close();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Connect an agent
|
|
* @param {string} id The id or url of the agent. In case of an
|
|
* url, this url should match the url of the
|
|
* WebSocket server.
|
|
* @param {Function} receive Invoked as receive(from, message)
|
|
* @return {WebSocketConnection} Returns a promise which resolves when
|
|
* connected.
|
|
*/
|
|
WebSocketTransport.prototype.connect = function(id, receive) {
|
|
var isURL = (id.indexOf('://') !== -1);
|
|
|
|
// FIXME: it's confusing right now what the final url will be based on the provided id...
|
|
var url = isURL ? id : (this.getUrl(id) || id);
|
|
if (url) url = util.normalizeURL(url);
|
|
|
|
// register the agents receive function
|
|
if (this.agents[url]) {
|
|
throw new Error('Agent with id ' + this.id + ' already exists');
|
|
}
|
|
|
|
var conn = new WebSocketConnection(this, url, receive);
|
|
this.agents[conn.url] = conn; // use conn.url, url can be changed when it was null
|
|
|
|
return conn;
|
|
};
|
|
|
|
/**
|
|
* Close the transport. Removes all agent connections.
|
|
*/
|
|
WebSocketTransport.prototype.close = function() {
|
|
// close all connections
|
|
for (var id in this.agents) {
|
|
if (this.agents.hasOwnProperty(id)) {
|
|
this.agents[id].close();
|
|
}
|
|
}
|
|
this.agents = {};
|
|
|
|
// close the server
|
|
if (this.server) {
|
|
this.server.close();
|
|
}
|
|
};
|
|
|
|
module.exports = WebSocketTransport;
|
|
|
|
},{"../../util":23,"../Transport":10,"./WebSocketConnection":21,"promise":114,"url":157,"uuid-v4":125,"ws":126}],23:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
/**
|
|
* Test whether the provided value is a Promise.
|
|
* A value is marked as a Promise when it is an object containing functions
|
|
* `then` and `catch`.
|
|
* @param {*} value
|
|
* @return {boolean} Returns true when `value` is a Promise
|
|
*/
|
|
exports.isPromise = function (value) {
|
|
return value &&
|
|
typeof value['then'] === 'function' &&
|
|
typeof value['catch'] === 'function'
|
|
};
|
|
|
|
/**
|
|
* Splits an url like "protocol://domain/path"
|
|
* @param {string} url
|
|
* @return {{protocol: string, domain: string, path: string} | null}
|
|
* Returns an object with properties protocol, domain, and path
|
|
* when there is a match. Returns null if no valid url.
|
|
*
|
|
*/
|
|
exports.parseUrl = function (url) {
|
|
// match an url like "protocol://domain/path"
|
|
var match = /^([A-z]+):\/\/([^\/]+)(\/(.*)$|$)/.exec(url);
|
|
if (match) {
|
|
return {
|
|
protocol: match[1],
|
|
domain: match[2],
|
|
path: match[4]
|
|
}
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Normalize a url. Removes trailing slash
|
|
* @param {string} url
|
|
* @return {string} Returns the normalized url
|
|
*/
|
|
exports.normalizeURL = function (url) {
|
|
if (url[url.length - 1] == '/') {
|
|
return url.substring(0, url.length - 1);
|
|
}
|
|
else {
|
|
return url;
|
|
}
|
|
};
|
|
|
|
},{}],24:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
var Connection = _dereq_('./lib/connection');
|
|
|
|
module.exports = {
|
|
Connection: Connection,
|
|
createConnection: function (options, implOptions, readyCallback) {
|
|
var c = new Connection(options, implOptions, readyCallback);
|
|
c.connect();
|
|
return c;
|
|
}
|
|
};
|
|
|
|
},{"./lib/connection":28}],25:[function(_dereq_,module,exports){
|
|
// Copyright (c) 2008, Fair Oaks Labs, Inc.
|
|
// All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without modification, are
|
|
// permitted provided that the following conditions are met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright notice, this list
|
|
// of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above copyright notice, this
|
|
// list of conditions and the following disclaimer in the documentation and/or other
|
|
// materials provided with the distribution.
|
|
// * Neither the name of Fair Oaks Labs, Inc. nor the names of its contributors may be
|
|
// used to endorse or promote products derived from this software without specific
|
|
// prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
|
// THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
|
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
// Modified from original JSPack <cbond@positrace.com>
|
|
exports.jspack = function (bigEndian) {
|
|
this.bigEndian = bigEndian;
|
|
}
|
|
|
|
exports.jspack.prototype._DeArray = function (a, p, l) {
|
|
return [a.slice(p, p + l)];
|
|
};
|
|
|
|
exports.jspack.prototype._EnArray = function (a, p, l, v) {
|
|
for (var i = 0; i < l; ++i) {
|
|
a[p + i] = v[i] ? v[i] : 0;
|
|
}
|
|
};
|
|
|
|
exports.jspack.prototype._DeChar = function (a, p) {
|
|
return String.fromCharCode(a[p]);
|
|
};
|
|
|
|
exports.jspack.prototype._EnChar = function (a, p, v) {
|
|
a[p] = v.charCodeAt(0);
|
|
};
|
|
|
|
exports.jspack.prototype._DeInt = function (a, p) {
|
|
var lsb = bigEndian ? format.len - 1 : 0;
|
|
var nsb = bigEndian ? -1 : 1;
|
|
var stp = lsb + nsb * format.len,
|
|
rv;
|
|
var ret = 0;
|
|
|
|
var i = lsb;
|
|
var f = 1;
|
|
while (i != stp) {
|
|
rv += a[p + i] * f;
|
|
i += nsb;
|
|
f *= 256;
|
|
}
|
|
|
|
if (format.signed) {
|
|
if ((rv & Math.pow(2, format.len * 8 - 1)) != 0) {
|
|
rv -= Math.pow(2, format.len * 8);
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
};
|
|
|
|
exports.jspack.prototype._EnInt = function (a, p, v) {
|
|
var lsb = bigEndian ? format.len - 1 : 0;
|
|
var nsb = bigEndian ? -1 : 1;
|
|
var stp = lsb + nsb * format.len;
|
|
|
|
v = v < format.min ? format.min : ((v > format.max) ? format.max : v);
|
|
|
|
var i = lsb;
|
|
while (i != stp) {
|
|
a[p + i] = v & 0xff;
|
|
i += nsb;
|
|
v >>= 8;
|
|
}
|
|
};
|
|
|
|
exports.jspack.prototype._DeString = function (a, p, l) {
|
|
var rv = new Array(1);
|
|
|
|
for (i = 0; i < l; i++) {
|
|
rv[i] = String.fromCharCode(a[p + i]);
|
|
}
|
|
|
|
return rv.join('');
|
|
};
|
|
|
|
exports.jspack.prototype._EnString = function (a, p, l, v) {
|
|
for (var t, i = 0; i < l; ++i) {
|
|
t = v.charCodeAt(i);
|
|
if (!t) t = 0;
|
|
|
|
a[p + i] = t;
|
|
}
|
|
};
|
|
|
|
exports.jspack.prototype._De754 = function (a, p) {
|
|
var s, e, m, i, d, bits, bit, len, bias, max;
|
|
|
|
bit = format.bit;
|
|
len = format.len * 8 - format.bit - 1;
|
|
max = (1 << len) - 1;
|
|
bias = max >> 1;
|
|
|
|
i = bigEndian ? 0 : format.len - 1;
|
|
d = bigEndian ? 1 : -1;;
|
|
s = a[p + i];
|
|
i = i + d;
|
|
|
|
bits = -7;
|
|
|
|
e = s & ((1 << -bits) - 1);
|
|
s >>= -bits;
|
|
|
|
for (bits += len; bits > 0; bits -= 8) {
|
|
e = e * 256 + a[p + i];
|
|
i += d;
|
|
}
|
|
|
|
m = e & ((1 << -bits) - 1);
|
|
e >>= -bits;
|
|
|
|
for (bits += bit; bits > 0; bits -= 8) {
|
|
m = m * 256 + a[p + i];
|
|
i += d;
|
|
}
|
|
|
|
switch (e) {
|
|
case 0:
|
|
// Zero, or denormalized number
|
|
e = 1 - bias;
|
|
break;
|
|
|
|
case max:
|
|
// NaN, or +/-Infinity
|
|
return m ? NaN : ((s ? -1 : 1) * Infinity);
|
|
|
|
default:
|
|
// Normalized number
|
|
m = m + Math.pow(2, bit);
|
|
e = e - bias;
|
|
break;
|
|
}
|
|
|
|
return (s ? -1 : 1) * m * Math.pow(2, e - bit);
|
|
};
|
|
|
|
exports.jspack.prototype._En754 = function (a, p, v) {
|
|
var s, e, m, i, d, c, bit, len, bias, max;
|
|
|
|
bit = format.bit;
|
|
len = format.len * 8 - format.bit - 1;
|
|
max = (1 << len) - 1;
|
|
bias = max >> 1;
|
|
|
|
s = v < 0 ? 1 : 0;
|
|
v = Math.abs(v);
|
|
|
|
if (isNaN(v) || (v == Infinity)) {
|
|
m = isNaN(v) ? 1 : 0;
|
|
e = max;
|
|
} else {
|
|
e = Math.floor(Math.log(v) / Math.LN2); // Calculate log2 of the value
|
|
c = Math.pow(2, -e);
|
|
if (v * c < 1) {
|
|
e--;
|
|
c = c * 2;
|
|
}
|
|
|
|
// Round by adding 1/2 the significand's LSD
|
|
if (e + bias >= 1) {
|
|
v += format.rt / c; // Normalized: bit significand digits
|
|
} else {
|
|
v += format.rt * Math.pow(2, 1 - bias); // Denormalized: <= bit significand digits
|
|
}
|
|
if (v * c >= 2) {
|
|
e++;
|
|
c = c / 2; // Rounding can increment the exponent
|
|
}
|
|
|
|
if (e + bias >= max) { // overflow
|
|
m = 0;
|
|
e = max;
|
|
} else if (e + bias >= 1) { // normalized
|
|
m = (v * c - 1) * Math.pow(2, bit); // do not reorder this expression
|
|
e = e + bias;
|
|
} else {
|
|
// Denormalized - also catches the '0' case, somewhat by chance
|
|
m = v * Math.pow(2, bias - 1) * Math.pow(2, bit);
|
|
e = 0;
|
|
}
|
|
}
|
|
|
|
i = bigEndian ? format.len - 1 : 0;
|
|
d = bigEndian ? -1 : 1;;
|
|
|
|
while (bit >= 8) {
|
|
a[p + i] = m & 0xff;
|
|
i += d;
|
|
m /= 256;
|
|
bit -= 8;
|
|
}
|
|
|
|
e = (e << bit) | m;
|
|
for (len += bit; len > 0; len -= 8) {
|
|
a[p + i] = e & 0xff;
|
|
i += d;
|
|
e /= 256;
|
|
}
|
|
|
|
a[p + i - d] |= s * 128;
|
|
};
|
|
|
|
// Unpack a series of n formatements of size s from array a at offset p with fxn
|
|
exports.jspack.prototype._UnpackSeries = function (n, s, a, p) {
|
|
var fxn = format.de;
|
|
|
|
var ret = [];
|
|
for (var i = 0; i < n; i++) {
|
|
ret.push(fxn(a, p + i * s));
|
|
}
|
|
|
|
return ret;
|
|
};
|
|
|
|
// Pack a series of n formatements of size s from array v at offset i to array a at offset p with fxn
|
|
exports.jspack.prototype._PackSeries = function (n, s, a, p, v, i) {
|
|
var fxn = format.en;
|
|
|
|
for (o = 0; o < n; o++) {
|
|
fxn(a, p + o * s, v[i + o]);
|
|
}
|
|
};
|
|
|
|
// Unpack the octet array a, beginning at offset p, according to the fmt string
|
|
exports.jspack.prototype.Unpack = function (fmt, a, p) {
|
|
bigEndian = fmt.charAt(0) != '<';
|
|
|
|
if (p == undefined || p == null) p = 0;
|
|
|
|
var re = new RegExp(this._sPattern, 'g');
|
|
|
|
var ret = [];
|
|
|
|
for (var m; m = re.exec(fmt); /* */ ) {
|
|
var n;
|
|
if (m[1] == undefined || m[1] == '') n = 1;
|
|
else n = parseInt(m[1]);
|
|
|
|
var s = this._lenLut[m[2]];
|
|
|
|
if ((p + n * s) > a.length) return undefined;
|
|
|
|
switch (m[2]) {
|
|
case 'A':
|
|
case 's':
|
|
rv.push(this._formatLut[m[2]].de(a, p, n));
|
|
break;
|
|
case 'c':
|
|
case 'b':
|
|
case 'B':
|
|
case 'h':
|
|
case 'H':
|
|
case 'i':
|
|
case 'I':
|
|
case 'l':
|
|
case 'L':
|
|
case 'f':
|
|
case 'd':
|
|
format = this._formatLut[m[2]];
|
|
ret.push(this._UnpackSeries(n, s, a, p));
|
|
break;
|
|
}
|
|
|
|
p += n * s;
|
|
}
|
|
|
|
return Array.prototype.concat.apply([], ret);
|
|
};
|
|
|
|
// Pack the supplied values into the octet array a, beginning at offset p, according to the fmt string
|
|
exports.jspack.prototype.PackTo = function (fmt, a, p, values) {
|
|
bigEndian = (fmt.charAt(0) != '<');
|
|
|
|
var re = new RegExp(this._sPattern, 'g');
|
|
|
|
for (var m, i = 0; m = re.exec(fmt); /* */ ) {
|
|
var n;
|
|
if (m[1] == undefined || m[1] == '') n = 1;
|
|
else n = parseInt(m[1]);
|
|
|
|
var s = this._lenLut[m[2]];
|
|
|
|
if ((p + n * s) > a.length) return false;
|
|
|
|
switch (m[2]) {
|
|
case 'A':
|
|
case 's':
|
|
if ((i + 1) > values.length) return false;
|
|
|
|
this._formatLut[m[2]].en(a, p, n, values[i]);
|
|
|
|
i += 1;
|
|
break;
|
|
|
|
case 'c':
|
|
case 'b':
|
|
case 'B':
|
|
case 'h':
|
|
case 'H':
|
|
case 'i':
|
|
case 'I':
|
|
case 'l':
|
|
case 'L':
|
|
case 'f':
|
|
case 'd':
|
|
format = this._formatLut[m[2]];
|
|
|
|
if (i + n > values.length) return false;
|
|
|
|
this._PackSeries(n, s, a, p, values, i);
|
|
|
|
i += n;
|
|
break;
|
|
|
|
case 'x':
|
|
for (var j = 0; j < n; j++) {
|
|
a[p + j] = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
p += n * s;
|
|
}
|
|
|
|
return a;
|
|
};
|
|
|
|
// Pack the supplied values into a new octet array, according to the fmt string
|
|
exports.jspack.prototype.Pack = function (fmt, values) {
|
|
return this.PackTo(fmt, new Array(this.CalcLength(fmt)), 0, values);
|
|
};
|
|
|
|
// Determine the number of bytes represented by the format string
|
|
exports.jspack.prototype.CalcLength = function (fmt) {
|
|
var re = new RegExp(this._sPattern, 'g');
|
|
var sz = 0;
|
|
|
|
while (match = re.exec(fmt)) {
|
|
var n;
|
|
if (match[1] == undefined || match[1] == '') n = 1;
|
|
else n = parseInt(match[1]);
|
|
|
|
sz += n * this._lenLut[match[2]];
|
|
}
|
|
|
|
return sz;
|
|
};
|
|
|
|
// Regular expression for counting digits
|
|
exports.jspack.prototype._sPattern = '(\\d+)?([AxcbBhHsfdiIlL])';
|
|
|
|
// Byte widths for associated formats
|
|
exports.jspack.prototype._lenLut = {
|
|
'A': 1,
|
|
'x': 1,
|
|
'c': 1,
|
|
'b': 1,
|
|
'B': 1,
|
|
'h': 2,
|
|
'H': 2,
|
|
's': 1,
|
|
'f': 4,
|
|
'd': 8,
|
|
'i': 4,
|
|
'I': 4,
|
|
'l': 4,
|
|
'L': 4
|
|
};
|
|
|
|
exports.jspack.prototype._formatLut = {
|
|
'A': {
|
|
en: exports.jspack.prototype._EnArray,
|
|
de: exports.jspack.prototype._DeArray
|
|
},
|
|
's': {
|
|
en: exports.jspack.prototype._EnString,
|
|
de: exports.jspack.prototype._DeString
|
|
},
|
|
'c': {
|
|
en: exports.jspack.prototype._EnChar,
|
|
de: exports.jspack.prototype._DeChar
|
|
},
|
|
'b': {
|
|
en: exports.jspack.prototype._EnInt,
|
|
de: exports.jspack.prototype._DeInt,
|
|
len: 1,
|
|
signed: true,
|
|
min: -Math.pow(2, 7),
|
|
max: Math.pow(2, 7) - 1
|
|
},
|
|
'B': {
|
|
en: exports.jspack.prototype._EnInt,
|
|
de: exports.jspack.prototype._DeInt,
|
|
len: 1,
|
|
signed: false,
|
|
min: 0,
|
|
max: Math.pow(2, 8) - 1
|
|
},
|
|
'h': {
|
|
en: exports.jspack.prototype._EnInt,
|
|
de: exports.jspack.prototype._DeInt,
|
|
len: 2,
|
|
signed: true,
|
|
min: -Math.pow(2, 15),
|
|
max: Math.pow(2, 15) - 1
|
|
},
|
|
'H': {
|
|
en: exports.jspack.prototype._EnInt,
|
|
de: exports.jspack.prototype._DeInt,
|
|
len: 2,
|
|
signed: false,
|
|
min: 0,
|
|
max: Math.pow(2, 16) - 1
|
|
},
|
|
'i': {
|
|
en: exports.jspack.prototype._EnInt,
|
|
de: exports.jspack.prototype._DeInt,
|
|
len: 4,
|
|
signed: true,
|
|
min: -Math.pow(2, 31),
|
|
max: Math.pow(2, 31) - 1
|
|
},
|
|
'I': {
|
|
en: exports.jspack.prototype._EnInt,
|
|
de: exports.jspack.prototype._DeInt,
|
|
len: 4,
|
|
signed: false,
|
|
min: 0,
|
|
max: Math.pow(2, 32) - 1
|
|
},
|
|
'l': {
|
|
en: exports.jspack.prototype._EnInt,
|
|
de: exports.jspack.prototype._DeInt,
|
|
len: 4,
|
|
signed: true,
|
|
min: -Math.pow(2, 31),
|
|
max: Math.pow(2, 31) - 1
|
|
},
|
|
'L': {
|
|
en: exports.jspack.prototype._EnInt,
|
|
de: exports.jspack.prototype._DeInt,
|
|
len: 4,
|
|
signed: false,
|
|
min: 0,
|
|
max: Math.pow(2, 32) - 1
|
|
},
|
|
'f': {
|
|
en: exports.jspack.prototype._En754,
|
|
de: exports.jspack.prototype._De754,
|
|
len: 4,
|
|
bit: 23,
|
|
rt: Math.pow(2, -24) - Math.pow(2, -77)
|
|
},
|
|
'd': {
|
|
en: exports.jspack.prototype._En754,
|
|
de: exports.jspack.prototype._De754,
|
|
len: 8,
|
|
bit: 52,
|
|
rt: 0
|
|
}
|
|
};
|
|
|
|
},{}],26:[function(_dereq_,module,exports){
|
|
exports.constants = [
|
|
[1, "frameMethod"],
|
|
[2, "frameHeader"],
|
|
[3, "frameBody"],
|
|
[8, "frameHeartbeat"],
|
|
[200, "replySuccess"],
|
|
[206, "frameEnd"],
|
|
[311, "contentTooLarge"],
|
|
[313, "noConsumers"],
|
|
[320, "connectionForced"],
|
|
[402, "invalidPath"],
|
|
[403, "accessRefused"],
|
|
[404, "notFound"],
|
|
[405, "resourceLocked"],
|
|
[406, "preconditionFailed"],
|
|
[501, "frameError"],
|
|
[502, "syntaxError"],
|
|
[503, "commandInvalid"],
|
|
[504, "channelError"],
|
|
[505, "unexpectedFrame"],
|
|
[506, "resourceError"],
|
|
[530, "notAllowed"],
|
|
[540, "notImplemented"],
|
|
[541, "internalError"],
|
|
[4096, "frameMinSize"]
|
|
];
|
|
exports.classes = [{
|
|
"name": "connection",
|
|
"index": 10,
|
|
"fields": [],
|
|
"methods": [{
|
|
"name": "start",
|
|
"index": 10,
|
|
"fields": [{
|
|
"name": "versionMajor",
|
|
"domain": "octet"
|
|
}, {
|
|
"name": "versionMinor",
|
|
"domain": "octet"
|
|
}, {
|
|
"name": "serverProperties",
|
|
"domain": "table"
|
|
}, {
|
|
"name": "mechanisms",
|
|
"domain": "longstr"
|
|
}, {
|
|
"name": "locales",
|
|
"domain": "longstr"
|
|
}]
|
|
}, {
|
|
"name": "startOk",
|
|
"index": 11,
|
|
"fields": [{
|
|
"name": "clientProperties",
|
|
"domain": "table"
|
|
}, {
|
|
"name": "mechanism",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "response",
|
|
"domain": "longstr"
|
|
}, {
|
|
"name": "locale",
|
|
"domain": "shortstr"
|
|
}]
|
|
}, {
|
|
"name": "secure",
|
|
"index": 20,
|
|
"fields": [{
|
|
"name": "challenge",
|
|
"domain": "longstr"
|
|
}]
|
|
}, {
|
|
"name": "secureOk",
|
|
"index": 21,
|
|
"fields": [{
|
|
"name": "response",
|
|
"domain": "longstr"
|
|
}]
|
|
}, {
|
|
"name": "tune",
|
|
"index": 30,
|
|
"fields": [{
|
|
"name": "channelMax",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "frameMax",
|
|
"domain": "long"
|
|
}, {
|
|
"name": "heartbeat",
|
|
"domain": "short"
|
|
}]
|
|
}, {
|
|
"name": "tuneOk",
|
|
"index": 31,
|
|
"fields": [{
|
|
"name": "channelMax",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "frameMax",
|
|
"domain": "long"
|
|
}, {
|
|
"name": "heartbeat",
|
|
"domain": "short"
|
|
}]
|
|
}, {
|
|
"name": "open",
|
|
"index": 40,
|
|
"fields": [{
|
|
"name": "virtualHost",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "reserved1",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "reserved2",
|
|
"domain": "bit"
|
|
}]
|
|
}, {
|
|
"name": "openOk",
|
|
"index": 41,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "shortstr"
|
|
}]
|
|
}, {
|
|
"name": "close",
|
|
"index": 50,
|
|
"fields": [{
|
|
"name": "replyCode",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "replyText",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "classId",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "methodId",
|
|
"domain": "short"
|
|
}]
|
|
}, {
|
|
"name": "closeOk",
|
|
"index": 51,
|
|
"fields": []
|
|
}]
|
|
}, {
|
|
"name": "channel",
|
|
"index": 20,
|
|
"fields": [],
|
|
"methods": [{
|
|
"name": "open",
|
|
"index": 10,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "shortstr"
|
|
}]
|
|
}, {
|
|
"name": "openOk",
|
|
"index": 11,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "longstr"
|
|
}]
|
|
}, {
|
|
"name": "flow",
|
|
"index": 20,
|
|
"fields": [{
|
|
"name": "active",
|
|
"domain": "bit"
|
|
}]
|
|
}, {
|
|
"name": "flowOk",
|
|
"index": 21,
|
|
"fields": [{
|
|
"name": "active",
|
|
"domain": "bit"
|
|
}]
|
|
}, {
|
|
"name": "close",
|
|
"index": 40,
|
|
"fields": [{
|
|
"name": "replyCode",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "replyText",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "classId",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "methodId",
|
|
"domain": "short"
|
|
}]
|
|
}, {
|
|
"name": "closeOk",
|
|
"index": 41,
|
|
"fields": []
|
|
}]
|
|
}, {
|
|
"name": "exchange",
|
|
"index": 40,
|
|
"fields": [],
|
|
"methods": [{
|
|
"name": "declare",
|
|
"index": 10,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "exchange",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "type",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "passive",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "durable",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "autoDelete",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "reserved2",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "reserved3",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "noWait",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "arguments",
|
|
"domain": "table"
|
|
}]
|
|
}, {
|
|
"name": "declareOk",
|
|
"index": 11,
|
|
"fields": []
|
|
}, {
|
|
"name": "delete",
|
|
"index": 20,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "exchange",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "ifUnused",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "noWait",
|
|
"domain": "bit"
|
|
}]
|
|
}, {
|
|
"name": "deleteOk",
|
|
"index": 21,
|
|
"fields": []
|
|
}, {
|
|
"name": "bind",
|
|
"index": 30,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "destination",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "source",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "routingKey",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "noWait",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "arguments",
|
|
"domain": "table"
|
|
}]
|
|
}, {
|
|
"name": "bindOk",
|
|
"index": 31,
|
|
"fields": []
|
|
}, {
|
|
"name": "unbind",
|
|
"index": 40,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "destination",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "source",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "routingKey",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "noWait",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "arguments",
|
|
"domain": "table"
|
|
}]
|
|
}, {
|
|
"name": "unbindOk",
|
|
"index": 51,
|
|
"fields": []
|
|
}]
|
|
}, {
|
|
"name": "queue",
|
|
"index": 50,
|
|
"fields": [],
|
|
"methods": [{
|
|
"name": "declare",
|
|
"index": 10,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "queue",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "passive",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "durable",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "exclusive",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "autoDelete",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "noWait",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "arguments",
|
|
"domain": "table"
|
|
}]
|
|
}, {
|
|
"name": "declareOk",
|
|
"index": 11,
|
|
"fields": [{
|
|
"name": "queue",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "messageCount",
|
|
"domain": "long"
|
|
}, {
|
|
"name": "consumerCount",
|
|
"domain": "long"
|
|
}]
|
|
}, {
|
|
"name": "bind",
|
|
"index": 20,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "queue",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "exchange",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "routingKey",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "noWait",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "arguments",
|
|
"domain": "table"
|
|
}]
|
|
}, {
|
|
"name": "bindOk",
|
|
"index": 21,
|
|
"fields": []
|
|
}, {
|
|
"name": "unbind",
|
|
"index": 50,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "queue",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "exchange",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "routingKey",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "arguments",
|
|
"domain": "table"
|
|
}]
|
|
}, {
|
|
"name": "unbindOk",
|
|
"index": 51,
|
|
"fields": []
|
|
}, {
|
|
"name": "purge",
|
|
"index": 30,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "queue",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "noWait",
|
|
"domain": "bit"
|
|
}]
|
|
}, {
|
|
"name": "purgeOk",
|
|
"index": 31,
|
|
"fields": [{
|
|
"name": "messageCount",
|
|
"domain": "long"
|
|
}]
|
|
}, {
|
|
"name": "delete",
|
|
"index": 40,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "queue",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "ifUnused",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "ifEmpty",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "noWait",
|
|
"domain": "bit"
|
|
}]
|
|
}, {
|
|
"name": "deleteOk",
|
|
"index": 41,
|
|
"fields": [{
|
|
"name": "messageCount",
|
|
"domain": "long"
|
|
}]
|
|
}]
|
|
}, {
|
|
"name": "basic",
|
|
"index": 60,
|
|
"fields": [{
|
|
"name": "contentType",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "contentEncoding",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "headers",
|
|
"domain": "table"
|
|
}, {
|
|
"name": "deliveryMode",
|
|
"domain": "octet"
|
|
}, {
|
|
"name": "priority",
|
|
"domain": "octet"
|
|
}, {
|
|
"name": "correlationId",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "replyTo",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "expiration",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "messageId",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "timestamp",
|
|
"domain": "timestamp"
|
|
}, {
|
|
"name": "type",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "userId",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "appId",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "reserved",
|
|
"domain": "shortstr"
|
|
}],
|
|
"methods": [{
|
|
"name": "qos",
|
|
"index": 10,
|
|
"fields": [{
|
|
"name": "prefetchSize",
|
|
"domain": "long"
|
|
}, {
|
|
"name": "prefetchCount",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "global",
|
|
"domain": "bit"
|
|
}]
|
|
}, {
|
|
"name": "qosOk",
|
|
"index": 11,
|
|
"fields": []
|
|
}, {
|
|
"name": "consume",
|
|
"index": 20,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "queue",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "consumerTag",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "noLocal",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "noAck",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "exclusive",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "noWait",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "arguments",
|
|
"domain": "table"
|
|
}]
|
|
}, {
|
|
"name": "consumeOk",
|
|
"index": 21,
|
|
"fields": [{
|
|
"name": "consumerTag",
|
|
"domain": "shortstr"
|
|
}]
|
|
}, {
|
|
"name": "cancel",
|
|
"index": 30,
|
|
"fields": [{
|
|
"name": "consumerTag",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "noWait",
|
|
"domain": "bit"
|
|
}]
|
|
}, {
|
|
"name": "cancelOk",
|
|
"index": 31,
|
|
"fields": [{
|
|
"name": "consumerTag",
|
|
"domain": "shortstr"
|
|
}]
|
|
}, {
|
|
"name": "publish",
|
|
"index": 40,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "exchange",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "routingKey",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "mandatory",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "immediate",
|
|
"domain": "bit"
|
|
}]
|
|
}, {
|
|
"name": "return",
|
|
"index": 50,
|
|
"fields": [{
|
|
"name": "replyCode",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "replyText",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "exchange",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "routingKey",
|
|
"domain": "shortstr"
|
|
}]
|
|
}, {
|
|
"name": "deliver",
|
|
"index": 60,
|
|
"fields": [{
|
|
"name": "consumerTag",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "deliveryTag",
|
|
"domain": "longlong"
|
|
}, {
|
|
"name": "redelivered",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "exchange",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "routingKey",
|
|
"domain": "shortstr"
|
|
}]
|
|
}, {
|
|
"name": "get",
|
|
"index": 70,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "short"
|
|
}, {
|
|
"name": "queue",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "noAck",
|
|
"domain": "bit"
|
|
}]
|
|
}, {
|
|
"name": "getOk",
|
|
"index": 71,
|
|
"fields": [{
|
|
"name": "deliveryTag",
|
|
"domain": "longlong"
|
|
}, {
|
|
"name": "redelivered",
|
|
"domain": "bit"
|
|
}, {
|
|
"name": "exchange",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "routingKey",
|
|
"domain": "shortstr"
|
|
}, {
|
|
"name": "messageCount",
|
|
"domain": "long"
|
|
}]
|
|
}, {
|
|
"name": "getEmpty",
|
|
"index": 72,
|
|
"fields": [{
|
|
"name": "reserved1",
|
|
"domain": "shortstr"
|
|
}]
|
|
}, {
|
|
"name": "ack",
|
|
"index": 80,
|
|
"fields": [{
|
|
"name": "deliveryTag",
|
|
"domain": "longlong"
|
|
}, {
|
|
"name": "multiple",
|
|
"domain": "bit"
|
|
}]
|
|
}, {
|
|
"name": "reject",
|
|
"index": 90,
|
|
"fields": [{
|
|
"name": "deliveryTag",
|
|
"domain": "longlong"
|
|
}, {
|
|
"name": "requeue",
|
|
"domain": "bit"
|
|
}]
|
|
}, {
|
|
"name": "recoverAsync",
|
|
"index": 100,
|
|
"fields": [{
|
|
"name": "requeue",
|
|
"domain": "bit"
|
|
}]
|
|
}, {
|
|
"name": "recover",
|
|
"index": 110,
|
|
"fields": [{
|
|
"name": "requeue",
|
|
"domain": "bit"
|
|
}]
|
|
}, {
|
|
"name": "recoverOk",
|
|
"index": 111,
|
|
"fields": []
|
|
}]
|
|
}, {
|
|
"name": "tx",
|
|
"index": 90,
|
|
"fields": [],
|
|
"methods": [{
|
|
"name": "select",
|
|
"index": 10,
|
|
"fields": []
|
|
}, {
|
|
"name": "selectOk",
|
|
"index": 11,
|
|
"fields": []
|
|
}, {
|
|
"name": "commit",
|
|
"index": 20,
|
|
"fields": []
|
|
}, {
|
|
"name": "commitOk",
|
|
"index": 21,
|
|
"fields": []
|
|
}, {
|
|
"name": "rollback",
|
|
"index": 30,
|
|
"fields": []
|
|
}, {
|
|
"name": "rollbackOk",
|
|
"index": 31,
|
|
"fields": []
|
|
}]
|
|
}, {
|
|
"name": "confirm",
|
|
"index": 85,
|
|
"fields": [],
|
|
"methods": [{
|
|
"name": "select",
|
|
"index": 10,
|
|
"fields": [{
|
|
"name": "noWait",
|
|
"domain": "bit"
|
|
}]
|
|
}, {
|
|
"name": "selectOk",
|
|
"index": 11,
|
|
"fields": []
|
|
}]
|
|
}];
|
|
},{}],27:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
var events = _dereq_('events');
|
|
var util = _dereq_('util');
|
|
var fs = _dereq_('fs');
|
|
var Promise = _dereq_('./promise').Promise;
|
|
var definitions = _dereq_('./definitions');
|
|
var methods = definitions.methods;
|
|
|
|
// This class is not exposed to the user. Queue and Exchange are subclasses
|
|
// of Channel. This just provides a task queue.
|
|
var Channel = module.exports = function Channel (connection, channel) {
|
|
events.EventEmitter.call(this);
|
|
|
|
// Unlimited listeners. Helps when e.g. publishing high-volume messages,
|
|
// 10 is far too low.
|
|
this.setMaxListeners(0);
|
|
|
|
this.channel = channel;
|
|
this.connection = connection;
|
|
this._tasks = [];
|
|
|
|
this.reconnect();
|
|
};
|
|
util.inherits(Channel, events.EventEmitter);
|
|
|
|
Channel.prototype.closeOK = function() {
|
|
this.connection._sendMethod(this.channel, methods.channelCloseOk, {reserved1: ""});
|
|
};
|
|
|
|
Channel.prototype.reconnect = function () {
|
|
this.connection._sendMethod(this.channel, methods.channelOpen, {reserved1: ""});
|
|
};
|
|
|
|
Channel.prototype._taskPush = function (reply, cb) {
|
|
var promise = new Promise();
|
|
this._tasks.push({
|
|
promise: promise,
|
|
reply: reply,
|
|
sent: false,
|
|
cb: cb
|
|
});
|
|
this._tasksFlush();
|
|
return promise;
|
|
};
|
|
|
|
Channel.prototype._tasksFlush = function () {
|
|
if (this.state != 'open') return;
|
|
|
|
for (var i = 0; i < this._tasks.length; i++) {
|
|
var task = this._tasks[i];
|
|
if (task.sent) continue;
|
|
task.cb();
|
|
task.sent = true;
|
|
if (!task.reply) {
|
|
// if we don't expect a reply, just delete it now
|
|
this._tasks.splice(i, 1);
|
|
i = i-1;
|
|
}
|
|
}
|
|
};
|
|
|
|
Channel.prototype._handleTaskReply = function (channel, method, args) {
|
|
var task, i;
|
|
|
|
for (i = 0; i < this._tasks.length; i++) {
|
|
if (this._tasks[i].reply == method) {
|
|
task = this._tasks[i];
|
|
this._tasks.splice(i, 1);
|
|
task.promise.emitSuccess(args);
|
|
this._tasksFlush();
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
Channel.prototype._onChannelMethod = function(channel, method, args) {
|
|
switch (method) {
|
|
case methods.channelCloseOk:
|
|
delete this.connection.channels[this.channel];
|
|
this.state = 'closed';
|
|
// TODO should this be falling through?
|
|
default:
|
|
this._onMethod(channel, method, args);
|
|
}
|
|
};
|
|
|
|
Channel.prototype.close = function(reason) {
|
|
this.state = 'closing';
|
|
this.connection._sendMethod(this.channel, methods.channelClose,
|
|
{'replyText': reason ? reason : 'Goodbye from node',
|
|
'replyCode': 200,
|
|
'classId': 0,
|
|
'methodId': 0});
|
|
};
|
|
|
|
},{"./definitions":31,"./promise":35,"events":137,"fs":127,"util":159}],28:[function(_dereq_,module,exports){
|
|
(function (process,Buffer){
|
|
'use strict';
|
|
var net = _dereq_('net');
|
|
var tls = _dereq_('tls');
|
|
var fs = _dereq_('fs');
|
|
var URL = _dereq_('url');
|
|
var _ = _dereq_('lodash');
|
|
var debug = _dereq_('./debug');
|
|
var EventEmitter = _dereq_('events').EventEmitter;
|
|
var util = _dereq_('util');
|
|
var serializer = _dereq_('./serializer');
|
|
var definitions = _dereq_('./definitions');
|
|
var methods = definitions.methods;
|
|
var methodTable = definitions.methodTable;
|
|
var classes = definitions.classes;
|
|
var Exchange = _dereq_('./exchange');
|
|
var Queue = _dereq_('./queue');
|
|
var AMQPParser = _dereq_('./parser');
|
|
var nodeAMQPVersion = _dereq_('../package').version;
|
|
|
|
var maxFrameBuffer = 131072; // 128k, same as rabbitmq (which was
|
|
// copying qpid)
|
|
|
|
var defaultPorts = { 'amqp': 5672, 'amqps': 5671 };
|
|
|
|
var defaultOptions = {
|
|
host: 'localhost',
|
|
port: defaultPorts['amqp'],
|
|
login: 'guest',
|
|
password: 'guest',
|
|
authMechanism: 'AMQPLAIN',
|
|
vhost: '/',
|
|
connectionTimeout: 10000,
|
|
ssl: {
|
|
enabled: false
|
|
}
|
|
};
|
|
|
|
var defaultSslOptions = {
|
|
port: defaultPorts['amqps'],
|
|
ssl: {
|
|
rejectUnauthorized: true
|
|
}
|
|
};
|
|
|
|
var defaultImplOptions = {
|
|
defaultExchangeName: '',
|
|
reconnect: true,
|
|
reconnectBackoffStrategy: 'linear',
|
|
reconnectExponentialLimit: 120000,
|
|
reconnectBackoffTime: 1000
|
|
};
|
|
|
|
var defaultClientProperties = {
|
|
version: nodeAMQPVersion,
|
|
platform: 'node-' + process.version,
|
|
product: 'node-amqp'
|
|
};
|
|
|
|
var Connection = module.exports = function Connection (connectionArgs, options, readyCallback) {
|
|
EventEmitter.call(this);
|
|
this.setOptions(connectionArgs);
|
|
this.setImplOptions(options);
|
|
|
|
if (typeof readyCallback === 'function') {
|
|
this._readyCallback = readyCallback;
|
|
}
|
|
|
|
this.connectionAttemptScheduled = false;
|
|
this._defaultExchange = null;
|
|
this.channelCounter = 0;
|
|
this._sendBuffer = new Buffer(maxFrameBuffer);
|
|
};
|
|
util.inherits(Connection, EventEmitter);
|
|
|
|
|
|
|
|
Connection.prototype.setOptions = function (options) {
|
|
var urlo = (options && options.url) ? this._parseURLOptions(options.url) : {};
|
|
var sslo = (options && options.ssl && options.ssl.enabled) ? defaultSslOptions : {};
|
|
this.options = _.extend({}, defaultOptions, sslo, urlo, options || {});
|
|
this.options.clientProperties = _.extend({}, defaultClientProperties, (options && options.clientProperties) || {});
|
|
};
|
|
|
|
Connection.prototype.setImplOptions = function (options) {
|
|
this.implOptions = _.extend({}, defaultImplOptions, options || {});
|
|
};
|
|
|
|
Connection.prototype.connect = function () {
|
|
// If this is our first connection, add listeners.
|
|
if (!this.socket) this.addAllListeners();
|
|
|
|
this._createSocket();
|
|
this._startHandshake();
|
|
};
|
|
|
|
Connection.prototype.reconnect = function () {
|
|
// Suspend activity on channels
|
|
for (var channel in this.channels) {
|
|
this.channels[channel].state = 'closed';
|
|
}
|
|
debug && debug("Connection lost, reconnecting...");
|
|
// Terminate socket activity
|
|
if (this.socket) this.socket.end();
|
|
this.connect();
|
|
};
|
|
|
|
Connection.prototype.disconnect = function () {
|
|
debug && debug("Sending disconnect request to server");
|
|
this._sendMethod(0, methods.connectionClose, {
|
|
'replyText': 'client disconnect',
|
|
'replyCode': 200,
|
|
'classId': 0,
|
|
'methodId': 0
|
|
});
|
|
};
|
|
|
|
Connection.prototype.addAllListeners = function() {
|
|
var self = this;
|
|
var connectEvent = this.options.ssl.enabled ? 'secureConnect' : 'connect';
|
|
|
|
|
|
self.addListener(connectEvent, function() {
|
|
// In the case where this is a reconnection, do not trample on the existing
|
|
// channels.
|
|
// For your reference, channel 0 is the control channel.
|
|
self.channels = self.channels || {0:self};
|
|
self.queues = self.queues || {};
|
|
self.exchanges = self.exchanges || {};
|
|
|
|
self.parser = new AMQPParser('0-9-1', 'client');
|
|
|
|
self.parser.onMethod = function (channel, method, args) {
|
|
self._onMethod(channel, method, args);
|
|
};
|
|
|
|
self.parser.onContent = function (channel, data) {
|
|
debug && debug(channel + " > content " + data.length);
|
|
if (self.channels[channel] && self.channels[channel]._onContent) {
|
|
self.channels[channel]._onContent(channel, data);
|
|
} else {
|
|
debug && debug("unhandled content: " + data);
|
|
}
|
|
};
|
|
|
|
self.parser.onContentHeader = function (channel, classInfo, weight, properties, size) {
|
|
debug && debug(channel + " > content header " + JSON.stringify([classInfo.name, weight, properties, size]));
|
|
if (self.channels[channel] && self.channels[channel]._onContentHeader) {
|
|
self.channels[channel]._onContentHeader(channel, classInfo, weight, properties, size);
|
|
} else {
|
|
debug && debug("unhandled content header");
|
|
}
|
|
};
|
|
|
|
self.parser.onHeartBeat = function () {
|
|
self.emit("heartbeat");
|
|
debug && debug("heartbeat");
|
|
};
|
|
|
|
self.parser.onError = function (e) {
|
|
self.emit("error", e);
|
|
self.emit("close");
|
|
};
|
|
|
|
// Remove readyEmitted flag so we can detect an auth error.
|
|
self.readyEmitted = false;
|
|
});
|
|
|
|
self.addListener('data', function (data) {
|
|
if(self.parser != null){
|
|
try {
|
|
self.parser.execute(data);
|
|
} catch (exception) {
|
|
self.emit('error', exception);
|
|
return;
|
|
}
|
|
}
|
|
self._inboundHeartbeatTimerReset();
|
|
});
|
|
|
|
var backoffTime = null;
|
|
self.addListener('error', function backoff(e) {
|
|
if (self._inboundHeartbeatTimer !== null) {
|
|
clearTimeout(self._inboundHeartbeatTimer);
|
|
self._inboundHeartbeatTimer = null;
|
|
}
|
|
if (self._outboundHeartbeatTimer !== null) {
|
|
clearTimeout(self._outboundHeartbeatTimer);
|
|
self._outboundHeartbeatTimer = null;
|
|
}
|
|
|
|
if (!self.connectionAttemptScheduled) {
|
|
// Set to true, as we are presently in the process of scheduling one.
|
|
self.connectionAttemptScheduled = true;
|
|
|
|
// Kill the socket, if it hasn't been killed already.
|
|
self.socket.end();
|
|
|
|
// Reset parser state
|
|
self.parser = null;
|
|
|
|
// In order for our reconnection to be seamless, we have to notify the
|
|
// channels that they are no longer connected so that nobody attempts
|
|
// to send messages which would be doomed to fail.
|
|
for (var channel in self.channels) {
|
|
if (channel !== 0) {
|
|
self.channels[channel].state = 'closed';
|
|
}
|
|
}
|
|
// Queues are channels (so we have already marked them as closed), but
|
|
// queues have special needs, since the subscriptions will no longer
|
|
// be known to the server when we reconnect. Mark the subscriptions as
|
|
// closed so that we can resubscribe them once we are reconnected.
|
|
for (var queue in self.queues) {
|
|
for (var index in self.queues[queue].consumerTagOptions) {
|
|
self.queues[queue].consumerTagOptions[index]['state'] = 'closed';
|
|
}
|
|
}
|
|
|
|
// Begin reconnection attempts
|
|
if (self.implOptions.reconnect) {
|
|
// Don't thrash, use a backoff strategy.
|
|
if (backoffTime === null) {
|
|
// This is the first time we've failed since a successful connection,
|
|
// so use the configured backoff time without any modification.
|
|
backoffTime = self.implOptions.reconnectBackoffTime;
|
|
} else if (self.implOptions.reconnectBackoffStrategy === 'exponential') {
|
|
// If you've configured exponential backoff, we'll double the
|
|
// backoff time each subsequent attempt until success.
|
|
backoffTime *= 2;
|
|
// limit the maxium timeout, to avoid potentially unlimited stalls
|
|
if(backoffTime > self.implOptions.reconnectExponentialLimit){
|
|
backoffTime = self.implOptions.reconnectExponentialLimit;
|
|
}
|
|
|
|
} else if (self.implOptions.reconnectBackoffStrategy === 'linear') {
|
|
// Linear strategy is the default. In this case, we will retry at a
|
|
// constant interval, so there's no need to change the backoff time
|
|
// between attempts.
|
|
} else {
|
|
// TODO should we warn people if they picked a nonexistent strategy?
|
|
}
|
|
|
|
setTimeout(function () {
|
|
// Set to false, so that if we fail in the reconnect attempt, we can
|
|
// schedule another one.
|
|
self.connectionAttemptScheduled = false;
|
|
self.reconnect();
|
|
}, backoffTime);
|
|
} else {
|
|
self.removeListener('error', backoff);
|
|
}
|
|
}
|
|
});
|
|
|
|
self.addListener('ready', function () {
|
|
// Reset the backoff time since we have successfully connected.
|
|
backoffTime = null;
|
|
|
|
if (self.implOptions.reconnect) {
|
|
// Reconnect any channels which were open.
|
|
_.each(self.channels, function(channel, index) {
|
|
// FIXME why is the index "0" instead of 0?
|
|
if (index !== "0") channel.reconnect();
|
|
});
|
|
}
|
|
|
|
// Set 'ready' flag for auth failure detection.
|
|
this.readyEmitted = true;
|
|
|
|
// Restart the heartbeat to the server
|
|
self._outboundHeartbeatTimerReset();
|
|
});
|
|
|
|
// Apparently, it is not possible to determine if an authentication error
|
|
// has occurred, but when the connection closes then we can HINT that a
|
|
// possible authentication error has occured. Although this may be a bug
|
|
// in the spec, handling it as a possible error is considerably better than
|
|
// failing silently.
|
|
self.addListener('end', function (){
|
|
if (!this.readyEmitted){
|
|
this.emit('error', new Error(
|
|
'Connection ended: possibly due to an authentication failure.'
|
|
));
|
|
}
|
|
});
|
|
};
|
|
|
|
Connection.prototype.heartbeat = function () {
|
|
if(this.socket.writable) this.write(new Buffer([8,0,0,0,0,0,0,206]));
|
|
};
|
|
|
|
// connection.exchange('my-exchange', { type: 'topic' });
|
|
// Options
|
|
// - type 'fanout', 'direct', or 'topic' (default)
|
|
// - passive (boolean)
|
|
// - durable (boolean)
|
|
// - autoDelete (boolean, default true)
|
|
Connection.prototype.exchange = function (name, options, openCallback) {
|
|
if (name === undefined) name = this.implOptions.defaultExchangeName;
|
|
|
|
if (!options) options = {};
|
|
if (name !== '' && options.type === undefined) options.type = 'topic';
|
|
|
|
try{
|
|
var channel = this.generateChannelId();
|
|
}catch(exception){
|
|
this.emit("error", exception);
|
|
return;
|
|
}
|
|
var exchange = new Exchange(this, channel, name, options, openCallback);
|
|
this.channels[channel] = exchange;
|
|
this.exchanges[name] = exchange;
|
|
return exchange;
|
|
};
|
|
|
|
// remove an exchange when it's closed (called from Exchange)
|
|
Connection.prototype.exchangeClosed = function (name) {
|
|
if (this.exchanges[name]) delete this.exchanges[name];
|
|
};
|
|
|
|
// Options
|
|
// - passive (boolean)
|
|
// - durable (boolean)
|
|
// - exclusive (boolean)
|
|
// - autoDelete (boolean, default true)
|
|
Connection.prototype.queue = function (name /* options, openCallback */) {
|
|
var options, callback;
|
|
if (typeof arguments[1] == 'object') {
|
|
options = arguments[1];
|
|
callback = arguments[2];
|
|
} else {
|
|
callback = arguments[1];
|
|
}
|
|
|
|
try{
|
|
var channel = this.generateChannelId();
|
|
}catch(exception){
|
|
this.emit("error", exception);
|
|
return;
|
|
}
|
|
|
|
var q = new Queue(this, channel, name, options, callback);
|
|
this.channels[channel] = q;
|
|
return q;
|
|
};
|
|
|
|
// remove a queue when it's closed (called from Queue)
|
|
Connection.prototype.queueClosed = function (name) {
|
|
if (this.queues[name]) delete this.queues[name];
|
|
};
|
|
|
|
// Publishes a message to the default exchange.
|
|
Connection.prototype.publish = function (routingKey, body, options, callback) {
|
|
if (!this._defaultExchange) this._defaultExchange = this.exchange();
|
|
return this._defaultExchange.publish(routingKey, body, options, callback);
|
|
};
|
|
|
|
Connection.prototype._bodyToBuffer = function (body) {
|
|
// Handles 3 cases
|
|
// - body is utf8 string
|
|
// - body is instance of Buffer
|
|
// - body is an object and its JSON representation is sent
|
|
// Does not handle the case for streaming bodies.
|
|
// Returns buffer.
|
|
if (typeof(body) == 'string') {
|
|
return [null, new Buffer(body, 'utf8')];
|
|
} else if (body instanceof Buffer) {
|
|
return [null, body];
|
|
} else {
|
|
var jsonBody = JSON.stringify(body);
|
|
|
|
debug && debug('sending json: ' + jsonBody);
|
|
|
|
var props = {contentType: 'application/json'};
|
|
return [props, new Buffer(jsonBody, 'utf8')];
|
|
}
|
|
};
|
|
|
|
Connection.prototype._inboundHeartbeatTimerReset = function () {
|
|
if (this._inboundHeartbeatTimer !== null) {
|
|
clearTimeout(this._inboundHeartbeatTimer);
|
|
this._inboundHeartbeatTimer = null;
|
|
}
|
|
if (this.options.heartbeat) {
|
|
var self = this;
|
|
var gracePeriod = 2 * this.options.heartbeat;
|
|
this._inboundHeartbeatTimer = setTimeout(function () {
|
|
if(self.socket.readable)
|
|
self.emit('error', new Error('no heartbeat or data in last ' + gracePeriod + ' seconds'));
|
|
}, gracePeriod * 1000);
|
|
}
|
|
};
|
|
|
|
Connection.prototype._outboundHeartbeatTimerReset = function () {
|
|
if (this._outboundHeartbeatTimer !== null) {
|
|
clearTimeout(this._outboundHeartbeatTimer);
|
|
this._outboundHeartbeatTimer = null;
|
|
}
|
|
if (this.socket.writable && this.options.heartbeat) {
|
|
var self = this;
|
|
this._outboundHeartbeatTimer = setTimeout(function () {
|
|
self.heartbeat();
|
|
self._outboundHeartbeatTimerReset();
|
|
}, 1000 * this.options.heartbeat);
|
|
}
|
|
};
|
|
|
|
Connection.prototype._onMethod = function (channel, method, args) {
|
|
debug && debug(channel + " > " + method.name + " " + JSON.stringify(args));
|
|
|
|
// Channel 0 is the control channel. If not zero then delegate to
|
|
// one of the channel objects.
|
|
|
|
if (channel > 0) {
|
|
if (!this.channels[channel]) {
|
|
debug && debug("Received message on untracked channel.");
|
|
return;
|
|
}
|
|
if (!this.channels[channel]._onChannelMethod) {
|
|
throw new Error('Channel ' + channel + ' has no _onChannelMethod method.');
|
|
}
|
|
this.channels[channel]._onChannelMethod(channel, method, args);
|
|
return;
|
|
}
|
|
|
|
// channel 0
|
|
|
|
switch (method) {
|
|
// 2. The server responds, after the version string, with the
|
|
// 'connectionStart' method (contains various useless information)
|
|
case methods.connectionStart:
|
|
// We check that they're serving us AMQP 0-9
|
|
if (args.versionMajor !== 0 && args.versionMinor != 9) {
|
|
this.socket.end();
|
|
this.emit('error', new Error("Bad server version"));
|
|
return;
|
|
}
|
|
this.serverProperties = args.serverProperties;
|
|
// 3. Then we reply with StartOk, containing our useless information.
|
|
this._sendMethod(0, methods.connectionStartOk, {
|
|
clientProperties: this.options.clientProperties,
|
|
mechanism: this.options.authMechanism,
|
|
response: {
|
|
LOGIN: this.options.login,
|
|
PASSWORD: this.options.password
|
|
},
|
|
locale: 'en_US'
|
|
});
|
|
break;
|
|
|
|
// 4. The server responds with a connectionTune request
|
|
case methods.connectionTune:
|
|
if (args.frameMax) {
|
|
debug && debug("tweaking maxFrameBuffer to " + args.frameMax);
|
|
maxFrameBuffer = args.frameMax;
|
|
}
|
|
// 5. We respond with connectionTuneOk
|
|
this._sendMethod(0, methods.connectionTuneOk, {
|
|
channelMax: 0,
|
|
frameMax: maxFrameBuffer,
|
|
heartbeat: this.options.heartbeat || 0
|
|
});
|
|
// 6. Then we have to send a connectionOpen request
|
|
this._sendMethod(0, methods.connectionOpen, {
|
|
virtualHost: this.options.vhost
|
|
// , capabilities: ''
|
|
// , insist: true
|
|
,
|
|
reserved1: '',
|
|
reserved2: true
|
|
});
|
|
break;
|
|
|
|
|
|
case methods.connectionOpenOk:
|
|
// 7. Finally they respond with connectionOpenOk
|
|
// Whew! That's why they call it the Advanced MQP.
|
|
if (this._readyCallback) {
|
|
this._readyCallback(this);
|
|
this._readyCallback = null;
|
|
}
|
|
this.emit('ready');
|
|
break;
|
|
|
|
case methods.connectionClose:
|
|
var e = new Error(args.replyText);
|
|
e.code = args.replyCode;
|
|
if (!this.listeners('close').length) {
|
|
console.log('Unhandled connection error: ' + args.replyText);
|
|
}
|
|
this.socket.destroy(e);
|
|
break;
|
|
|
|
case methods.connectionCloseOk:
|
|
debug && debug("Received close-ok from server, closing socket");
|
|
this.socket.end();
|
|
break;
|
|
|
|
default:
|
|
throw new Error("Uncaught method '" + method.name + "' with args " +
|
|
JSON.stringify(args));
|
|
}
|
|
};
|
|
|
|
// Generate connection options from URI string formatted with amqp scheme.
|
|
Connection.prototype._parseURLOptions = function(connectionString) {
|
|
var opts = {};
|
|
opts.ssl = {};
|
|
var url = URL.parse(connectionString);
|
|
var scheme = url.protocol.substring(0, url.protocol.lastIndexOf(':'));
|
|
if (scheme != 'amqp' && scheme != 'amqps') {
|
|
throw new Error('Connection URI must use amqp or amqps scheme. ' +
|
|
'For example, "amqp://bus.megacorp.internal:5766".');
|
|
}
|
|
opts.ssl.enabled = ('amqps' === scheme);
|
|
opts.host = url.hostname;
|
|
opts.port = url.port || defaultPorts[scheme];
|
|
if (url.auth) {
|
|
var auth = url.auth.split(':');
|
|
auth[0] && (opts.login = auth[0]);
|
|
auth[1] && (opts.password = auth[1]);
|
|
}
|
|
if (url.pathname) {
|
|
opts.vhost = unescape(url.pathname.substr(1));
|
|
}
|
|
return opts;
|
|
};
|
|
|
|
/*
|
|
*
|
|
* Connect helpers
|
|
*
|
|
*/
|
|
|
|
// If you pass a array of hosts, lets choose a random host or the preferred host number, or then next one.
|
|
Connection.prototype._chooseHost = function() {
|
|
if(Array.isArray(this.options.host)){
|
|
if(this.hosti == null){
|
|
if(typeof this.options.hostPreference == 'number') {
|
|
this.hosti = (this.options.hostPreference < this.options.host.length) ?
|
|
this.options.hostPreference : this.options.host.length-1;
|
|
} else {
|
|
this.hosti = parseInt(Math.random() * this.options.host.length, 10);
|
|
}
|
|
} else {
|
|
// If this is already set, it looks like we want to choose another one.
|
|
// Add one to hosti but don't overflow it.
|
|
this.hosti = (this.hosti + 1) % this.options.host.length;
|
|
}
|
|
return this.options.host[this.hosti];
|
|
} else {
|
|
return this.options.host;
|
|
}
|
|
};
|
|
|
|
Connection.prototype._createSocket = function() {
|
|
var hostName = this._chooseHost(), self = this;
|
|
|
|
var options = {
|
|
port: this.options.port,
|
|
host: hostName
|
|
};
|
|
|
|
var resetConnectionTimeout = function () {
|
|
debug && debug('connected so resetting connection timeout');
|
|
this.setTimeout(0);
|
|
};
|
|
|
|
// Connect socket
|
|
if (this.options.ssl.enabled) {
|
|
debug && debug('making ssl connection');
|
|
options = _.extend(options, this._getSSLOptions());
|
|
this.socket = tls.connect(options, resetConnectionTimeout);
|
|
} else {
|
|
debug && debug('making non-ssl connection');
|
|
this.socket = net.connect(options, resetConnectionTimeout);
|
|
}
|
|
var connTimeout = this.options.connectionTimeout;
|
|
if (connTimeout) {
|
|
debug && debug('setting connection timeout to ' + connTimeout);
|
|
this.socket.setTimeout(connTimeout, function () {
|
|
debug && debug('connection timeout');
|
|
this.destroy();
|
|
var e = new Error('connection timeout');
|
|
e.name = 'TimeoutError';
|
|
self.emit('error', e);
|
|
});
|
|
}
|
|
|
|
// Proxy events.
|
|
// Note that if we don't attach a 'data' event, no data will flow.
|
|
var events = ['close', 'connect', 'data', 'drain', 'error', 'end', 'secureConnect', 'timeout'];
|
|
_.each(events, function(event){
|
|
self.socket.on(event, self.emit.bind(self, event));
|
|
});
|
|
|
|
// Proxy a few methods that we use / previously used.
|
|
var methods = ['end', 'destroy', 'write', 'pause', 'resume', 'setEncoding', 'ref', 'unref', 'address'];
|
|
_.each(methods, function(method){
|
|
self[method] = function(){
|
|
self.socket[method].apply(self.socket, arguments);
|
|
};
|
|
});
|
|
|
|
};
|
|
|
|
Connection.prototype._getSSLOptions = function() {
|
|
if (this.sslConnectionOptions) return this.sslConnectionOptions;
|
|
this.sslConnectionOptions = {};
|
|
if (this.options.ssl.keyFile) {
|
|
this.sslConnectionOptions.key = fs.readFileSync(this.options.ssl.keyFile);
|
|
}
|
|
if (this.options.ssl.certFile) {
|
|
this.sslConnectionOptions.cert = fs.readFileSync(this.options.ssl.certFile);
|
|
}
|
|
if (this.options.ssl.caFile) {
|
|
this.sslConnectionOptions.ca = fs.readFileSync(this.options.ssl.caFile);
|
|
}
|
|
this.sslConnectionOptions.rejectUnauthorized = this.options.ssl.rejectUnauthorized;
|
|
return this.sslConnectionOptions;
|
|
};
|
|
|
|
// Time to start the AMQP 7-way connection initialization handshake!
|
|
// 1. The client sends the server a version string
|
|
Connection.prototype._startHandshake = function() {
|
|
debug && debug("Initiating handshake...");
|
|
this.write("AMQP" + String.fromCharCode(0,0,9,1));
|
|
};
|
|
|
|
/*
|
|
*
|
|
* Parse helpers
|
|
*
|
|
*/
|
|
|
|
Connection.prototype._sendBody = function (channel, body, properties) {
|
|
var r = this._bodyToBuffer(body);
|
|
var props = r[0], buffer = r[1];
|
|
|
|
properties = _.extend(props || {}, properties);
|
|
|
|
this._sendHeader(channel, buffer.length, properties);
|
|
|
|
var pos = 0, len = buffer.length;
|
|
var metaSize = 8; // headerBytes = 7, frameEndBytes = 1
|
|
var maxBodySize = maxFrameBuffer - metaSize;
|
|
|
|
while (len > 0) {
|
|
var bodySize = len < maxBodySize ? len : maxBodySize;
|
|
var frameSize = bodySize + metaSize;
|
|
|
|
var b = new Buffer(frameSize);
|
|
b.used = 0;
|
|
b[b.used++] = 3; // constants.frameBody
|
|
serializer.serializeInt(b, 2, channel);
|
|
serializer.serializeInt(b, 4, bodySize);
|
|
buffer.copy(b, b.used, pos, pos+bodySize);
|
|
b.used += bodySize;
|
|
b[b.used++] = 206; // constants.frameEnd;
|
|
this.write(b);
|
|
|
|
len -= bodySize;
|
|
pos += bodySize;
|
|
}
|
|
return;
|
|
};
|
|
|
|
// connection: the connection
|
|
// channel: the channel to send this on
|
|
// size: size in bytes of the following message
|
|
// properties: an object containing any of the following:
|
|
// - contentType (default 'application/octet-stream')
|
|
// - contentEncoding
|
|
// - headers
|
|
// - deliveryMode
|
|
// - priority (0-9)
|
|
// - correlationId
|
|
// - replyTo
|
|
// - expiration
|
|
// - messageId
|
|
// - timestamp
|
|
// - userId
|
|
// - appId
|
|
// - clusterId
|
|
Connection.prototype._sendHeader = function(channel, size, properties) {
|
|
var b = new Buffer(maxFrameBuffer); // FIXME allocating too much.
|
|
// use freelist?
|
|
b.used = 0;
|
|
|
|
var classInfo = classes[60]; // always basic class.
|
|
|
|
// 7 OCTET FRAME HEADER
|
|
|
|
b[b.used++] = 2; // constants.frameHeader
|
|
|
|
serializer.serializeInt(b, 2, channel);
|
|
|
|
var lengthStart = b.used;
|
|
|
|
serializer.serializeInt(b, 4, 0 /*dummy*/); // length
|
|
|
|
var bodyStart = b.used;
|
|
|
|
// HEADER'S BODY
|
|
|
|
serializer.serializeInt(b, 2, classInfo.index); // class 60 for Basic
|
|
serializer.serializeInt(b, 2, 0); // weight, always 0 for rabbitmq
|
|
serializer.serializeInt(b, 8, size); // byte size of body
|
|
|
|
// properties - first propertyFlags
|
|
properties = _.defaults(properties || {}, {contentType: 'application/octet-stream'});
|
|
var propertyFlags = 0;
|
|
for (var i = 0; i < classInfo.fields.length; i++) {
|
|
if (properties[classInfo.fields[i].name]) propertyFlags |= 1 << (15-i);
|
|
}
|
|
serializer.serializeInt(b, 2, propertyFlags);
|
|
// now the actual properties.
|
|
serializer.serializeFields(b, classInfo.fields, properties, false);
|
|
|
|
//serializeTable(b, properties);
|
|
|
|
var bodyEnd = b.used;
|
|
|
|
// Go back to the header and write in the length now that we know it.
|
|
b.used = lengthStart;
|
|
serializer.serializeInt(b, 4, bodyEnd - bodyStart);
|
|
b.used = bodyEnd;
|
|
|
|
// 1 OCTET END
|
|
|
|
b[b.used++] = 206; // constants.frameEnd;
|
|
|
|
var s = new Buffer(b.used);
|
|
b.copy(s);
|
|
|
|
//debug && debug('header sent: ' + JSON.stringify(s));
|
|
|
|
this.write(s);
|
|
};
|
|
|
|
Connection.prototype._sendMethod = function (channel, method, args) {
|
|
debug && debug(channel + " < " + method.name + " " + JSON.stringify(args));
|
|
var b = this._sendBuffer;
|
|
b.used = 0;
|
|
|
|
b[b.used++] = 1; // constants.frameMethod
|
|
|
|
serializer.serializeInt(b, 2, channel);
|
|
|
|
var lengthIndex = b.used;
|
|
|
|
serializer.serializeInt(b, 4, 42); // replace with actual length.
|
|
|
|
var startIndex = b.used;
|
|
|
|
|
|
serializer.serializeInt(b, 2, method.classIndex); // short, classId
|
|
serializer.serializeInt(b, 2, method.methodIndex); // short, methodId
|
|
|
|
serializer.serializeFields(b, method.fields, args, true);
|
|
|
|
var endIndex = b.used;
|
|
|
|
// write in the frame length now that we know it.
|
|
b.used = lengthIndex;
|
|
serializer.serializeInt(b, 4, endIndex - startIndex);
|
|
b.used = endIndex;
|
|
|
|
b[b.used++] = 206; // constants.frameEnd;
|
|
|
|
var c = new Buffer(b.used);
|
|
b.copy(c);
|
|
|
|
debug && debug("sending frame: " + c.toJSON());
|
|
|
|
this.write(c);
|
|
|
|
this._outboundHeartbeatTimerReset();
|
|
};
|
|
|
|
// tries to find the next available id slot for a channel
|
|
Connection.prototype.generateChannelId = function () {
|
|
// start from the last used slot id
|
|
var channelId = this.channelCounter;
|
|
while(true){
|
|
// use values in range of 1..65535
|
|
channelId = channelId % 65535 + 1;
|
|
if(!this.channels[channelId]){
|
|
break;
|
|
}
|
|
// after a full loop throw an Error
|
|
if(channelId == this.channelCounter){
|
|
throw new Error("No valid Channel Id values available");
|
|
}
|
|
}
|
|
this.channelCounter = channelId;
|
|
return this.channelCounter;
|
|
};
|
|
|
|
}).call(this,_dereq_("C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"),_dereq_("buffer").Buffer)
|
|
},{"../package":39,"./debug":30,"./definitions":31,"./exchange":32,"./parser":34,"./queue":36,"./serializer":37,"C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":144,"buffer":128,"events":137,"fs":127,"lodash":38,"net":127,"tls":127,"url":157,"util":159}],29:[function(_dereq_,module,exports){
|
|
module.exports = {
|
|
AMQPTypes: Object.freeze({
|
|
STRING: 'S'.charCodeAt(0)
|
|
, INTEGER: 'I'.charCodeAt(0)
|
|
, HASH: 'F'.charCodeAt(0)
|
|
, TIME: 'T'.charCodeAt(0)
|
|
, DECIMAL: 'D'.charCodeAt(0)
|
|
, BOOLEAN: 't'.charCodeAt(0)
|
|
, SIGNED_8BIT: 'b'.charCodeAt(0)
|
|
, SIGNED_16BIT: 's'.charCodeAt(0)
|
|
, SIGNED_64BIT: 'l'.charCodeAt(0)
|
|
, _32BIT_FLOAT: 'f'.charCodeAt(0)
|
|
, _64BIT_FLOAT: 'd'.charCodeAt(0)
|
|
, VOID: 'v'.charCodeAt(0)
|
|
, BYTE_ARRAY: 'x'.charCodeAt(0)
|
|
, ARRAY: 'A'.charCodeAt(0)
|
|
, TEN: '10'.charCodeAt(0)
|
|
, BOOLEAN_TRUE: '\x01'
|
|
, BOOLEAN_FALSE:'\x00'
|
|
|
|
})
|
|
, Indicators: Object.freeze({
|
|
FRAME_END: 206
|
|
})
|
|
, FrameType: Object.freeze({
|
|
METHOD: 1
|
|
, HEADER: 2
|
|
, BODY: 3
|
|
, HEARTBEAT: 8
|
|
})
|
|
}
|
|
|
|
|
|
},{}],30:[function(_dereq_,module,exports){
|
|
(function (process){
|
|
'use strict';
|
|
|
|
var DEBUG = process.env['NODE_DEBUG_AMQP'];
|
|
|
|
// only define debug function in debugging mode
|
|
if (DEBUG) {
|
|
module.exports = function debug () {
|
|
console.error.apply(null, arguments);
|
|
};
|
|
} else {
|
|
module.exports = null;
|
|
}
|
|
|
|
|
|
}).call(this,_dereq_("C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"))
|
|
},{"C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":144}],31:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var protocol = _dereq_('./amqp-definitions-0-9-1');
|
|
|
|
// a look up table for methods recieved
|
|
// indexed on class id, method id
|
|
var methodTable = {};
|
|
|
|
// methods keyed on their name
|
|
var methods = {};
|
|
|
|
// classes keyed on their index
|
|
var classes = {};
|
|
|
|
(function () { // anon scope for init
|
|
//debug("initializing amqp methods...");
|
|
|
|
for (var i = 0; i < protocol.classes.length; i++) {
|
|
var classInfo = protocol.classes[i];
|
|
classes[classInfo.index] = classInfo;
|
|
|
|
for (var j = 0; j < classInfo.methods.length; j++) {
|
|
var methodInfo = classInfo.methods[j];
|
|
|
|
var name = classInfo.name +
|
|
methodInfo.name[0].toUpperCase() +
|
|
methodInfo.name.slice(1);
|
|
|
|
//debug(name);
|
|
|
|
var method = {
|
|
name: name,
|
|
fields: methodInfo.fields,
|
|
methodIndex: methodInfo.index,
|
|
classIndex: classInfo.index
|
|
};
|
|
|
|
if (!methodTable[classInfo.index]) methodTable[classInfo.index] = {};
|
|
methodTable[classInfo.index][methodInfo.index] = method;
|
|
methods[name] = method;
|
|
}
|
|
}
|
|
})();
|
|
|
|
module.exports = {methods: methods, classes: classes, methodTable: methodTable};
|
|
|
|
},{"./amqp-definitions-0-9-1":26}],32:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
var events = _dereq_('events');
|
|
var util = _dereq_('util');
|
|
var net = _dereq_('net');
|
|
var tls = _dereq_('tls');
|
|
var fs = _dereq_('fs');
|
|
var _ = _dereq_('lodash');
|
|
var methods = _dereq_('./definitions').methods;
|
|
var Channel = _dereq_('./channel');
|
|
|
|
var Exchange = module.exports = function Exchange (connection, channel, name, options, openCallback) {
|
|
Channel.call(this, connection, channel);
|
|
this.name = name;
|
|
this.binds = 0; // keep track of queues bound
|
|
this.exchangeBinds = 0; // keep track of exchanges bound
|
|
this.sourceExchanges = {};
|
|
this.options = _.defaults(options || {}, {autoDelete: true});
|
|
this._openCallback = openCallback;
|
|
|
|
this._sequence = null;
|
|
this._unAcked = {};
|
|
this._addedExchangeErrorHandler = false;
|
|
};
|
|
util.inherits(Exchange, Channel);
|
|
|
|
// creates an error handler scoped to the given `exchange`
|
|
function createExchangeErrorHandlerFor (exchange) {
|
|
return function (err) {
|
|
if (!exchange.options.confirm) return;
|
|
|
|
for (var id in exchange._unAcked) {
|
|
var task = exchange._unAcked[id];
|
|
task.emit('ack error', err);
|
|
delete exchange._unAcked[id];
|
|
}
|
|
}
|
|
};
|
|
|
|
Exchange.prototype._onMethod = function (channel, method, args) {
|
|
this.emit(method.name, args);
|
|
|
|
if (this._handleTaskReply.apply(this, arguments))
|
|
return true;
|
|
|
|
var cb;
|
|
|
|
switch (method) {
|
|
case methods.channelOpenOk:
|
|
// Pre-baked exchanges don't need to be declared
|
|
if (/^$|(amq\.)/.test(this.name)) {
|
|
this.state = 'open';
|
|
// - issue #33 fix
|
|
if (this._openCallback) {
|
|
this._openCallback(this);
|
|
this._openCallback = null;
|
|
}
|
|
// --
|
|
this.emit('open');
|
|
|
|
// For if we want to delete a exchange,
|
|
// we dont care if all of the options match.
|
|
} else if (this.options.noDeclare) {
|
|
this.state = 'open';
|
|
|
|
if (this._openCallback) {
|
|
this._openCallback(this);
|
|
this._openCallback = null;
|
|
}
|
|
|
|
this.emit('open');
|
|
} else {
|
|
this.connection._sendMethod(channel, methods.exchangeDeclare,
|
|
{ reserved1: 0
|
|
, reserved2: false
|
|
, reserved3: false
|
|
, exchange: this.name
|
|
, type: this.options.type || 'topic'
|
|
, passive: !!this.options.passive
|
|
, durable: !!this.options.durable
|
|
, autoDelete: !!this.options.autoDelete
|
|
, internal: !!this.options.internal
|
|
, noWait: false
|
|
, "arguments":this.options.arguments || {}
|
|
});
|
|
this.state = 'declaring';
|
|
}
|
|
break;
|
|
|
|
case methods.exchangeDeclareOk:
|
|
|
|
if (this.options.confirm) {
|
|
this.connection._sendMethod(channel, methods.confirmSelect,
|
|
{ noWait: false });
|
|
} else {
|
|
|
|
this.state = 'open';
|
|
this.emit('open');
|
|
if (this._openCallback) {
|
|
this._openCallback(this);
|
|
this._openCallback = null;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case methods.confirmSelectOk:
|
|
this._sequence = 1;
|
|
|
|
this.state = 'open';
|
|
this.emit('open');
|
|
if (this._openCallback) {
|
|
this._openCallback(this);
|
|
this._openCallback = null;
|
|
}
|
|
break;
|
|
|
|
case methods.channelClose:
|
|
this.state = "closed";
|
|
this.closeOK();
|
|
this.connection.exchangeClosed(this.name);
|
|
var e = new Error(args.replyText);
|
|
e.code = args.replyCode;
|
|
this.emit('error', e);
|
|
this.emit('close');
|
|
break;
|
|
|
|
case methods.channelCloseOk:
|
|
this.connection.exchangeClosed(this.name);
|
|
this.emit('close');
|
|
break;
|
|
|
|
|
|
case methods.basicAck:
|
|
this.emit('basic-ack', args);
|
|
var sequenceNumber = args.deliveryTag.readUInt32BE(4), tag;
|
|
|
|
if (sequenceNumber === 0 && args.multiple === true) {
|
|
// we must ack everything
|
|
for (tag in this._unAcked) {
|
|
this._unAcked[tag].emit('ack');
|
|
delete this._unAcked[tag];
|
|
}
|
|
} else if (sequenceNumber !== 0 && args.multiple === true) {
|
|
// we must ack everything before the delivery tag
|
|
for (tag in this._unAcked) {
|
|
if (tag <= sequenceNumber) {
|
|
this._unAcked[tag].emit('ack');
|
|
delete this._unAcked[tag];
|
|
}
|
|
}
|
|
} else if (this._unAcked[sequenceNumber] && args.multiple === false) {
|
|
// simple single ack
|
|
this._unAcked[sequenceNumber].emit('ack');
|
|
delete this._unAcked[sequenceNumber];
|
|
}
|
|
break;
|
|
|
|
case methods.basicReturn:
|
|
this.emit('basic-return', args);
|
|
break;
|
|
|
|
case methods.exchangeBindOk:
|
|
if (this._bindCallback) {
|
|
// setting this._bindCallback to null before calling the callback allows for a subsequent bind within the callback
|
|
cb = this._bindCallback;
|
|
this._bindCallback = null;
|
|
cb(this);
|
|
}
|
|
break;
|
|
|
|
case methods.exchangeUnbindOk:
|
|
if (this._unbindCallback) {
|
|
cb = this._unbindCallback;
|
|
this._unbindCallback = null;
|
|
cb(this);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
throw new Error("Uncaught method '" + method.name + "' with args " +
|
|
JSON.stringify(args));
|
|
}
|
|
|
|
this._tasksFlush();
|
|
};
|
|
|
|
// exchange.publish('routing.key', 'body');
|
|
//
|
|
// the third argument can specify additional options
|
|
// - mandatory (boolean, default false)
|
|
// - immediate (boolean, default false)
|
|
// - contentType (default 'application/octet-stream')
|
|
// - contentEncoding
|
|
// - headers
|
|
// - deliveryMode
|
|
// - priority (0-9)
|
|
// - correlationId
|
|
// - replyTo
|
|
// - expiration
|
|
// - messageId
|
|
// - timestamp
|
|
// - userId
|
|
// - appId
|
|
// - clusterId
|
|
//
|
|
// the callback is optional and is only used when confirm is turned on for the exchange
|
|
|
|
Exchange.prototype.publish = function (routingKey, data, options, callback) {
|
|
var self = this;
|
|
|
|
options = _.extend({}, options || {});
|
|
options.routingKey = routingKey;
|
|
options.exchange = self.name;
|
|
options.mandatory = options.mandatory ? true : false;
|
|
options.immediate = options.immediate ? true : false;
|
|
options.reserved1 = 0;
|
|
|
|
var task = this._taskPush(null, function () {
|
|
self.connection._sendMethod(self.channel, methods.basicPublish, options);
|
|
// This interface is probably not appropriate for streaming large files.
|
|
// (Of course it's arguable about whether AMQP is the appropriate
|
|
// transport for large files.) The content header wants to know the size
|
|
// of the data before sending it - so there's no point in trying to have a
|
|
// general streaming interface - streaming messages of unknown size simply
|
|
// isn't possible with AMQP. This is all to say, don't send big messages.
|
|
// If you need to stream something large, chunk it yourself.
|
|
self.connection._sendBody(self.channel, data, options);
|
|
});
|
|
|
|
if (self.options.confirm) self._awaitConfirm(task, callback);
|
|
return task;
|
|
};
|
|
|
|
// registers tasks for confirms
|
|
Exchange.prototype._awaitConfirm = function _awaitConfirm (task, callback) {
|
|
if (!this._addedExchangeErrorHandler) {
|
|
this.on('error', createExchangeErrorHandlerFor(this));
|
|
this._addedExchangeErrorHandler = true;
|
|
}
|
|
|
|
task.sequence = this._sequence;
|
|
this._unAcked[this._sequence] = task;
|
|
this._sequence++;
|
|
|
|
if ('function' != typeof callback) return;
|
|
|
|
task.once('ack error', function (err) {
|
|
task.removeAllListeners();
|
|
callback(true, err);
|
|
});
|
|
|
|
task.once('ack', function () {
|
|
task.removeAllListeners();
|
|
callback(false);
|
|
});
|
|
};
|
|
|
|
// do any necessary cleanups eg. after queue destruction
|
|
Exchange.prototype.cleanup = function() {
|
|
if (this.binds === 0) { // don't keep reference open if unused
|
|
this.connection.exchangeClosed(this.name);
|
|
}
|
|
};
|
|
|
|
Exchange.prototype.destroy = function (ifUnused) {
|
|
var self = this;
|
|
return this._taskPush(methods.exchangeDeleteOk, function () {
|
|
self.connection.exchangeClosed(self.name);
|
|
self.connection._sendMethod(self.channel, methods.exchangeDelete,
|
|
{ reserved1: 0
|
|
, exchange: self.name
|
|
, ifUnused: ifUnused ? true : false
|
|
, noWait: false
|
|
});
|
|
});
|
|
};
|
|
|
|
// E2E Unbind
|
|
// support RabbitMQ's exchange-to-exchange binding extension
|
|
// http://www.rabbitmq.com/e2e.html
|
|
Exchange.prototype.unbind = function (/* exchange, routingKey [, bindCallback] */) {
|
|
var self = this;
|
|
|
|
// Both arguments are required. The binding to the destination
|
|
// exchange/routingKey will be unbound.
|
|
|
|
var exchange = arguments[0]
|
|
, routingKey = arguments[1]
|
|
, callback = arguments[2]
|
|
;
|
|
|
|
if (callback) this._unbindCallback = callback;
|
|
|
|
return this._taskPush(methods.exchangeUnbindOk, function () {
|
|
var source = exchange instanceof Exchange ? exchange.name : exchange;
|
|
var destination = self.name;
|
|
|
|
if (source in self.connection.exchanges) {
|
|
delete self.sourceExchanges[source];
|
|
self.connection.exchanges[source].exchangeBinds--;
|
|
}
|
|
|
|
self.connection._sendMethod(self.channel, methods.exchangeUnbind,
|
|
{ reserved1: 0
|
|
, destination: destination
|
|
, source: source
|
|
, routingKey: routingKey
|
|
, noWait: false
|
|
, "arguments": {}
|
|
});
|
|
});
|
|
};
|
|
|
|
// E2E Bind
|
|
// support RabbitMQ's exchange-to-exchange binding extension
|
|
// http://www.rabbitmq.com/e2e.html
|
|
Exchange.prototype.bind = function (/* exchange, routingKey [, bindCallback] */) {
|
|
var self = this;
|
|
|
|
// Two arguments are required. The binding to the destination
|
|
// exchange/routingKey will be established.
|
|
|
|
var exchange = arguments[0]
|
|
, routingKey = arguments[1]
|
|
, callback = arguments[2]
|
|
;
|
|
|
|
if (callback) this._bindCallback = callback;
|
|
|
|
var source = exchange instanceof Exchange ? exchange.name : exchange;
|
|
var destination = self.name;
|
|
|
|
if(source in self.connection.exchanges) {
|
|
self.sourceExchanges[source] = self.connection.exchanges[source];
|
|
self.connection.exchanges[source].exchangeBinds++;
|
|
}
|
|
|
|
self.connection._sendMethod(self.channel, methods.exchangeBind,
|
|
{ reserved1: 0
|
|
, destination: destination
|
|
, source: source
|
|
, routingKey: routingKey
|
|
, noWait: false
|
|
, "arguments": {}
|
|
});
|
|
|
|
};
|
|
|
|
// E2E Bind
|
|
// support RabbitMQ's exchange-to-exchange binding extension
|
|
// http://www.rabbitmq.com/e2e.html
|
|
Exchange.prototype.bind_headers = function (/* exchange, routing [, bindCallback] */) {
|
|
var self = this;
|
|
|
|
// Two arguments are required. The binding to the destination
|
|
// exchange/routingKey will be established.
|
|
|
|
var exchange = arguments[0]
|
|
, routing = arguments[1]
|
|
, callback = arguments[2]
|
|
;
|
|
|
|
if (callback) this._bindCallback = callback;
|
|
|
|
var source = exchange instanceof Exchange ? exchange.name : exchange;
|
|
var destination = self.name;
|
|
|
|
if (source in self.connection.exchanges) {
|
|
self.sourceExchanges[source] = self.connection.exchanges[source];
|
|
self.connection.exchanges[source].exchangeBinds++;
|
|
}
|
|
|
|
self.connection._sendMethod(self.channel, methods.exchangeBind,
|
|
{ reserved1: 0
|
|
, destination: destination
|
|
, source: source
|
|
, routingKey: ''
|
|
, noWait: false
|
|
, "arguments": routing
|
|
});
|
|
};
|
|
|
|
},{"./channel":27,"./definitions":31,"events":137,"fs":127,"lodash":38,"net":127,"tls":127,"util":159}],33:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
var events = _dereq_('events'),
|
|
util = _dereq_('util'),
|
|
fs = _dereq_('fs'),
|
|
protocol,
|
|
definitions = _dereq_('./definitions');
|
|
|
|
// Properties:
|
|
// - routingKey
|
|
// - size
|
|
// - deliveryTag
|
|
//
|
|
// - contentType (default 'application/octet-stream')
|
|
// - contentEncoding
|
|
// - headers
|
|
// - deliveryMode
|
|
// - priority (0-9)
|
|
// - correlationId
|
|
// - replyTo
|
|
// - experation
|
|
// - messageId
|
|
// - timestamp
|
|
// - userId
|
|
// - appId
|
|
// - clusterId
|
|
var Message = module.exports = function Message (queue, args) {
|
|
var msgProperties = definitions.classes[60].fields;
|
|
|
|
events.EventEmitter.call(this);
|
|
|
|
this.queue = queue;
|
|
|
|
this.deliveryTag = args.deliveryTag;
|
|
this.redelivered = args.redelivered;
|
|
this.exchange = args.exchange;
|
|
this.routingKey = args.routingKey;
|
|
this.consumerTag = args.consumerTag;
|
|
|
|
for (var i=0, l=msgProperties.length; i<l; i++) {
|
|
if (args[msgProperties[i].name]) {
|
|
this[msgProperties[i].name] = args[msgProperties[i].name];
|
|
}
|
|
}
|
|
};
|
|
util.inherits(Message, events.EventEmitter);
|
|
|
|
|
|
// Acknowledge receipt of message.
|
|
// Set first arg to 'true' to acknowledge this and all previous messages
|
|
// received on this queue.
|
|
Message.prototype.acknowledge = function (all) {
|
|
this.queue.connection._sendMethod(this.queue.channel, definitions.methods.basicAck,
|
|
{ reserved1: 0
|
|
, deliveryTag: this.deliveryTag
|
|
, multiple: all ? true : false
|
|
});
|
|
};
|
|
|
|
// Reject an incoming message.
|
|
// Set first arg to 'true' to requeue the message.
|
|
Message.prototype.reject = function (requeue) {
|
|
this.queue.connection._sendMethod(this.queue.channel, definitions.methods.basicReject,
|
|
{ deliveryTag: this.deliveryTag
|
|
, requeue: requeue ? true : false
|
|
});
|
|
};
|
|
|
|
|
|
},{"./definitions":31,"events":137,"fs":127,"util":159}],34:[function(_dereq_,module,exports){
|
|
(function (Buffer){
|
|
'use strict';
|
|
|
|
var events = _dereq_('events');
|
|
var util = _dereq_('util');
|
|
var net = _dereq_('net');
|
|
var tls = _dereq_('tls');
|
|
var fs = _dereq_('fs');
|
|
var debug = _dereq_('./debug');
|
|
var jspack = _dereq_('../jspack').jspack;
|
|
var AMQPTypes = _dereq_('./constants').AMQPTypes;
|
|
var Indicators = _dereq_('./constants').Indicators;
|
|
var FrameType = _dereq_('./constants').FrameType;
|
|
var definitions = _dereq_('./definitions');
|
|
var methodTable = definitions.methodTable;
|
|
var classes = definitions.classes;
|
|
|
|
// parser
|
|
|
|
var maxFrameBuffer = 131072; // 128k, same as rabbitmq (which was
|
|
// copying qpid)
|
|
|
|
// An interruptible AMQP parser.
|
|
//
|
|
// type is either 'server' or 'client'
|
|
// version is '0-9-1'.
|
|
//
|
|
// Instances of this class have several callbacks
|
|
// - onMethod(channel, method, args);
|
|
// - onHeartBeat()
|
|
// - onContent(channel, buffer);
|
|
// - onContentHeader(channel, class, weight, properties, size);
|
|
//
|
|
// This class does not subclass EventEmitter, in order to reduce the speed
|
|
// of emitting the callbacks. Since this is an internal class, that should
|
|
// be fine.
|
|
var AMQPParser = module.exports = function AMQPParser (version, type) {
|
|
this.isClient = (type == 'client');
|
|
this.state = this.isClient ? 'frameHeader' : 'protocolHeader';
|
|
|
|
if (version != '0-9-1') this.throwError("Unsupported protocol version");
|
|
|
|
var frameHeader = new Buffer(7);
|
|
frameHeader.used = 0;
|
|
var frameBuffer, frameType, frameChannel;
|
|
|
|
var self = this;
|
|
|
|
function header(data) {
|
|
var fh = frameHeader;
|
|
var needed = fh.length - fh.used;
|
|
data.copy(fh, fh.used, 0, data.length);
|
|
fh.used += data.length; // sloppy
|
|
if (fh.used >= fh.length) {
|
|
fh.read = 0;
|
|
frameType = fh[fh.read++];
|
|
frameChannel = parseInt(fh, 2);
|
|
var frameSize = parseInt(fh, 4);
|
|
fh.used = 0; // for reuse
|
|
if (frameSize > maxFrameBuffer) {
|
|
self.throwError("Oversized frame " + frameSize);
|
|
}
|
|
frameBuffer = new Buffer(frameSize);
|
|
frameBuffer.used = 0;
|
|
return frame(data.slice(needed));
|
|
}
|
|
else { // need more!
|
|
return header;
|
|
}
|
|
}
|
|
|
|
function frame(data) {
|
|
var fb = frameBuffer;
|
|
var needed = fb.length - fb.used;
|
|
var sourceEnd = (fb.length > data.length) ? data.length : fb.length;
|
|
data.copy(fb, fb.used, 0, sourceEnd);
|
|
fb.used += data.length;
|
|
if (data.length > needed) {
|
|
return frameEnd(data.slice(needed));
|
|
}
|
|
else if (data.length == needed) {
|
|
return frameEnd;
|
|
}
|
|
else {
|
|
return frame;
|
|
}
|
|
}
|
|
|
|
function frameEnd(data) {
|
|
if (data.length > 0) {
|
|
if (data[0] === Indicators.FRAME_END) {
|
|
switch (frameType) {
|
|
case FrameType.METHOD:
|
|
self._parseMethodFrame(frameChannel, frameBuffer);
|
|
break;
|
|
case FrameType.HEADER:
|
|
self._parseHeaderFrame(frameChannel, frameBuffer);
|
|
break;
|
|
case FrameType.BODY:
|
|
if (self.onContent) {
|
|
self.onContent(frameChannel, frameBuffer);
|
|
}
|
|
break;
|
|
case FrameType.HEARTBEAT:
|
|
debug && debug("heartbeat");
|
|
if (self.onHeartBeat) self.onHeartBeat();
|
|
break;
|
|
default:
|
|
self.throwError("Unhandled frame type " + frameType);
|
|
break;
|
|
}
|
|
return header(data.slice(1));
|
|
}
|
|
else {
|
|
self.throwError("Missing frame end marker");
|
|
}
|
|
}
|
|
else {
|
|
return frameEnd;
|
|
}
|
|
}
|
|
|
|
self.parse = header;
|
|
}
|
|
|
|
// If there's an error in the parser, call the onError handler or throw
|
|
AMQPParser.prototype.throwError = function (error) {
|
|
if (this.onError) this.onError(error);
|
|
else throw new Error(error);
|
|
};
|
|
|
|
// Everytime data is recieved on the socket, pass it to this function for
|
|
// parsing.
|
|
AMQPParser.prototype.execute = function (data) {
|
|
// This function only deals with dismantling and buffering the frames.
|
|
// It delegates to other functions for parsing the frame-body.
|
|
debug && debug('execute: ' + data.toString('hex'));
|
|
this.parse = this.parse(data);
|
|
};
|
|
|
|
|
|
// parse Network Byte Order integers. size can be 1,2,4,8
|
|
function parseInt (buffer, size) {
|
|
switch (size) {
|
|
case 1:
|
|
return buffer[buffer.read++];
|
|
|
|
case 2:
|
|
return (buffer[buffer.read++] << 8) + buffer[buffer.read++];
|
|
|
|
case 4:
|
|
return (buffer[buffer.read++] << 24) + (buffer[buffer.read++] << 16) +
|
|
(buffer[buffer.read++] << 8) + buffer[buffer.read++];
|
|
|
|
case 8:
|
|
return (buffer[buffer.read++] << 56) + (buffer[buffer.read++] << 48) +
|
|
(buffer[buffer.read++] << 40) + (buffer[buffer.read++] << 32) +
|
|
(buffer[buffer.read++] << 24) + (buffer[buffer.read++] << 16) +
|
|
(buffer[buffer.read++] << 8) + buffer[buffer.read++];
|
|
|
|
default:
|
|
throw new Error("cannot parse ints of that size");
|
|
}
|
|
}
|
|
|
|
|
|
function parseShortString (buffer) {
|
|
var length = buffer[buffer.read++];
|
|
var s = buffer.toString('utf8', buffer.read, buffer.read+length);
|
|
buffer.read += length;
|
|
return s;
|
|
}
|
|
|
|
|
|
function parseLongString (buffer) {
|
|
var length = parseInt(buffer, 4);
|
|
var s = buffer.slice(buffer.read, buffer.read + length);
|
|
buffer.read += length;
|
|
return s.toString();
|
|
}
|
|
|
|
|
|
function parseSignedInteger (buffer) {
|
|
var int = parseInt(buffer, 4);
|
|
if (int & 0x80000000) {
|
|
int |= 0xEFFFFFFF;
|
|
int = -int;
|
|
}
|
|
return int;
|
|
}
|
|
|
|
function parseValue (buffer) {
|
|
switch (buffer[buffer.read++]) {
|
|
case AMQPTypes.STRING:
|
|
return parseLongString(buffer);
|
|
|
|
case AMQPTypes.INTEGER:
|
|
return parseInt(buffer, 4);
|
|
|
|
case AMQPTypes.DECIMAL:
|
|
var dec = parseInt(buffer, 1);
|
|
var num = parseInt(buffer, 4);
|
|
return num / (dec * 10);
|
|
|
|
case AMQPTypes._64BIT_FLOAT:
|
|
var b = [];
|
|
for (var i = 0; i < 8; ++i)
|
|
b[i] = buffer[buffer.read++];
|
|
|
|
return (new jspack(true)).Unpack('d', b);
|
|
|
|
case AMQPTypes._32BIT_FLOAT:
|
|
var b = [];
|
|
for (var i = 0; i < 4; ++i)
|
|
b[i] = buffer[buffer.read++];
|
|
|
|
return (new jspack(true)).Unpack('f', b);
|
|
|
|
case AMQPTypes.TIME:
|
|
var int = parseInt(buffer, 8);
|
|
return (new Date()).setTime(int * 1000);
|
|
|
|
case AMQPTypes.HASH:
|
|
return parseTable(buffer);
|
|
|
|
case AMQPTypes.SIGNED_64BIT:
|
|
return parseInt(buffer, 8);
|
|
|
|
case AMQPTypes.BOOLEAN:
|
|
return (parseInt(buffer, 1) > 0);
|
|
|
|
case AMQPTypes.BYTE_ARRAY:
|
|
var len = parseInt(buffer, 4);
|
|
var buf = new Buffer(len);
|
|
buffer.copy(buf, 0, buffer.read, buffer.read + len);
|
|
buffer.read += len;
|
|
return buf;
|
|
|
|
case AMQPTypes.ARRAY:
|
|
var len = parseInt(buffer, 4);
|
|
var end = buffer.read + len;
|
|
var arr = [];
|
|
|
|
while (buffer.read < end) {
|
|
arr.push(parseValue(buffer));
|
|
}
|
|
|
|
return arr;
|
|
|
|
default:
|
|
throw new Error("Unknown field value type " + buffer[buffer.read-1]);
|
|
}
|
|
}
|
|
|
|
function parseTable (buffer) {
|
|
var length = buffer.read + parseInt(buffer, 4);
|
|
var table = {};
|
|
|
|
while (buffer.read < length) {
|
|
table[parseShortString(buffer)] = parseValue(buffer);
|
|
}
|
|
|
|
return table;
|
|
}
|
|
|
|
function parseFields (buffer, fields) {
|
|
var args = {};
|
|
var bitIndex = 0;
|
|
var value;
|
|
|
|
for (var i = 0; i < fields.length; i++) {
|
|
var field = fields[i];
|
|
|
|
//debug && debug("parsing field " + field.name + " of type " + field.domain);
|
|
|
|
switch (field.domain) {
|
|
case 'bit':
|
|
// 8 bits can be packed into one octet.
|
|
|
|
// XXX check if bitIndex greater than 7?
|
|
|
|
value = (buffer[buffer.read] & (1 << bitIndex)) ? true : false;
|
|
|
|
if (fields[i+1] && fields[i+1].domain == 'bit') {
|
|
bitIndex++;
|
|
} else {
|
|
bitIndex = 0;
|
|
buffer.read++;
|
|
}
|
|
break;
|
|
|
|
case 'octet':
|
|
value = buffer[buffer.read++];
|
|
break;
|
|
|
|
case 'short':
|
|
value = parseInt(buffer, 2);
|
|
break;
|
|
|
|
case 'long':
|
|
value = parseInt(buffer, 4);
|
|
break;
|
|
|
|
// In a previous version this shared code with 'longlong', which caused problems when passed Date
|
|
// integers. Nobody expects to pass a Buffer here, 53 bits is still 28 million years after 1970, we'll be fine.
|
|
case 'timestamp':
|
|
value = parseInt(buffer, 8);
|
|
break;
|
|
|
|
// JS doesn't support 64-bit Numbers, so we expect if you're using 'longlong' that you've
|
|
// used a Buffer instead
|
|
case 'longlong':
|
|
value = new Buffer(8);
|
|
for (var j = 0; j < 8; j++) {
|
|
value[j] = buffer[buffer.read++];
|
|
}
|
|
break;
|
|
|
|
case 'shortstr':
|
|
value = parseShortString(buffer);
|
|
break;
|
|
|
|
case 'longstr':
|
|
value = parseLongString(buffer);
|
|
break;
|
|
|
|
case 'table':
|
|
value = parseTable(buffer);
|
|
break;
|
|
|
|
default:
|
|
throw new Error("Unhandled parameter type " + field.domain);
|
|
}
|
|
//debug && debug("got " + value);
|
|
args[field.name] = value;
|
|
}
|
|
|
|
return args;
|
|
}
|
|
|
|
|
|
AMQPParser.prototype._parseMethodFrame = function (channel, buffer) {
|
|
buffer.read = 0;
|
|
var classId = parseInt(buffer, 2),
|
|
methodId = parseInt(buffer, 2);
|
|
|
|
// Make sure that this is a method that we understand.
|
|
if (!methodTable[classId] || !methodTable[classId][methodId]) {
|
|
this.throwError("Received unknown [classId, methodId] pair [" +
|
|
classId + ", " + methodId + "]");
|
|
}
|
|
|
|
var method = methodTable[classId][methodId];
|
|
|
|
if (!method) this.throwError("bad method?");
|
|
|
|
var args = parseFields(buffer, method.fields);
|
|
|
|
if (this.onMethod) {
|
|
debug && debug("Executing method", channel, method, args);
|
|
this.onMethod(channel, method, args);
|
|
}
|
|
};
|
|
|
|
|
|
AMQPParser.prototype._parseHeaderFrame = function (channel, buffer) {
|
|
buffer.read = 0;
|
|
|
|
var classIndex = parseInt(buffer, 2);
|
|
var weight = parseInt(buffer, 2);
|
|
var size = parseInt(buffer, 8);
|
|
|
|
var classInfo = classes[classIndex];
|
|
|
|
if (classInfo.fields.length > 15) {
|
|
this.throwError("TODO: support more than 15 properties");
|
|
}
|
|
|
|
var propertyFlags = parseInt(buffer, 2);
|
|
|
|
var fields = [];
|
|
for (var i = 0; i < classInfo.fields.length; i++) {
|
|
var field = classInfo.fields[i];
|
|
// groan.
|
|
if (propertyFlags & (1 << (15-i))) fields.push(field);
|
|
}
|
|
|
|
var properties = parseFields(buffer, fields);
|
|
|
|
if (this.onContentHeader) {
|
|
this.onContentHeader(channel, classInfo, weight, properties, size);
|
|
}
|
|
};
|
|
|
|
}).call(this,_dereq_("buffer").Buffer)
|
|
},{"../jspack":25,"./constants":29,"./debug":30,"./definitions":31,"buffer":128,"events":137,"fs":127,"net":127,"tls":127,"util":159}],35:[function(_dereq_,module,exports){
|
|
(function (process){
|
|
var events = _dereq_('events');
|
|
var inherits = _dereq_('util').inherits;
|
|
|
|
exports.Promise = function () {
|
|
events.EventEmitter.call(this);
|
|
this._blocking = false;
|
|
this.hasFired = false;
|
|
this.hasAcked = false;
|
|
this._values = undefined;
|
|
};
|
|
inherits(exports.Promise, events.EventEmitter);
|
|
|
|
exports.Promise.prototype.timeout = function(timeout) {
|
|
if (!timeout) {
|
|
return this._timeoutDuration;
|
|
}
|
|
|
|
this._timeoutDuration = timeout;
|
|
|
|
if (this.hasFired) return;
|
|
this._clearTimeout();
|
|
|
|
var self = this;
|
|
this._timer = setTimeout(function() {
|
|
self._timer = null;
|
|
if (self.hasFired) {
|
|
return;
|
|
}
|
|
|
|
self.emitError(new Error('timeout'));
|
|
}, timeout);
|
|
|
|
return this;
|
|
};
|
|
|
|
exports.Promise.prototype._clearTimeout = function() {
|
|
if (!this._timer) return;
|
|
|
|
clearTimeout(this._timer);
|
|
this._timer = null;
|
|
}
|
|
|
|
exports.Promise.prototype.emitSuccess = function() {
|
|
if (this.hasFired) return;
|
|
this.hasFired = 'success';
|
|
this._clearTimeout();
|
|
|
|
this._values = Array.prototype.slice.call(arguments);
|
|
this.emit.apply(this, ['success'].concat(this._values));
|
|
};
|
|
|
|
exports.Promise.prototype.emitError = function() {
|
|
if (this.hasFired) return;
|
|
this.hasFired = 'error';
|
|
this._clearTimeout();
|
|
|
|
this._values = Array.prototype.slice.call(arguments);
|
|
this.emit.apply(this, ['error'].concat(this._values));
|
|
|
|
if (this.listeners('error').length == 0) {
|
|
var self = this;
|
|
process.nextTick(function() {
|
|
if (self.listeners('error').length == 0) {
|
|
throw (self._values[0] instanceof Error)
|
|
? self._values[0]
|
|
: new Error('Unhandled emitError: '+JSON.stringify(self._values));
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
exports.Promise.prototype.addCallback = function (listener) {
|
|
if (this.hasFired === 'success') {
|
|
listener.apply(this, this._values);
|
|
}
|
|
|
|
return this.addListener("success", listener);
|
|
};
|
|
|
|
exports.Promise.prototype.addErrback = function (listener) {
|
|
if (this.hasFired === 'error') {
|
|
listener.apply(this, this._values);
|
|
}
|
|
|
|
return this.addListener("error", listener);
|
|
};
|
|
|
|
}).call(this,_dereq_("C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"))
|
|
},{"C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":144,"events":137,"util":159}],36:[function(_dereq_,module,exports){
|
|
(function (process,Buffer){
|
|
'use strict';
|
|
var util = _dereq_('util');
|
|
var fs = _dereq_('fs');
|
|
var _ = _dereq_('lodash');
|
|
var Channel = _dereq_('./channel');
|
|
var Exchange = _dereq_('./exchange');
|
|
var Message = _dereq_('./message');
|
|
var debug = _dereq_('./debug');
|
|
var definitions = _dereq_('./definitions');
|
|
var methods = definitions.methods;
|
|
var classes = definitions.classes;
|
|
|
|
var Queue = module.exports = function Queue (connection, channel, name, options, callback) {
|
|
Channel.call(this, connection, channel);
|
|
|
|
var self = this;
|
|
this.name = name;
|
|
this._bindings = {};
|
|
this.consumerTagListeners = {};
|
|
this.consumerTagOptions = {};
|
|
|
|
// route messages to subscribers based on consumerTag
|
|
this.on('rawMessage', function(message) {
|
|
if (message.consumerTag && self.consumerTagListeners[message.consumerTag]) {
|
|
self.consumerTagListeners[message.consumerTag](message);
|
|
}
|
|
});
|
|
|
|
this.options = { autoDelete: true, closeChannelOnUnsubscribe: false };
|
|
_.extend(this.options, options || {});
|
|
|
|
this._openCallback = callback;
|
|
};
|
|
util.inherits(Queue, Channel);
|
|
|
|
Queue.prototype.subscribeRaw = function (options, messageListener) {
|
|
var self = this;
|
|
|
|
// multiple method signatures
|
|
if (typeof options === "function") {
|
|
messageListener = options;
|
|
options = {};
|
|
}
|
|
|
|
var consumerTag = 'node-amqp-' + process.pid + '-' + Math.random();
|
|
this.consumerTagListeners[consumerTag] = messageListener;
|
|
|
|
options = options || {};
|
|
options['state'] = 'opening';
|
|
this.consumerTagOptions[consumerTag] = options;
|
|
if (options.prefetchCount !== undefined) {
|
|
self.connection._sendMethod(self.channel, methods.basicQos,
|
|
{ reserved1: 0
|
|
, prefetchSize: 0
|
|
, prefetchCount: options.prefetchCount
|
|
, global: false
|
|
});
|
|
}
|
|
|
|
return this._taskPush(methods.basicConsumeOk, function () {
|
|
self.connection._sendMethod(self.channel, methods.basicConsume,
|
|
{ reserved1: 0
|
|
, queue: self.name
|
|
, consumerTag: consumerTag
|
|
, noLocal: !!options.noLocal
|
|
, noAck: !!options.noAck
|
|
, exclusive: !!options.exclusive
|
|
, noWait: false
|
|
, "arguments": {}
|
|
});
|
|
self.consumerTagOptions[consumerTag]['state'] = 'open';
|
|
});
|
|
};
|
|
|
|
Queue.prototype.unsubscribe = function(consumerTag) {
|
|
var self = this;
|
|
return this._taskPush(methods.basicCancelOk, function () {
|
|
self.connection._sendMethod(self.channel, methods.basicCancel,
|
|
{ reserved1: 0,
|
|
consumerTag: consumerTag,
|
|
noWait: false });
|
|
})
|
|
.addCallback(function () {
|
|
if (self.options.closeChannelOnUnsubscribe) {
|
|
self.close();
|
|
}
|
|
delete self.consumerTagListeners[consumerTag];
|
|
delete self.consumerTagOptions[consumerTag];
|
|
});
|
|
};
|
|
|
|
Queue.prototype.subscribe = function (options, messageListener) {
|
|
var self = this;
|
|
|
|
// Optional options
|
|
if (typeof options === "function") {
|
|
messageListener = options;
|
|
options = {};
|
|
}
|
|
|
|
options = _.defaults(options || {}, {
|
|
ack: false,
|
|
prefetchCount: 1,
|
|
routingKeyInPayload: self.connection.options.routingKeyInPayload,
|
|
deliveryTagInPayload: self.connection.options.deliveryTagInPayload
|
|
});
|
|
|
|
// basic consume
|
|
var rawOptions = {
|
|
noAck: !options.ack,
|
|
exclusive: options.exclusive
|
|
};
|
|
|
|
if (options.ack) {
|
|
rawOptions['prefetchCount'] = options.prefetchCount;
|
|
}
|
|
|
|
return this.subscribeRaw(rawOptions, function (m) {
|
|
var contentType = m.contentType;
|
|
|
|
if (contentType == null && m.headers && m.headers.properties) {
|
|
contentType = m.headers.properties.content_type;
|
|
}
|
|
|
|
var isJSON = contentType == 'text/json' ||
|
|
contentType == 'application/json';
|
|
|
|
var buffer;
|
|
|
|
if (isJSON) {
|
|
buffer = "";
|
|
} else {
|
|
buffer = new Buffer(m.size);
|
|
buffer.used = 0;
|
|
}
|
|
|
|
self._lastMessage = m;
|
|
|
|
m.addListener('data', function (d) {
|
|
if (isJSON) {
|
|
buffer += d.toString();
|
|
} else {
|
|
d.copy(buffer, buffer.used);
|
|
buffer.used += d.length;
|
|
}
|
|
});
|
|
|
|
m.addListener('end', function () {
|
|
var json, deliveryInfo = {}, msgProperties = classes[60].fields, i, l;
|
|
|
|
if (isJSON) {
|
|
try {
|
|
json = JSON.parse(buffer);
|
|
} catch (e) {
|
|
json = null;
|
|
deliveryInfo.parseError = e;
|
|
deliveryInfo.rawData = buffer;
|
|
}
|
|
} else {
|
|
json = { data: buffer, contentType: m.contentType };
|
|
}
|
|
|
|
for (i = 0, l = msgProperties.length; i<l; i++) {
|
|
if (m[msgProperties[i].name]) {
|
|
deliveryInfo[msgProperties[i].name] = m[msgProperties[i].name];
|
|
}
|
|
}
|
|
|
|
deliveryInfo.queue = m.queue ? m.queue.name : null;
|
|
deliveryInfo.deliveryTag = m.deliveryTag;
|
|
deliveryInfo.redelivered = m.redelivered;
|
|
deliveryInfo.exchange = m.exchange;
|
|
deliveryInfo.routingKey = m.routingKey;
|
|
deliveryInfo.consumerTag = m.consumerTag;
|
|
|
|
if (options.routingKeyInPayload) json._routingKey = m.routingKey;
|
|
if (options.deliveryTagInPayload) json._deliveryTag = m.deliveryTag;
|
|
|
|
var headers = {};
|
|
for (i in this.headers) {
|
|
if (this.headers.hasOwnProperty(i)) {
|
|
if (this.headers[i] instanceof Buffer) {
|
|
headers[i] = this.headers[i].toString();
|
|
} else {
|
|
headers[i] = this.headers[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (messageListener) messageListener(json, headers, deliveryInfo, m);
|
|
self.emit('message', json, headers, deliveryInfo, m);
|
|
});
|
|
});
|
|
};
|
|
Queue.prototype.subscribeJSON = Queue.prototype.subscribe;
|
|
|
|
/* Acknowledges the last message */
|
|
Queue.prototype.shift = function (reject, requeue) {
|
|
if (this._lastMessage) {
|
|
if (reject) {
|
|
this._lastMessage.reject(requeue ? true : false);
|
|
} else {
|
|
this._lastMessage.acknowledge();
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
Queue.prototype.bind = function (exchange, routingKey, callback) {
|
|
var self = this;
|
|
|
|
// The first argument, exchange is optional.
|
|
// If not supplied the connection will use the 'amq.topic'
|
|
// exchange.
|
|
if (routingKey === undefined || _.isFunction(routingKey)) {
|
|
callback = routingKey;
|
|
routingKey = exchange;
|
|
exchange = 'amq.topic';
|
|
}
|
|
|
|
if (_.isFunction(callback)) this._bindCallback = callback;
|
|
|
|
var exchangeName = exchange instanceof Exchange ? exchange.name : exchange;
|
|
|
|
if (exchangeName in self.connection.exchanges) {
|
|
this.exchange = self.connection.exchanges[exchangeName];
|
|
this.exchange.binds++;
|
|
}
|
|
|
|
// Record this binding so we can restore it upon reconnect.
|
|
if (!this._bindings[exchangeName]) {
|
|
this._bindings[exchangeName] = {};
|
|
}
|
|
|
|
if (!this._bindings[exchangeName][routingKey]) {
|
|
this._bindings[exchangeName][routingKey] = 0;
|
|
}
|
|
|
|
this._bindings[exchangeName][routingKey]++;
|
|
|
|
self.connection._sendMethod(self.channel, methods.queueBind,
|
|
{ reserved1: 0
|
|
, queue: self.name
|
|
, exchange: exchangeName
|
|
, routingKey: routingKey
|
|
, noWait: false
|
|
, "arguments": {}
|
|
});
|
|
|
|
};
|
|
|
|
Queue.prototype.unbind = function (exchange, routingKey) {
|
|
var self = this;
|
|
|
|
// The first argument, exchange is optional.
|
|
// If not supplied the connection will use the default 'amq.topic'
|
|
// exchange.
|
|
if (routingKey === undefined) {
|
|
routingKey = exchange;
|
|
exchange = 'amq.topic';
|
|
}
|
|
|
|
var exchangeName = exchange instanceof Exchange ? exchange.name : exchange;
|
|
|
|
// Decrement binding count.
|
|
this._bindings[exchangeName][routingKey]--;
|
|
if (!this._bindings[exchangeName][routingKey]) {
|
|
delete this._bindings[exchangeName][routingKey];
|
|
}
|
|
|
|
// If there are no more bindings to this exchange, delete the key for the exchange.
|
|
if (!_.keys(this._bindings[exchangeName]).length){
|
|
delete this._bindings[exchangeName];
|
|
}
|
|
|
|
return this._taskPush(methods.queueUnbindOk, function () {
|
|
self.connection._sendMethod(self.channel, methods.queueUnbind,
|
|
{ reserved1: 0
|
|
, queue: self.name
|
|
, exchange: exchangeName
|
|
, routingKey: routingKey
|
|
, noWait: false
|
|
, "arguments": {}
|
|
});
|
|
});
|
|
};
|
|
|
|
Queue.prototype.bind_headers = function (/* [exchange,] matchingPairs */) {
|
|
var self = this;
|
|
|
|
// The first argument, exchange is optional.
|
|
// If not supplied the connection will use the default 'amq.headers'
|
|
// exchange.
|
|
|
|
var exchange, matchingPairs;
|
|
|
|
if (arguments.length == 2) {
|
|
exchange = arguments[0];
|
|
matchingPairs = arguments[1];
|
|
} else {
|
|
exchange = 'amq.headers';
|
|
matchingPairs = arguments[0];
|
|
}
|
|
|
|
|
|
return this._taskPush(methods.queueBindOk, function () {
|
|
var exchangeName = exchange instanceof Exchange ? exchange.name : exchange;
|
|
self.connection._sendMethod(self.channel, methods.queueBind,
|
|
{ reserved1: 0
|
|
, queue: self.name
|
|
, exchange: exchangeName
|
|
, routingKey: ''
|
|
, noWait: false
|
|
, "arguments": matchingPairs
|
|
});
|
|
});
|
|
};
|
|
|
|
Queue.prototype.unbind_headers = function (/* [exchange,] matchingPairs */) {
|
|
var self = this;
|
|
|
|
// The first argument, exchange is optional.
|
|
// If not supplied the connection will use the default 'amq.topic'
|
|
// exchange.
|
|
|
|
var exchange, matchingPairs;
|
|
|
|
if (arguments.length === 2) {
|
|
exchange = arguments[0];
|
|
matchingPairs = arguments[1];
|
|
} else {
|
|
exchange = 'amq.headers';
|
|
matchingPairs = arguments[0];
|
|
}
|
|
|
|
return this._taskPush(methods.queueUnbindOk, function () {
|
|
var exchangeName = exchange instanceof Exchange ? exchange.name : exchange;
|
|
self.connection._sendMethod(self.channel, methods.queueUnbind,
|
|
{ reserved1: 0
|
|
, queue: self.name
|
|
, exchange: exchangeName
|
|
, routingKey: ''
|
|
, noWait: false
|
|
, "arguments": matchingPairs
|
|
});
|
|
});
|
|
};
|
|
|
|
Queue.prototype.destroy = function (options) {
|
|
var self = this;
|
|
|
|
options = options || {};
|
|
return this._taskPush(methods.queueDeleteOk, function () {
|
|
self.connection.queueClosed(self.name);
|
|
if ('exchange' in self) {
|
|
self.exchange.binds--;
|
|
self.exchange.cleanup();
|
|
}
|
|
self.connection._sendMethod(self.channel, methods.queueDelete,
|
|
{ reserved1: 0
|
|
, queue: self.name
|
|
, ifUnused: options.ifUnused ? true : false
|
|
, ifEmpty: options.ifEmpty ? true : false
|
|
, noWait: false
|
|
, "arguments": {}
|
|
});
|
|
});
|
|
};
|
|
|
|
Queue.prototype.purge = function() {
|
|
var self = this;
|
|
return this._taskPush(methods.queuePurgeOk, function () {
|
|
self.connection._sendMethod(self.channel, methods.queuePurge,
|
|
{ reserved1 : 0,
|
|
queue: self.name,
|
|
noWait: false});
|
|
});
|
|
};
|
|
|
|
|
|
Queue.prototype._onMethod = function (channel, method, args) {
|
|
var self = this;
|
|
this.emit(method.name, args);
|
|
if (this._handleTaskReply.apply(this, arguments)) return;
|
|
|
|
switch (method) {
|
|
case methods.channelOpenOk:
|
|
if (this.options.noDeclare) {
|
|
this.state = 'open';
|
|
|
|
if (this._openCallback) {
|
|
this._openCallback(this);
|
|
this._openCallback = null;
|
|
}
|
|
|
|
this.emit('open');
|
|
} else {
|
|
if (this.name.indexOf('amq.') == 0) {
|
|
this.name = '';
|
|
}
|
|
this.connection._sendMethod(channel, methods.queueDeclare,
|
|
{ reserved1: 0
|
|
, queue: this.name
|
|
, passive: !!this.options.passive
|
|
, durable: !!this.options.durable
|
|
, exclusive: !!this.options.exclusive
|
|
, autoDelete: !!this.options.autoDelete
|
|
, noWait: false
|
|
, "arguments": this.options.arguments || {}
|
|
});
|
|
this.state = "declare queue";
|
|
}
|
|
break;
|
|
|
|
case methods.queueDeclareOk:
|
|
this.state = 'open';
|
|
this.name = args.queue;
|
|
this.connection.queues[this.name] = this;
|
|
|
|
// Rebind to previously bound exchanges, if present.
|
|
// Important this is called *before* openCallback, otherwise bindings will happen twice.
|
|
// Run test-purge to make sure you got this right
|
|
_.each(this._bindings, function(exchange, exchangeName){
|
|
_.each(exchange, function(count, routingKey){
|
|
self.bind(exchangeName, routingKey);
|
|
});
|
|
});
|
|
|
|
// Call opening callback (passed in function)
|
|
// FIXME use eventemitter - maybe we call a namespaced event here
|
|
if (this._openCallback) {
|
|
this._openCallback(this, args.messageCount, args.consumerCount);
|
|
this._openCallback = null;
|
|
}
|
|
|
|
// TODO this is legacy interface, remove me
|
|
this.emit('open', args.queue, args.messageCount, args.consumerCount);
|
|
|
|
// If this is a reconnect, we must re-subscribe our queue listeners.
|
|
var consumerTags = Object.keys(this.consumerTagListeners);
|
|
for (var index in consumerTags) {
|
|
if (consumerTags.hasOwnProperty(index)) {
|
|
if (this.consumerTagOptions[consumerTags[index]]['state'] === 'closed') {
|
|
this.subscribeRaw(this.consumerTagOptions[consumerTags[index]], this.consumerTagListeners[consumerTags[index]]);
|
|
// Having called subscribeRaw, we are now a new consumer with a new consumerTag.
|
|
delete this.consumerTagListeners[consumerTags[index]];
|
|
delete this.consumerTagOptions[consumerTags[index]];
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case methods.basicConsumeOk:
|
|
debug && debug('basicConsumeOk', util.inspect(args, null));
|
|
break;
|
|
|
|
case methods.queueBindOk:
|
|
if (this._bindCallback) {
|
|
// setting this._bindCallback to null before calling the callback allows for a subsequent bind within the callback
|
|
// FIXME use eventemitter
|
|
var cb = this._bindCallback;
|
|
this._bindCallback = null;
|
|
cb(this);
|
|
}
|
|
break;
|
|
|
|
case methods.queueUnbindOk:
|
|
break;
|
|
|
|
case methods.basicQosOk:
|
|
break;
|
|
|
|
case methods.confirmSelectOk:
|
|
this._sequence = 1;
|
|
this.confirm = true;
|
|
break;
|
|
|
|
case methods.channelClose:
|
|
this.state = "closed";
|
|
this.closeOK();
|
|
this.connection.queueClosed(this.name);
|
|
var e = new Error(args.replyText);
|
|
e.code = args.replyCode;
|
|
this.emit('error', e);
|
|
this.emit('close');
|
|
break;
|
|
|
|
case methods.channelCloseOk:
|
|
this.connection.queueClosed(this.name);
|
|
this.emit('close');
|
|
break;
|
|
|
|
case methods.basicDeliver:
|
|
this.currentMessage = new Message(this, args);
|
|
break;
|
|
|
|
case methods.queueDeleteOk:
|
|
break;
|
|
|
|
case methods.basicCancel:
|
|
this.close("Closed due to basicCancel received on consumer (" + args.consumerTag + ")");
|
|
break;
|
|
|
|
default:
|
|
throw new Error("Uncaught method '" + method.name + "' with args " +
|
|
JSON.stringify(args) + "; tasks = " + JSON.stringify(this._tasks));
|
|
}
|
|
|
|
this._tasksFlush();
|
|
};
|
|
|
|
|
|
Queue.prototype._onContentHeader = function (channel, classInfo, weight, properties, size) {
|
|
_.extend(this.currentMessage, properties);
|
|
this.currentMessage.read = 0;
|
|
this.currentMessage.size = size;
|
|
|
|
this.emit('rawMessage', this.currentMessage);
|
|
if (size === 0) {
|
|
// If the message has no body, directly emit 'end'
|
|
this.currentMessage.emit('end');
|
|
}
|
|
};
|
|
|
|
Queue.prototype._onContent = function (channel, data) {
|
|
this.currentMessage.read += data.length;
|
|
this.currentMessage.emit('data', data);
|
|
if (this.currentMessage.read == this.currentMessage.size) {
|
|
this.currentMessage.emit('end');
|
|
}
|
|
};
|
|
|
|
Queue.prototype.flow = function(active) {
|
|
var self = this;
|
|
return this._taskPush(methods.channelFlowOk, function () {
|
|
self.connection._sendMethod(self.channel, methods.channelFlow, {'active': active });
|
|
});
|
|
};
|
|
|
|
}).call(this,_dereq_("C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"),_dereq_("buffer").Buffer)
|
|
},{"./channel":27,"./debug":30,"./definitions":31,"./exchange":32,"./message":33,"C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":144,"buffer":128,"fs":127,"lodash":38,"util":159}],37:[function(_dereq_,module,exports){
|
|
(function (Buffer){
|
|
'use strict';
|
|
|
|
var jspack = _dereq_('../jspack').jspack;
|
|
|
|
var serializer = module.exports = {
|
|
serializeFloat: function(b, size, value, bigEndian) {
|
|
var jp = new jspack(bigEndian);
|
|
|
|
switch(size) {
|
|
case 4:
|
|
var x = jp.Pack('f', [value]);
|
|
for (var i = 0; i < x.length; ++i)
|
|
b[b.used++] = x[i];
|
|
break;
|
|
|
|
case 8:
|
|
var x = jp.Pack('d', [value]);
|
|
for (var i = 0; i < x.length; ++i)
|
|
b[b.used++] = x[i];
|
|
break;
|
|
|
|
default:
|
|
throw new Error("Unknown floating point size");
|
|
}
|
|
},
|
|
|
|
serializeInt: function (b, size, int) {
|
|
if (b.used + size > b.length) {
|
|
throw new Error("write out of bounds");
|
|
}
|
|
|
|
// Only 4 cases - just going to be explicit instead of looping.
|
|
|
|
switch (size) {
|
|
// octet
|
|
case 1:
|
|
b[b.used++] = int;
|
|
break;
|
|
|
|
// short
|
|
case 2:
|
|
b[b.used++] = (int & 0xFF00) >> 8;
|
|
b[b.used++] = (int & 0x00FF) >> 0;
|
|
break;
|
|
|
|
// long
|
|
case 4:
|
|
b[b.used++] = (int & 0xFF000000) >> 24;
|
|
b[b.used++] = (int & 0x00FF0000) >> 16;
|
|
b[b.used++] = (int & 0x0000FF00) >> 8;
|
|
b[b.used++] = (int & 0x000000FF) >> 0;
|
|
break;
|
|
|
|
|
|
// long long
|
|
case 8:
|
|
b[b.used++] = (int & 0xFF00000000000000) >> 56;
|
|
b[b.used++] = (int & 0x00FF000000000000) >> 48;
|
|
b[b.used++] = (int & 0x0000FF0000000000) >> 40;
|
|
b[b.used++] = (int & 0x000000FF00000000) >> 32;
|
|
b[b.used++] = (int & 0x00000000FF000000) >> 24;
|
|
b[b.used++] = (int & 0x0000000000FF0000) >> 16;
|
|
b[b.used++] = (int & 0x000000000000FF00) >> 8;
|
|
b[b.used++] = (int & 0x00000000000000FF) >> 0;
|
|
break;
|
|
|
|
default:
|
|
throw new Error("Bad size");
|
|
}
|
|
},
|
|
|
|
|
|
serializeShortString: function (b, string) {
|
|
if (typeof(string) != "string") {
|
|
throw new Error("param must be a string");
|
|
}
|
|
var byteLength = Buffer.byteLength(string, 'utf8');
|
|
if (byteLength > 0xFF) {
|
|
throw new Error("String too long for 'shortstr' parameter");
|
|
}
|
|
if (1 + byteLength + b.used >= b.length) {
|
|
throw new Error("Not enough space in buffer for 'shortstr'");
|
|
}
|
|
b[b.used++] = byteLength;
|
|
b.write(string, b.used, 'utf8');
|
|
b.used += byteLength;
|
|
},
|
|
|
|
serializeLongString: function(b, string) {
|
|
// we accept string, object, or buffer for this parameter.
|
|
// in the case of string we serialize it to utf8.
|
|
if (typeof(string) == 'string') {
|
|
var byteLength = Buffer.byteLength(string, 'utf8');
|
|
serializer.serializeInt(b, 4, byteLength);
|
|
b.write(string, b.used, 'utf8');
|
|
b.used += byteLength;
|
|
} else if (typeof(string) == 'object') {
|
|
serializer.serializeTable(b, string);
|
|
} else {
|
|
// data is Buffer
|
|
var byteLength = string.length;
|
|
serializer.serializeInt(b, 4, byteLength);
|
|
b.write(string, b.used); // memcpy
|
|
b.used += byteLength;
|
|
}
|
|
},
|
|
|
|
serializeDate: function(b, date) {
|
|
serializer.serializeInt(b, 8, date.valueOf() / 1000);
|
|
},
|
|
|
|
serializeBuffer: function(b, buffer) {
|
|
serializer.serializeInt(b, 4, buffer.length);
|
|
buffer.copy(b, b.used, 0);
|
|
b.used += buffer.length;
|
|
},
|
|
|
|
serializeBase64: function(b, buffer) {
|
|
serializer.serializeLongString(b, buffer.toString('base64'));
|
|
},
|
|
|
|
isBigInt: function(value) {
|
|
return value > 0xffffffff;
|
|
},
|
|
|
|
getCode: function(dec) {
|
|
var hexArray = "0123456789ABCDEF".split('');
|
|
var code1 = Math.floor(dec / 16);
|
|
var code2 = dec - code1 * 16;
|
|
return hexArray[code2];
|
|
},
|
|
|
|
isFloat: function(value){
|
|
return value === +value && value !== (value|0);
|
|
},
|
|
|
|
serializeValue: function(b, value) {
|
|
switch (typeof(value)) {
|
|
case 'string':
|
|
b[b.used++] = 'S'.charCodeAt(0);
|
|
serializer.serializeLongString(b, value);
|
|
break;
|
|
|
|
case 'number':
|
|
if (!serializer.isFloat(value)) {
|
|
if (serializer.isBigInt(value)) {
|
|
// 64-bit uint
|
|
b[b.used++] = 'l'.charCodeAt(0);
|
|
serializer.serializeInt(b, 8, value);
|
|
} else {
|
|
//32-bit uint
|
|
b[b.used++] = 'I'.charCodeAt(0);
|
|
serializer.serializeInt(b, 4, value);
|
|
}
|
|
} else {
|
|
//64-bit float
|
|
b[b.used++] = 'd'.charCodeAt(0);
|
|
serializer.serializeFloat(b, 8, value);
|
|
}
|
|
break;
|
|
|
|
case 'boolean':
|
|
b[b.used++] = 't'.charCodeAt(0);
|
|
b[b.used++] = value;
|
|
break;
|
|
|
|
default:
|
|
if (value instanceof Date) {
|
|
b[b.used++] = 'T'.charCodeAt(0);
|
|
serializer.serializeDate(b, value);
|
|
} else if (value instanceof Buffer) {
|
|
b[b.used++] = 'x'.charCodeAt(0);
|
|
serializer.serializeBuffer(b, value);
|
|
} else if (Array.isArray(value)) {
|
|
b[b.used++] = 'A'.charCodeAt(0);
|
|
serializer.serializeArray(b, value);
|
|
} else if (typeof(value) === 'object') {
|
|
b[b.used++] = 'F'.charCodeAt(0);
|
|
serializer.serializeTable(b, value);
|
|
} else {
|
|
throw new Error("unsupported type in amqp table: " + typeof(value));
|
|
}
|
|
}
|
|
},
|
|
|
|
serializeTable: function(b, object) {
|
|
if (typeof(object) != "object") {
|
|
throw new Error("param must be an object");
|
|
}
|
|
|
|
// Save our position so that we can go back and write the length of this table
|
|
// at the beginning of the packet (once we know how many entries there are).
|
|
var lengthIndex = b.used;
|
|
b.used += 4; // sizeof long
|
|
var startIndex = b.used;
|
|
|
|
for (var key in object) {
|
|
if (!object.hasOwnProperty(key)) continue;
|
|
serializer.serializeShortString(b, key);
|
|
serializer.serializeValue(b, object[key]);
|
|
}
|
|
|
|
var endIndex = b.used;
|
|
b.used = lengthIndex;
|
|
serializer.serializeInt(b, 4, endIndex - startIndex);
|
|
b.used = endIndex;
|
|
},
|
|
|
|
serializeArray: function(b, arr) {
|
|
// Save our position so that we can go back and write the byte length of this array
|
|
// at the beginning of the packet (once we have serialized all elements).
|
|
var lengthIndex = b.used;
|
|
b.used += 4; // sizeof long
|
|
var startIndex = b.used;
|
|
|
|
var len = arr.length;
|
|
for (var i = 0; i < len; i++) {
|
|
serializer.serializeValue(b, arr[i]);
|
|
}
|
|
|
|
var endIndex = b.used;
|
|
b.used = lengthIndex;
|
|
serializer.serializeInt(b, 4, endIndex - startIndex);
|
|
b.used = endIndex;
|
|
},
|
|
|
|
serializeFields: function(buffer, fields, args, strict) {
|
|
var bitField = 0;
|
|
var bitIndex = 0;
|
|
for (var i = 0; i < fields.length; i++) {
|
|
var field = fields[i];
|
|
var domain = field.domain;
|
|
if (!(field.name in args)) {
|
|
if (strict) {
|
|
throw new Error("Missing field '" + field.name + "' of type '" + domain + "' while executing AMQP method '" +
|
|
arguments.callee.caller.arguments[1].name + "'");
|
|
}
|
|
continue;
|
|
}
|
|
|
|
var param = args[field.name];
|
|
|
|
//debug("domain: " + domain + " param: " + param);
|
|
|
|
switch (domain) {
|
|
case 'bit':
|
|
if (typeof(param) != "boolean") {
|
|
throw new Error("Unmatched field " + JSON.stringify(field));
|
|
}
|
|
|
|
if (param) bitField |= (1 << bitIndex);
|
|
bitIndex++;
|
|
|
|
if (!fields[i+1] || fields[i+1].domain != 'bit') {
|
|
//debug('SET bit field ' + field.name + ' 0x' + bitField.toString(16));
|
|
buffer[buffer.used++] = bitField;
|
|
bitField = 0;
|
|
bitIndex = 0;
|
|
}
|
|
break;
|
|
|
|
case 'octet':
|
|
if (typeof(param) != "number" || param > 0xFF) {
|
|
throw new Error("Unmatched field " + JSON.stringify(field));
|
|
}
|
|
buffer[buffer.used++] = param;
|
|
break;
|
|
|
|
case 'short':
|
|
if (typeof(param) != "number" || param > 0xFFFF) {
|
|
throw new Error("Unmatched field " + JSON.stringify(field));
|
|
}
|
|
serializer.serializeInt(buffer, 2, param);
|
|
break;
|
|
|
|
case 'long':
|
|
if (typeof(param) != "number" || param > 0xFFFFFFFF) {
|
|
throw new Error("Unmatched field " + JSON.stringify(field));
|
|
}
|
|
serializer.serializeInt(buffer, 4, param);
|
|
break;
|
|
|
|
// In a previous version this shared code with 'longlong', which caused problems when passed Date
|
|
// integers. Nobody expects to pass a Buffer here, 53 bits is still 28 million years after 1970, we'll be fine.
|
|
case 'timestamp':
|
|
serializer.serializeInt(buffer, 8, param);
|
|
break;
|
|
|
|
case 'longlong':
|
|
for (var j = 0; j < 8; j++) {
|
|
buffer[buffer.used++] = param[j];
|
|
}
|
|
break;
|
|
|
|
case 'shortstr':
|
|
if (typeof(param) != "string" || param.length > 0xFF) {
|
|
throw new Error("Unmatched field " + JSON.stringify(field));
|
|
}
|
|
serializer.serializeShortString(buffer, param);
|
|
break;
|
|
|
|
case 'longstr':
|
|
serializer.serializeLongString(buffer, param);
|
|
break;
|
|
|
|
case 'table':
|
|
if (typeof(param) != "object") {
|
|
throw new Error("Unmatched field " + JSON.stringify(field));
|
|
}
|
|
serializer.serializeTable(buffer, param);
|
|
break;
|
|
|
|
default:
|
|
throw new Error("Unknown domain value type " + domain);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
}).call(this,_dereq_("buffer").Buffer)
|
|
},{"../jspack":25,"buffer":128}],38:[function(_dereq_,module,exports){
|
|
(function (global){
|
|
/**
|
|
* @license
|
|
* Lo-Dash 1.3.1 (Custom Build) <http://lodash.com/>
|
|
* Build: `lodash modern -o ./dist/lodash.js`
|
|
* Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
|
|
* Based on Underscore.js 1.4.4 <http://underscorejs.org/>
|
|
* Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
|
|
* Available under MIT license <http://lodash.com/license>
|
|
*/
|
|
;(function(window) {
|
|
|
|
/** Used as a safe reference for `undefined` in pre ES5 environments */
|
|
var undefined;
|
|
|
|
/** Used to pool arrays and objects used internally */
|
|
var arrayPool = [],
|
|
objectPool = [];
|
|
|
|
/** Used to generate unique IDs */
|
|
var idCounter = 0;
|
|
|
|
/** Used internally to indicate various things */
|
|
var indicatorObject = {};
|
|
|
|
/** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
|
|
var keyPrefix = +new Date + '';
|
|
|
|
/** Used as the size when optimizations are enabled for large arrays */
|
|
var largeArraySize = 75;
|
|
|
|
/** Used as the max size of the `arrayPool` and `objectPool` */
|
|
var maxPoolSize = 40;
|
|
|
|
/** Used to match empty string literals in compiled template source */
|
|
var reEmptyStringLeading = /\b__p \+= '';/g,
|
|
reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
|
|
reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
|
|
|
|
/** Used to match HTML entities */
|
|
var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g;
|
|
|
|
/**
|
|
* Used to match ES6 template delimiters
|
|
* http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.6
|
|
*/
|
|
var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
|
|
|
|
/** Used to match regexp flags from their coerced string values */
|
|
var reFlags = /\w*$/;
|
|
|
|
/** Used to match "interpolate" template delimiters */
|
|
var reInterpolate = /<%=([\s\S]+?)%>/g;
|
|
|
|
/** Used to detect functions containing a `this` reference */
|
|
var reThis = (reThis = /\bthis\b/) && reThis.test(runInContext) && reThis;
|
|
|
|
/** Used to detect and test whitespace */
|
|
var whitespace = (
|
|
// whitespace
|
|
' \t\x0B\f\xA0\ufeff' +
|
|
|
|
// line terminators
|
|
'\n\r\u2028\u2029' +
|
|
|
|
// unicode category "Zs" space separators
|
|
'\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000'
|
|
);
|
|
|
|
/** Used to match leading whitespace and zeros to be removed */
|
|
var reLeadingSpacesAndZeros = RegExp('^[' + whitespace + ']*0+(?=.$)');
|
|
|
|
/** Used to ensure capturing order of template delimiters */
|
|
var reNoMatch = /($^)/;
|
|
|
|
/** Used to match HTML characters */
|
|
var reUnescapedHtml = /[&<>"']/g;
|
|
|
|
/** Used to match unescaped characters in compiled string literals */
|
|
var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
|
|
|
|
/** Used to assign default `context` object properties */
|
|
var contextProps = [
|
|
'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object',
|
|
'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
|
|
'parseInt', 'setImmediate', 'setTimeout'
|
|
];
|
|
|
|
/** Used to make template sourceURLs easier to identify */
|
|
var templateCounter = 0;
|
|
|
|
/** `Object#toString` result shortcuts */
|
|
var argsClass = '[object Arguments]',
|
|
arrayClass = '[object Array]',
|
|
boolClass = '[object Boolean]',
|
|
dateClass = '[object Date]',
|
|
errorClass = '[object Error]',
|
|
funcClass = '[object Function]',
|
|
numberClass = '[object Number]',
|
|
objectClass = '[object Object]',
|
|
regexpClass = '[object RegExp]',
|
|
stringClass = '[object String]';
|
|
|
|
/** Used to identify object classifications that `_.clone` supports */
|
|
var cloneableClasses = {};
|
|
cloneableClasses[funcClass] = false;
|
|
cloneableClasses[argsClass] = cloneableClasses[arrayClass] =
|
|
cloneableClasses[boolClass] = cloneableClasses[dateClass] =
|
|
cloneableClasses[numberClass] = cloneableClasses[objectClass] =
|
|
cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true;
|
|
|
|
/** Used to determine if values are of the language type Object */
|
|
var objectTypes = {
|
|
'boolean': false,
|
|
'function': true,
|
|
'object': true,
|
|
'number': false,
|
|
'string': false,
|
|
'undefined': false
|
|
};
|
|
|
|
/** Used to escape characters for inclusion in compiled string literals */
|
|
var stringEscapes = {
|
|
'\\': '\\',
|
|
"'": "'",
|
|
'\n': 'n',
|
|
'\r': 'r',
|
|
'\t': 't',
|
|
'\u2028': 'u2028',
|
|
'\u2029': 'u2029'
|
|
};
|
|
|
|
/** Detect free variable `exports` */
|
|
var freeExports = objectTypes[typeof exports] && exports;
|
|
|
|
/** Detect free variable `module` */
|
|
var freeModule = objectTypes[typeof module] && module && module.exports == freeExports && module;
|
|
|
|
/** Detect free variable `global`, from Node.js or Browserified code, and use it as `window` */
|
|
var freeGlobal = objectTypes[typeof global] && global;
|
|
if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
|
|
window = freeGlobal;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* A basic implementation of `_.indexOf` without support for binary searches
|
|
* or `fromIndex` constraints.
|
|
*
|
|
* @private
|
|
* @param {Array} array The array to search.
|
|
* @param {Mixed} value The value to search for.
|
|
* @param {Number} [fromIndex=0] The index to search from.
|
|
* @returns {Number} Returns the index of the matched value or `-1`.
|
|
*/
|
|
function basicIndexOf(array, value, fromIndex) {
|
|
var index = (fromIndex || 0) - 1,
|
|
length = array.length;
|
|
|
|
while (++index < length) {
|
|
if (array[index] === value) {
|
|
return index;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* An implementation of `_.contains` for cache objects that mimics the return
|
|
* signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
|
|
*
|
|
* @private
|
|
* @param {Object} cache The cache object to inspect.
|
|
* @param {Mixed} value The value to search for.
|
|
* @returns {Number} Returns `0` if `value` is found, else `-1`.
|
|
*/
|
|
function cacheIndexOf(cache, value) {
|
|
var type = typeof value;
|
|
cache = cache.cache;
|
|
|
|
if (type == 'boolean' || value == null) {
|
|
return cache[value];
|
|
}
|
|
if (type != 'number' && type != 'string') {
|
|
type = 'object';
|
|
}
|
|
var key = type == 'number' ? value : keyPrefix + value;
|
|
cache = cache[type] || (cache[type] = {});
|
|
|
|
return type == 'object'
|
|
? (cache[key] && basicIndexOf(cache[key], value) > -1 ? 0 : -1)
|
|
: (cache[key] ? 0 : -1);
|
|
}
|
|
|
|
/**
|
|
* Adds a given `value` to the corresponding cache object.
|
|
*
|
|
* @private
|
|
* @param {Mixed} value The value to add to the cache.
|
|
*/
|
|
function cachePush(value) {
|
|
var cache = this.cache,
|
|
type = typeof value;
|
|
|
|
if (type == 'boolean' || value == null) {
|
|
cache[value] = true;
|
|
} else {
|
|
if (type != 'number' && type != 'string') {
|
|
type = 'object';
|
|
}
|
|
var key = type == 'number' ? value : keyPrefix + value,
|
|
typeCache = cache[type] || (cache[type] = {});
|
|
|
|
if (type == 'object') {
|
|
if ((typeCache[key] || (typeCache[key] = [])).push(value) == this.array.length) {
|
|
cache[type] = false;
|
|
}
|
|
} else {
|
|
typeCache[key] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Used by `_.max` and `_.min` as the default `callback` when a given
|
|
* `collection` is a string value.
|
|
*
|
|
* @private
|
|
* @param {String} value The character to inspect.
|
|
* @returns {Number} Returns the code unit of given character.
|
|
*/
|
|
function charAtCallback(value) {
|
|
return value.charCodeAt(0);
|
|
}
|
|
|
|
/**
|
|
* Used by `sortBy` to compare transformed `collection` values, stable sorting
|
|
* them in ascending order.
|
|
*
|
|
* @private
|
|
* @param {Object} a The object to compare to `b`.
|
|
* @param {Object} b The object to compare to `a`.
|
|
* @returns {Number} Returns the sort order indicator of `1` or `-1`.
|
|
*/
|
|
function compareAscending(a, b) {
|
|
var ai = a.index,
|
|
bi = b.index;
|
|
|
|
a = a.criteria;
|
|
b = b.criteria;
|
|
|
|
// ensure a stable sort in V8 and other engines
|
|
// http://code.google.com/p/v8/issues/detail?id=90
|
|
if (a !== b) {
|
|
if (a > b || typeof a == 'undefined') {
|
|
return 1;
|
|
}
|
|
if (a < b || typeof b == 'undefined') {
|
|
return -1;
|
|
}
|
|
}
|
|
return ai < bi ? -1 : 1;
|
|
}
|
|
|
|
/**
|
|
* Creates a cache object to optimize linear searches of large arrays.
|
|
*
|
|
* @private
|
|
* @param {Array} [array=[]] The array to search.
|
|
* @returns {Null|Object} Returns the cache object or `null` if caching should not be used.
|
|
*/
|
|
function createCache(array) {
|
|
var index = -1,
|
|
length = array.length;
|
|
|
|
var cache = getObject();
|
|
cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
|
|
|
|
var result = getObject();
|
|
result.array = array;
|
|
result.cache = cache;
|
|
result.push = cachePush;
|
|
|
|
while (++index < length) {
|
|
result.push(array[index]);
|
|
}
|
|
return cache.object === false
|
|
? (releaseObject(result), null)
|
|
: result;
|
|
}
|
|
|
|
/**
|
|
* Used by `template` to escape characters for inclusion in compiled
|
|
* string literals.
|
|
*
|
|
* @private
|
|
* @param {String} match The matched character to escape.
|
|
* @returns {String} Returns the escaped character.
|
|
*/
|
|
function escapeStringChar(match) {
|
|
return '\\' + stringEscapes[match];
|
|
}
|
|
|
|
/**
|
|
* Gets an array from the array pool or creates a new one if the pool is empty.
|
|
*
|
|
* @private
|
|
* @returns {Array} The array from the pool.
|
|
*/
|
|
function getArray() {
|
|
return arrayPool.pop() || [];
|
|
}
|
|
|
|
/**
|
|
* Gets an object from the object pool or creates a new one if the pool is empty.
|
|
*
|
|
* @private
|
|
* @returns {Object} The object from the pool.
|
|
*/
|
|
function getObject() {
|
|
return objectPool.pop() || {
|
|
'array': null,
|
|
'cache': null,
|
|
'criteria': null,
|
|
'false': false,
|
|
'index': 0,
|
|
'leading': false,
|
|
'maxWait': 0,
|
|
'null': false,
|
|
'number': null,
|
|
'object': null,
|
|
'push': null,
|
|
'string': null,
|
|
'trailing': false,
|
|
'true': false,
|
|
'undefined': false,
|
|
'value': null
|
|
};
|
|
}
|
|
|
|
/**
|
|
* A no-operation function.
|
|
*
|
|
* @private
|
|
*/
|
|
function noop() {
|
|
// no operation performed
|
|
}
|
|
|
|
/**
|
|
* Releases the given `array` back to the array pool.
|
|
*
|
|
* @private
|
|
* @param {Array} [array] The array to release.
|
|
*/
|
|
function releaseArray(array) {
|
|
array.length = 0;
|
|
if (arrayPool.length < maxPoolSize) {
|
|
arrayPool.push(array);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Releases the given `object` back to the object pool.
|
|
*
|
|
* @private
|
|
* @param {Object} [object] The object to release.
|
|
*/
|
|
function releaseObject(object) {
|
|
var cache = object.cache;
|
|
if (cache) {
|
|
releaseObject(cache);
|
|
}
|
|
object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
|
|
if (objectPool.length < maxPoolSize) {
|
|
objectPool.push(object);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Slices the `collection` from the `start` index up to, but not including,
|
|
* the `end` index.
|
|
*
|
|
* Note: This function is used, instead of `Array#slice`, to support node lists
|
|
* in IE < 9 and to ensure dense arrays are returned.
|
|
*
|
|
* @private
|
|
* @param {Array|Object|String} collection The collection to slice.
|
|
* @param {Number} start The start index.
|
|
* @param {Number} end The end index.
|
|
* @returns {Array} Returns the new array.
|
|
*/
|
|
function slice(array, start, end) {
|
|
start || (start = 0);
|
|
if (typeof end == 'undefined') {
|
|
end = array ? array.length : 0;
|
|
}
|
|
var index = -1,
|
|
length = end - start || 0,
|
|
result = Array(length < 0 ? 0 : length);
|
|
|
|
while (++index < length) {
|
|
result[index] = array[start + index];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Create a new `lodash` function using the given `context` object.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Object} [context=window] The context object.
|
|
* @returns {Function} Returns the `lodash` function.
|
|
*/
|
|
function runInContext(context) {
|
|
// Avoid issues with some ES3 environments that attempt to use values, named
|
|
// after built-in constructors like `Object`, for the creation of literals.
|
|
// ES5 clears this up by stating that literals must use built-in constructors.
|
|
// See http://es5.github.com/#x11.1.5.
|
|
context = context ? _.defaults(window.Object(), context, _.pick(window, contextProps)) : window;
|
|
|
|
/** Native constructor references */
|
|
var Array = context.Array,
|
|
Boolean = context.Boolean,
|
|
Date = context.Date,
|
|
Function = context.Function,
|
|
Math = context.Math,
|
|
Number = context.Number,
|
|
Object = context.Object,
|
|
RegExp = context.RegExp,
|
|
String = context.String,
|
|
TypeError = context.TypeError;
|
|
|
|
/**
|
|
* Used for `Array` method references.
|
|
*
|
|
* Normally `Array.prototype` would suffice, however, using an array literal
|
|
* avoids issues in Narwhal.
|
|
*/
|
|
var arrayRef = [];
|
|
|
|
/** Used for native method references */
|
|
var objectProto = Object.prototype,
|
|
stringProto = String.prototype;
|
|
|
|
/** Used to restore the original `_` reference in `noConflict` */
|
|
var oldDash = context._;
|
|
|
|
/** Used to detect if a method is native */
|
|
var reNative = RegExp('^' +
|
|
String(objectProto.valueOf)
|
|
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
.replace(/valueOf|for [^\]]+/g, '.+?') + '$'
|
|
);
|
|
|
|
/** Native method shortcuts */
|
|
var ceil = Math.ceil,
|
|
clearTimeout = context.clearTimeout,
|
|
concat = arrayRef.concat,
|
|
floor = Math.floor,
|
|
fnToString = Function.prototype.toString,
|
|
getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
|
|
hasOwnProperty = objectProto.hasOwnProperty,
|
|
push = arrayRef.push,
|
|
propertyIsEnumerable = objectProto.propertyIsEnumerable,
|
|
setImmediate = context.setImmediate,
|
|
setTimeout = context.setTimeout,
|
|
toString = objectProto.toString;
|
|
|
|
/* Native method shortcuts for methods with the same name as other `lodash` methods */
|
|
var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind,
|
|
nativeCreate = reNative.test(nativeCreate = Object.create) && nativeCreate,
|
|
nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray,
|
|
nativeIsFinite = context.isFinite,
|
|
nativeIsNaN = context.isNaN,
|
|
nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys,
|
|
nativeMax = Math.max,
|
|
nativeMin = Math.min,
|
|
nativeParseInt = context.parseInt,
|
|
nativeRandom = Math.random,
|
|
nativeSlice = arrayRef.slice;
|
|
|
|
/** Detect various environments */
|
|
var isIeOpera = reNative.test(context.attachEvent),
|
|
isV8 = nativeBind && !/\n|true/.test(nativeBind + isIeOpera);
|
|
|
|
/** Used to lookup a built-in constructor by [[Class]] */
|
|
var ctorByClass = {};
|
|
ctorByClass[arrayClass] = Array;
|
|
ctorByClass[boolClass] = Boolean;
|
|
ctorByClass[dateClass] = Date;
|
|
ctorByClass[funcClass] = Function;
|
|
ctorByClass[objectClass] = Object;
|
|
ctorByClass[numberClass] = Number;
|
|
ctorByClass[regexpClass] = RegExp;
|
|
ctorByClass[stringClass] = String;
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Creates a `lodash` object, which wraps the given `value`, to enable method
|
|
* chaining.
|
|
*
|
|
* In addition to Lo-Dash methods, wrappers also have the following `Array` methods:
|
|
* `concat`, `join`, `pop`, `push`, `reverse`, `shift`, `slice`, `sort`, `splice`,
|
|
* and `unshift`
|
|
*
|
|
* Chaining is supported in custom builds as long as the `value` method is
|
|
* implicitly or explicitly included in the build.
|
|
*
|
|
* The chainable wrapper functions are:
|
|
* `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`,
|
|
* `compose`, `concat`, `countBy`, `createCallback`, `debounce`, `defaults`,
|
|
* `defer`, `delay`, `difference`, `filter`, `flatten`, `forEach`, `forIn`,
|
|
* `forOwn`, `functions`, `groupBy`, `initial`, `intersection`, `invert`,
|
|
* `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`,
|
|
* `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `push`, `range`,
|
|
* `reject`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`, `splice`,
|
|
* `tap`, `throttle`, `times`, `toArray`, `transform`, `union`, `uniq`, `unshift`,
|
|
* `unzip`, `values`, `where`, `without`, `wrap`, and `zip`
|
|
*
|
|
* The non-chainable wrapper functions are:
|
|
* `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `has`,
|
|
* `identity`, `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`,
|
|
* `isElement`, `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`,
|
|
* `isNull`, `isNumber`, `isObject`, `isPlainObject`, `isRegExp`, `isString`,
|
|
* `isUndefined`, `join`, `lastIndexOf`, `mixin`, `noConflict`, `parseInt`,
|
|
* `pop`, `random`, `reduce`, `reduceRight`, `result`, `shift`, `size`, `some`,
|
|
* `sortedIndex`, `runInContext`, `template`, `unescape`, `uniqueId`, and `value`
|
|
*
|
|
* The wrapper functions `first` and `last` return wrapped values when `n` is
|
|
* passed, otherwise they return unwrapped values.
|
|
*
|
|
* @name _
|
|
* @constructor
|
|
* @alias chain
|
|
* @category Chaining
|
|
* @param {Mixed} value The value to wrap in a `lodash` instance.
|
|
* @returns {Object} Returns a `lodash` instance.
|
|
* @example
|
|
*
|
|
* var wrapped = _([1, 2, 3]);
|
|
*
|
|
* // returns an unwrapped value
|
|
* wrapped.reduce(function(sum, num) {
|
|
* return sum + num;
|
|
* });
|
|
* // => 6
|
|
*
|
|
* // returns a wrapped value
|
|
* var squares = wrapped.map(function(num) {
|
|
* return num * num;
|
|
* });
|
|
*
|
|
* _.isArray(squares);
|
|
* // => false
|
|
*
|
|
* _.isArray(squares.value());
|
|
* // => true
|
|
*/
|
|
function lodash(value) {
|
|
// don't wrap if already wrapped, even if wrapped by a different `lodash` constructor
|
|
return (value && typeof value == 'object' && !isArray(value) && hasOwnProperty.call(value, '__wrapped__'))
|
|
? value
|
|
: new lodashWrapper(value);
|
|
}
|
|
|
|
/**
|
|
* A fast path for creating `lodash` wrapper objects.
|
|
*
|
|
* @private
|
|
* @param {Mixed} value The value to wrap in a `lodash` instance.
|
|
* @returns {Object} Returns a `lodash` instance.
|
|
*/
|
|
function lodashWrapper(value) {
|
|
this.__wrapped__ = value;
|
|
}
|
|
// ensure `new lodashWrapper` is an instance of `lodash`
|
|
lodashWrapper.prototype = lodash.prototype;
|
|
|
|
/**
|
|
* An object used to flag environments features.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Object
|
|
*/
|
|
var support = lodash.support = {};
|
|
|
|
/**
|
|
* Detect if `Function#bind` exists and is inferred to be fast (all but V8).
|
|
*
|
|
* @memberOf _.support
|
|
* @type Boolean
|
|
*/
|
|
support.fastBind = nativeBind && !isV8;
|
|
|
|
/**
|
|
* By default, the template delimiters used by Lo-Dash are similar to those in
|
|
* embedded Ruby (ERB). Change the following template settings to use alternative
|
|
* delimiters.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Object
|
|
*/
|
|
lodash.templateSettings = {
|
|
|
|
/**
|
|
* Used to detect `data` property values to be HTML-escaped.
|
|
*
|
|
* @memberOf _.templateSettings
|
|
* @type RegExp
|
|
*/
|
|
'escape': /<%-([\s\S]+?)%>/g,
|
|
|
|
/**
|
|
* Used to detect code to be evaluated.
|
|
*
|
|
* @memberOf _.templateSettings
|
|
* @type RegExp
|
|
*/
|
|
'evaluate': /<%([\s\S]+?)%>/g,
|
|
|
|
/**
|
|
* Used to detect `data` property values to inject.
|
|
*
|
|
* @memberOf _.templateSettings
|
|
* @type RegExp
|
|
*/
|
|
'interpolate': reInterpolate,
|
|
|
|
/**
|
|
* Used to reference the data object in the template text.
|
|
*
|
|
* @memberOf _.templateSettings
|
|
* @type String
|
|
*/
|
|
'variable': '',
|
|
|
|
/**
|
|
* Used to import variables into the compiled template.
|
|
*
|
|
* @memberOf _.templateSettings
|
|
* @type Object
|
|
*/
|
|
'imports': {
|
|
|
|
/**
|
|
* A reference to the `lodash` function.
|
|
*
|
|
* @memberOf _.templateSettings.imports
|
|
* @type Function
|
|
*/
|
|
'_': lodash
|
|
}
|
|
};
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Creates a function that, when called, invokes `func` with the `this` binding
|
|
* of `thisArg` and prepends any `partialArgs` to the arguments passed to the
|
|
* bound function.
|
|
*
|
|
* @private
|
|
* @param {Function|String} func The function to bind or the method name.
|
|
* @param {Mixed} [thisArg] The `this` binding of `func`.
|
|
* @param {Array} partialArgs An array of arguments to be partially applied.
|
|
* @param {Object} [idicator] Used to indicate binding by key or partially
|
|
* applying arguments from the right.
|
|
* @returns {Function} Returns the new bound function.
|
|
*/
|
|
function createBound(func, thisArg, partialArgs, indicator) {
|
|
var isFunc = isFunction(func),
|
|
isPartial = !partialArgs,
|
|
key = thisArg;
|
|
|
|
// juggle arguments
|
|
if (isPartial) {
|
|
var rightIndicator = indicator;
|
|
partialArgs = thisArg;
|
|
}
|
|
else if (!isFunc) {
|
|
if (!indicator) {
|
|
throw new TypeError;
|
|
}
|
|
thisArg = func;
|
|
}
|
|
|
|
function bound() {
|
|
// `Function#bind` spec
|
|
// http://es5.github.com/#x15.3.4.5
|
|
var args = arguments,
|
|
thisBinding = isPartial ? this : thisArg;
|
|
|
|
if (!isFunc) {
|
|
func = thisArg[key];
|
|
}
|
|
if (partialArgs.length) {
|
|
args = args.length
|
|
? (args = nativeSlice.call(args), rightIndicator ? args.concat(partialArgs) : partialArgs.concat(args))
|
|
: partialArgs;
|
|
}
|
|
if (this instanceof bound) {
|
|
// ensure `new bound` is an instance of `func`
|
|
thisBinding = createObject(func.prototype);
|
|
|
|
// mimic the constructor's `return` behavior
|
|
// http://es5.github.com/#x13.2.2
|
|
var result = func.apply(thisBinding, args);
|
|
return isObject(result) ? result : thisBinding;
|
|
}
|
|
return func.apply(thisBinding, args);
|
|
}
|
|
return bound;
|
|
}
|
|
|
|
/**
|
|
* Creates a new object with the specified `prototype`.
|
|
*
|
|
* @private
|
|
* @param {Object} prototype The prototype object.
|
|
* @returns {Object} Returns the new object.
|
|
*/
|
|
function createObject(prototype) {
|
|
return isObject(prototype) ? nativeCreate(prototype) : {};
|
|
}
|
|
|
|
/**
|
|
* Used by `escape` to convert characters to HTML entities.
|
|
*
|
|
* @private
|
|
* @param {String} match The matched character to escape.
|
|
* @returns {String} Returns the escaped character.
|
|
*/
|
|
function escapeHtmlChar(match) {
|
|
return htmlEscapes[match];
|
|
}
|
|
|
|
/**
|
|
* Gets the appropriate "indexOf" function. If the `_.indexOf` method is
|
|
* customized, this method returns the custom method, otherwise it returns
|
|
* the `basicIndexOf` function.
|
|
*
|
|
* @private
|
|
* @returns {Function} Returns the "indexOf" function.
|
|
*/
|
|
function getIndexOf(array, value, fromIndex) {
|
|
var result = (result = lodash.indexOf) === indexOf ? basicIndexOf : result;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates a function that juggles arguments, allowing argument overloading
|
|
* for `_.flatten` and `_.uniq`, before passing them to the given `func`.
|
|
*
|
|
* @private
|
|
* @param {Function} func The function to wrap.
|
|
* @returns {Function} Returns the new function.
|
|
*/
|
|
function overloadWrapper(func) {
|
|
return function(array, flag, callback, thisArg) {
|
|
// juggle arguments
|
|
if (typeof flag != 'boolean' && flag != null) {
|
|
thisArg = callback;
|
|
callback = !(thisArg && thisArg[flag] === array) ? flag : undefined;
|
|
flag = false;
|
|
}
|
|
if (callback != null) {
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
}
|
|
return func(array, flag, callback, thisArg);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* A fallback implementation of `isPlainObject` which checks if a given `value`
|
|
* is an object created by the `Object` constructor, assuming objects created
|
|
* by the `Object` constructor have no inherited enumerable properties and that
|
|
* there are no `Object.prototype` extensions.
|
|
*
|
|
* @private
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if `value` is a plain object, else `false`.
|
|
*/
|
|
function shimIsPlainObject(value) {
|
|
var ctor,
|
|
result;
|
|
|
|
// avoid non Object objects, `arguments` objects, and DOM elements
|
|
if (!(value && toString.call(value) == objectClass) ||
|
|
(ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor))) {
|
|
return false;
|
|
}
|
|
// In most environments an object's own properties are iterated before
|
|
// its inherited properties. If the last iterated property is an object's
|
|
// own property then there are no inherited enumerable properties.
|
|
forIn(value, function(value, key) {
|
|
result = key;
|
|
});
|
|
return result === undefined || hasOwnProperty.call(value, result);
|
|
}
|
|
|
|
/**
|
|
* Used by `unescape` to convert HTML entities to characters.
|
|
*
|
|
* @private
|
|
* @param {String} match The matched character to unescape.
|
|
* @returns {String} Returns the unescaped character.
|
|
*/
|
|
function unescapeHtmlChar(match) {
|
|
return htmlUnescapes[match];
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Checks if `value` is an `arguments` object.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is an `arguments` object, else `false`.
|
|
* @example
|
|
*
|
|
* (function() { return _.isArguments(arguments); })(1, 2, 3);
|
|
* // => true
|
|
*
|
|
* _.isArguments([1, 2, 3]);
|
|
* // => false
|
|
*/
|
|
function isArguments(value) {
|
|
return toString.call(value) == argsClass;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is an array.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is an array, else `false`.
|
|
* @example
|
|
*
|
|
* (function() { return _.isArray(arguments); })();
|
|
* // => false
|
|
*
|
|
* _.isArray([1, 2, 3]);
|
|
* // => true
|
|
*/
|
|
var isArray = nativeIsArray;
|
|
|
|
/**
|
|
* A fallback implementation of `Object.keys` which produces an array of the
|
|
* given object's own enumerable property names.
|
|
*
|
|
* @private
|
|
* @type Function
|
|
* @param {Object} object The object to inspect.
|
|
* @returns {Array} Returns a new array of property names.
|
|
*/
|
|
var shimKeys = function (object) {
|
|
var index, iterable = object, result = [];
|
|
if (!iterable) return result;
|
|
if (!(objectTypes[typeof object])) return result;
|
|
for (index in iterable) {
|
|
if (hasOwnProperty.call(iterable, index)) {
|
|
result.push(index);
|
|
}
|
|
}
|
|
return result
|
|
};
|
|
|
|
/**
|
|
* Creates an array composed of the own enumerable property names of `object`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to inspect.
|
|
* @returns {Array} Returns a new array of property names.
|
|
* @example
|
|
*
|
|
* _.keys({ 'one': 1, 'two': 2, 'three': 3 });
|
|
* // => ['one', 'two', 'three'] (order is not guaranteed)
|
|
*/
|
|
var keys = !nativeKeys ? shimKeys : function(object) {
|
|
if (!isObject(object)) {
|
|
return [];
|
|
}
|
|
return nativeKeys(object);
|
|
};
|
|
|
|
/**
|
|
* Used to convert characters to HTML entities:
|
|
*
|
|
* Though the `>` character is escaped for symmetry, characters like `>` and `/`
|
|
* don't require escaping in HTML and have no special meaning unless they're part
|
|
* of a tag or an unquoted attribute value.
|
|
* http://mathiasbynens.be/notes/ambiguous-ampersands (under "semi-related fun fact")
|
|
*/
|
|
var htmlEscapes = {
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"',
|
|
"'": '''
|
|
};
|
|
|
|
/** Used to convert HTML entities to characters */
|
|
var htmlUnescapes = invert(htmlEscapes);
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Assigns own enumerable properties of source object(s) to the destination
|
|
* object. Subsequent sources will overwrite property assignments of previous
|
|
* sources. If a `callback` function is passed, it will be executed to produce
|
|
* the assigned values. The `callback` is bound to `thisArg` and invoked with
|
|
* two arguments; (objectValue, sourceValue).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @alias extend
|
|
* @category Objects
|
|
* @param {Object} object The destination object.
|
|
* @param {Object} [source1, source2, ...] The source objects.
|
|
* @param {Function} [callback] The function to customize assigning values.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns the destination object.
|
|
* @example
|
|
*
|
|
* _.assign({ 'name': 'moe' }, { 'age': 40 });
|
|
* // => { 'name': 'moe', 'age': 40 }
|
|
*
|
|
* var defaults = _.partialRight(_.assign, function(a, b) {
|
|
* return typeof a == 'undefined' ? b : a;
|
|
* });
|
|
*
|
|
* var food = { 'name': 'apple' };
|
|
* defaults(food, { 'name': 'banana', 'type': 'fruit' });
|
|
* // => { 'name': 'apple', 'type': 'fruit' }
|
|
*/
|
|
var assign = function (object, source, guard) {
|
|
var index, iterable = object, result = iterable;
|
|
if (!iterable) return result;
|
|
var args = arguments,
|
|
argsIndex = 0,
|
|
argsLength = typeof guard == 'number' ? 2 : args.length;
|
|
if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {
|
|
var callback = lodash.createCallback(args[--argsLength - 1], args[argsLength--], 2);
|
|
} else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {
|
|
callback = args[--argsLength];
|
|
}
|
|
while (++argsIndex < argsLength) {
|
|
iterable = args[argsIndex];
|
|
if (iterable && objectTypes[typeof iterable]) {
|
|
var ownIndex = -1,
|
|
ownProps = objectTypes[typeof iterable] && keys(iterable),
|
|
length = ownProps ? ownProps.length : 0;
|
|
|
|
while (++ownIndex < length) {
|
|
index = ownProps[ownIndex];
|
|
result[index] = callback ? callback(result[index], iterable[index]) : iterable[index];
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
};
|
|
|
|
/**
|
|
* Creates a clone of `value`. If `deep` is `true`, nested objects will also
|
|
* be cloned, otherwise they will be assigned by reference. If a `callback`
|
|
* function is passed, it will be executed to produce the cloned values. If
|
|
* `callback` returns `undefined`, cloning will be handled by the method instead.
|
|
* The `callback` is bound to `thisArg` and invoked with one argument; (value).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to clone.
|
|
* @param {Boolean} [deep=false] A flag to indicate a deep clone.
|
|
* @param {Function} [callback] The function to customize cloning values.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @param- {Array} [stackA=[]] Tracks traversed source objects.
|
|
* @param- {Array} [stackB=[]] Associates clones with source counterparts.
|
|
* @returns {Mixed} Returns the cloned `value`.
|
|
* @example
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* var shallow = _.clone(stooges);
|
|
* shallow[0] === stooges[0];
|
|
* // => true
|
|
*
|
|
* var deep = _.clone(stooges, true);
|
|
* deep[0] === stooges[0];
|
|
* // => false
|
|
*
|
|
* _.mixin({
|
|
* 'clone': _.partialRight(_.clone, function(value) {
|
|
* return _.isElement(value) ? value.cloneNode(false) : undefined;
|
|
* })
|
|
* });
|
|
*
|
|
* var clone = _.clone(document.body);
|
|
* clone.childNodes.length;
|
|
* // => 0
|
|
*/
|
|
function clone(value, deep, callback, thisArg, stackA, stackB) {
|
|
var result = value;
|
|
|
|
// allows working with "Collections" methods without using their `callback`
|
|
// argument, `index|key`, for this method's `callback`
|
|
if (typeof deep != 'boolean' && deep != null) {
|
|
thisArg = callback;
|
|
callback = deep;
|
|
deep = false;
|
|
}
|
|
if (typeof callback == 'function') {
|
|
callback = (typeof thisArg == 'undefined')
|
|
? callback
|
|
: lodash.createCallback(callback, thisArg, 1);
|
|
|
|
result = callback(result);
|
|
if (typeof result != 'undefined') {
|
|
return result;
|
|
}
|
|
result = value;
|
|
}
|
|
// inspect [[Class]]
|
|
var isObj = isObject(result);
|
|
if (isObj) {
|
|
var className = toString.call(result);
|
|
if (!cloneableClasses[className]) {
|
|
return result;
|
|
}
|
|
var isArr = isArray(result);
|
|
}
|
|
// shallow clone
|
|
if (!isObj || !deep) {
|
|
return isObj
|
|
? (isArr ? slice(result) : assign({}, result))
|
|
: result;
|
|
}
|
|
var ctor = ctorByClass[className];
|
|
switch (className) {
|
|
case boolClass:
|
|
case dateClass:
|
|
return new ctor(+result);
|
|
|
|
case numberClass:
|
|
case stringClass:
|
|
return new ctor(result);
|
|
|
|
case regexpClass:
|
|
return ctor(result.source, reFlags.exec(result));
|
|
}
|
|
// check for circular references and return corresponding clone
|
|
var initedStack = !stackA;
|
|
stackA || (stackA = getArray());
|
|
stackB || (stackB = getArray());
|
|
|
|
var length = stackA.length;
|
|
while (length--) {
|
|
if (stackA[length] == value) {
|
|
return stackB[length];
|
|
}
|
|
}
|
|
// init cloned object
|
|
result = isArr ? ctor(result.length) : {};
|
|
|
|
// add array properties assigned by `RegExp#exec`
|
|
if (isArr) {
|
|
if (hasOwnProperty.call(value, 'index')) {
|
|
result.index = value.index;
|
|
}
|
|
if (hasOwnProperty.call(value, 'input')) {
|
|
result.input = value.input;
|
|
}
|
|
}
|
|
// add the source value to the stack of traversed objects
|
|
// and associate it with its clone
|
|
stackA.push(value);
|
|
stackB.push(result);
|
|
|
|
// recursively populate clone (susceptible to call stack limits)
|
|
(isArr ? forEach : forOwn)(value, function(objValue, key) {
|
|
result[key] = clone(objValue, deep, callback, undefined, stackA, stackB);
|
|
});
|
|
|
|
if (initedStack) {
|
|
releaseArray(stackA);
|
|
releaseArray(stackB);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates a deep clone of `value`. If a `callback` function is passed,
|
|
* it will be executed to produce the cloned values. If `callback` returns
|
|
* `undefined`, cloning will be handled by the method instead. The `callback`
|
|
* is bound to `thisArg` and invoked with one argument; (value).
|
|
*
|
|
* Note: This method is loosely based on the structured clone algorithm. Functions
|
|
* and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
|
|
* objects created by constructors other than `Object` are cloned to plain `Object` objects.
|
|
* See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to deep clone.
|
|
* @param {Function} [callback] The function to customize cloning values.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the deep cloned `value`.
|
|
* @example
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* var deep = _.cloneDeep(stooges);
|
|
* deep[0] === stooges[0];
|
|
* // => false
|
|
*
|
|
* var view = {
|
|
* 'label': 'docs',
|
|
* 'node': element
|
|
* };
|
|
*
|
|
* var clone = _.cloneDeep(view, function(value) {
|
|
* return _.isElement(value) ? value.cloneNode(true) : undefined;
|
|
* });
|
|
*
|
|
* clone.node == view.node;
|
|
* // => false
|
|
*/
|
|
function cloneDeep(value, callback, thisArg) {
|
|
return clone(value, true, callback, thisArg);
|
|
}
|
|
|
|
/**
|
|
* Assigns own enumerable properties of source object(s) to the destination
|
|
* object for all destination properties that resolve to `undefined`. Once a
|
|
* property is set, additional defaults of the same property will be ignored.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @category Objects
|
|
* @param {Object} object The destination object.
|
|
* @param {Object} [source1, source2, ...] The source objects.
|
|
* @param- {Object} [guard] Allows working with `_.reduce` without using its
|
|
* callback's `key` and `object` arguments as sources.
|
|
* @returns {Object} Returns the destination object.
|
|
* @example
|
|
*
|
|
* var food = { 'name': 'apple' };
|
|
* _.defaults(food, { 'name': 'banana', 'type': 'fruit' });
|
|
* // => { 'name': 'apple', 'type': 'fruit' }
|
|
*/
|
|
var defaults = function (object, source, guard) {
|
|
var index, iterable = object, result = iterable;
|
|
if (!iterable) return result;
|
|
var args = arguments,
|
|
argsIndex = 0,
|
|
argsLength = typeof guard == 'number' ? 2 : args.length;
|
|
while (++argsIndex < argsLength) {
|
|
iterable = args[argsIndex];
|
|
if (iterable && objectTypes[typeof iterable]) {
|
|
var ownIndex = -1,
|
|
ownProps = objectTypes[typeof iterable] && keys(iterable),
|
|
length = ownProps ? ownProps.length : 0;
|
|
|
|
while (++ownIndex < length) {
|
|
index = ownProps[ownIndex];
|
|
if (typeof result[index] == 'undefined') result[index] = iterable[index];
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
};
|
|
|
|
/**
|
|
* This method is similar to `_.find`, except that it returns the key of the
|
|
* element that passes the callback check, instead of the element itself.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to search.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the key of the found element, else `undefined`.
|
|
* @example
|
|
*
|
|
* _.findKey({ 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, function(num) {
|
|
* return num % 2 == 0;
|
|
* });
|
|
* // => 'b'
|
|
*/
|
|
function findKey(object, callback, thisArg) {
|
|
var result;
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
forOwn(object, function(value, key, object) {
|
|
if (callback(value, key, object)) {
|
|
result = key;
|
|
return false;
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Iterates over `object`'s own and inherited enumerable properties, executing
|
|
* the `callback` for each property. The `callback` is bound to `thisArg` and
|
|
* invoked with three arguments; (value, key, object). Callbacks may exit iteration
|
|
* early by explicitly returning `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @category Objects
|
|
* @param {Object} object The object to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns `object`.
|
|
* @example
|
|
*
|
|
* function Dog(name) {
|
|
* this.name = name;
|
|
* }
|
|
*
|
|
* Dog.prototype.bark = function() {
|
|
* alert('Woof, woof!');
|
|
* };
|
|
*
|
|
* _.forIn(new Dog('Dagny'), function(value, key) {
|
|
* alert(key);
|
|
* });
|
|
* // => alerts 'name' and 'bark' (order is not guaranteed)
|
|
*/
|
|
var forIn = function (collection, callback, thisArg) {
|
|
var index, iterable = collection, result = iterable;
|
|
if (!iterable) return result;
|
|
if (!objectTypes[typeof iterable]) return result;
|
|
callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg);
|
|
for (index in iterable) {
|
|
if (callback(iterable[index], index, collection) === false) return result;
|
|
}
|
|
return result
|
|
};
|
|
|
|
/**
|
|
* Iterates over an object's own enumerable properties, executing the `callback`
|
|
* for each property. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, key, object). Callbacks may exit iteration early by explicitly
|
|
* returning `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @category Objects
|
|
* @param {Object} object The object to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns `object`.
|
|
* @example
|
|
*
|
|
* _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
|
|
* alert(key);
|
|
* });
|
|
* // => alerts '0', '1', and 'length' (order is not guaranteed)
|
|
*/
|
|
var forOwn = function (collection, callback, thisArg) {
|
|
var index, iterable = collection, result = iterable;
|
|
if (!iterable) return result;
|
|
if (!objectTypes[typeof iterable]) return result;
|
|
callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg);
|
|
var ownIndex = -1,
|
|
ownProps = objectTypes[typeof iterable] && keys(iterable),
|
|
length = ownProps ? ownProps.length : 0;
|
|
|
|
while (++ownIndex < length) {
|
|
index = ownProps[ownIndex];
|
|
if (callback(iterable[index], index, collection) === false) return result;
|
|
}
|
|
return result
|
|
};
|
|
|
|
/**
|
|
* Creates a sorted array of all enumerable properties, own and inherited,
|
|
* of `object` that have function values.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias methods
|
|
* @category Objects
|
|
* @param {Object} object The object to inspect.
|
|
* @returns {Array} Returns a new array of property names that have function values.
|
|
* @example
|
|
*
|
|
* _.functions(_);
|
|
* // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...]
|
|
*/
|
|
function functions(object) {
|
|
var result = [];
|
|
forIn(object, function(value, key) {
|
|
if (isFunction(value)) {
|
|
result.push(key);
|
|
}
|
|
});
|
|
return result.sort();
|
|
}
|
|
|
|
/**
|
|
* Checks if the specified object `property` exists and is a direct property,
|
|
* instead of an inherited property.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to check.
|
|
* @param {String} property The property to check for.
|
|
* @returns {Boolean} Returns `true` if key is a direct property, else `false`.
|
|
* @example
|
|
*
|
|
* _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b');
|
|
* // => true
|
|
*/
|
|
function has(object, property) {
|
|
return object ? hasOwnProperty.call(object, property) : false;
|
|
}
|
|
|
|
/**
|
|
* Creates an object composed of the inverted keys and values of the given `object`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to invert.
|
|
* @returns {Object} Returns the created inverted object.
|
|
* @example
|
|
*
|
|
* _.invert({ 'first': 'moe', 'second': 'larry' });
|
|
* // => { 'moe': 'first', 'larry': 'second' }
|
|
*/
|
|
function invert(object) {
|
|
var index = -1,
|
|
props = keys(object),
|
|
length = props.length,
|
|
result = {};
|
|
|
|
while (++index < length) {
|
|
var key = props[index];
|
|
result[object[key]] = key;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a boolean value.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a boolean value, else `false`.
|
|
* @example
|
|
*
|
|
* _.isBoolean(null);
|
|
* // => false
|
|
*/
|
|
function isBoolean(value) {
|
|
return value === true || value === false || toString.call(value) == boolClass;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a date.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a date, else `false`.
|
|
* @example
|
|
*
|
|
* _.isDate(new Date);
|
|
* // => true
|
|
*/
|
|
function isDate(value) {
|
|
return value ? (typeof value == 'object' && toString.call(value) == dateClass) : false;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a DOM element.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a DOM element, else `false`.
|
|
* @example
|
|
*
|
|
* _.isElement(document.body);
|
|
* // => true
|
|
*/
|
|
function isElement(value) {
|
|
return value ? value.nodeType === 1 : false;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is empty. Arrays, strings, or `arguments` objects with a
|
|
* length of `0` and objects with no own enumerable properties are considered
|
|
* "empty".
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Array|Object|String} value The value to inspect.
|
|
* @returns {Boolean} Returns `true`, if the `value` is empty, else `false`.
|
|
* @example
|
|
*
|
|
* _.isEmpty([1, 2, 3]);
|
|
* // => false
|
|
*
|
|
* _.isEmpty({});
|
|
* // => true
|
|
*
|
|
* _.isEmpty('');
|
|
* // => true
|
|
*/
|
|
function isEmpty(value) {
|
|
var result = true;
|
|
if (!value) {
|
|
return result;
|
|
}
|
|
var className = toString.call(value),
|
|
length = value.length;
|
|
|
|
if ((className == arrayClass || className == stringClass || className == argsClass ) ||
|
|
(className == objectClass && typeof length == 'number' && isFunction(value.splice))) {
|
|
return !length;
|
|
}
|
|
forOwn(value, function() {
|
|
return (result = false);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Performs a deep comparison between two values to determine if they are
|
|
* equivalent to each other. If `callback` is passed, it will be executed to
|
|
* compare values. If `callback` returns `undefined`, comparisons will be handled
|
|
* by the method instead. The `callback` is bound to `thisArg` and invoked with
|
|
* two arguments; (a, b).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} a The value to compare.
|
|
* @param {Mixed} b The other value to compare.
|
|
* @param {Function} [callback] The function to customize comparing values.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @param- {Array} [stackA=[]] Tracks traversed `a` objects.
|
|
* @param- {Array} [stackB=[]] Tracks traversed `b` objects.
|
|
* @returns {Boolean} Returns `true`, if the values are equivalent, else `false`.
|
|
* @example
|
|
*
|
|
* var moe = { 'name': 'moe', 'age': 40 };
|
|
* var copy = { 'name': 'moe', 'age': 40 };
|
|
*
|
|
* moe == copy;
|
|
* // => false
|
|
*
|
|
* _.isEqual(moe, copy);
|
|
* // => true
|
|
*
|
|
* var words = ['hello', 'goodbye'];
|
|
* var otherWords = ['hi', 'goodbye'];
|
|
*
|
|
* _.isEqual(words, otherWords, function(a, b) {
|
|
* var reGreet = /^(?:hello|hi)$/i,
|
|
* aGreet = _.isString(a) && reGreet.test(a),
|
|
* bGreet = _.isString(b) && reGreet.test(b);
|
|
*
|
|
* return (aGreet || bGreet) ? (aGreet == bGreet) : undefined;
|
|
* });
|
|
* // => true
|
|
*/
|
|
function isEqual(a, b, callback, thisArg, stackA, stackB) {
|
|
// used to indicate that when comparing objects, `a` has at least the properties of `b`
|
|
var whereIndicator = callback === indicatorObject;
|
|
if (typeof callback == 'function' && !whereIndicator) {
|
|
callback = lodash.createCallback(callback, thisArg, 2);
|
|
var result = callback(a, b);
|
|
if (typeof result != 'undefined') {
|
|
return !!result;
|
|
}
|
|
}
|
|
// exit early for identical values
|
|
if (a === b) {
|
|
// treat `+0` vs. `-0` as not equal
|
|
return a !== 0 || (1 / a == 1 / b);
|
|
}
|
|
var type = typeof a,
|
|
otherType = typeof b;
|
|
|
|
// exit early for unlike primitive values
|
|
if (a === a &&
|
|
(!a || (type != 'function' && type != 'object')) &&
|
|
(!b || (otherType != 'function' && otherType != 'object'))) {
|
|
return false;
|
|
}
|
|
// exit early for `null` and `undefined`, avoiding ES3's Function#call behavior
|
|
// http://es5.github.com/#x15.3.4.4
|
|
if (a == null || b == null) {
|
|
return a === b;
|
|
}
|
|
// compare [[Class]] names
|
|
var className = toString.call(a),
|
|
otherClass = toString.call(b);
|
|
|
|
if (className == argsClass) {
|
|
className = objectClass;
|
|
}
|
|
if (otherClass == argsClass) {
|
|
otherClass = objectClass;
|
|
}
|
|
if (className != otherClass) {
|
|
return false;
|
|
}
|
|
switch (className) {
|
|
case boolClass:
|
|
case dateClass:
|
|
// coerce dates and booleans to numbers, dates to milliseconds and booleans
|
|
// to `1` or `0`, treating invalid dates coerced to `NaN` as not equal
|
|
return +a == +b;
|
|
|
|
case numberClass:
|
|
// treat `NaN` vs. `NaN` as equal
|
|
return (a != +a)
|
|
? b != +b
|
|
// but treat `+0` vs. `-0` as not equal
|
|
: (a == 0 ? (1 / a == 1 / b) : a == +b);
|
|
|
|
case regexpClass:
|
|
case stringClass:
|
|
// coerce regexes to strings (http://es5.github.com/#x15.10.6.4)
|
|
// treat string primitives and their corresponding object instances as equal
|
|
return a == String(b);
|
|
}
|
|
var isArr = className == arrayClass;
|
|
if (!isArr) {
|
|
// unwrap any `lodash` wrapped values
|
|
if (hasOwnProperty.call(a, '__wrapped__ ') || hasOwnProperty.call(b, '__wrapped__')) {
|
|
return isEqual(a.__wrapped__ || a, b.__wrapped__ || b, callback, thisArg, stackA, stackB);
|
|
}
|
|
// exit for functions and DOM nodes
|
|
if (className != objectClass) {
|
|
return false;
|
|
}
|
|
// in older versions of Opera, `arguments` objects have `Array` constructors
|
|
var ctorA = a.constructor,
|
|
ctorB = b.constructor;
|
|
|
|
// non `Object` object instances with different constructors are not equal
|
|
if (ctorA != ctorB && !(
|
|
isFunction(ctorA) && ctorA instanceof ctorA &&
|
|
isFunction(ctorB) && ctorB instanceof ctorB
|
|
)) {
|
|
return false;
|
|
}
|
|
}
|
|
// assume cyclic structures are equal
|
|
// the algorithm for detecting cyclic structures is adapted from ES 5.1
|
|
// section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3)
|
|
var initedStack = !stackA;
|
|
stackA || (stackA = getArray());
|
|
stackB || (stackB = getArray());
|
|
|
|
var length = stackA.length;
|
|
while (length--) {
|
|
if (stackA[length] == a) {
|
|
return stackB[length] == b;
|
|
}
|
|
}
|
|
var size = 0;
|
|
result = true;
|
|
|
|
// add `a` and `b` to the stack of traversed objects
|
|
stackA.push(a);
|
|
stackB.push(b);
|
|
|
|
// recursively compare objects and arrays (susceptible to call stack limits)
|
|
if (isArr) {
|
|
length = a.length;
|
|
size = b.length;
|
|
|
|
// compare lengths to determine if a deep comparison is necessary
|
|
result = size == a.length;
|
|
if (!result && !whereIndicator) {
|
|
return result;
|
|
}
|
|
// deep compare the contents, ignoring non-numeric properties
|
|
while (size--) {
|
|
var index = length,
|
|
value = b[size];
|
|
|
|
if (whereIndicator) {
|
|
while (index--) {
|
|
if ((result = isEqual(a[index], value, callback, thisArg, stackA, stackB))) {
|
|
break;
|
|
}
|
|
}
|
|
} else if (!(result = isEqual(a[size], value, callback, thisArg, stackA, stackB))) {
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
// deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
|
|
// which, in this case, is more costly
|
|
forIn(b, function(value, key, b) {
|
|
if (hasOwnProperty.call(b, key)) {
|
|
// count the number of properties.
|
|
size++;
|
|
// deep compare each property value.
|
|
return (result = hasOwnProperty.call(a, key) && isEqual(a[key], value, callback, thisArg, stackA, stackB));
|
|
}
|
|
});
|
|
|
|
if (result && !whereIndicator) {
|
|
// ensure both objects have the same number of properties
|
|
forIn(a, function(value, key, a) {
|
|
if (hasOwnProperty.call(a, key)) {
|
|
// `size` will be `-1` if `a` has more properties than `b`
|
|
return (result = --size > -1);
|
|
}
|
|
});
|
|
}
|
|
if (initedStack) {
|
|
releaseArray(stackA);
|
|
releaseArray(stackB);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is, or can be coerced to, a finite number.
|
|
*
|
|
* Note: This is not the same as native `isFinite`, which will return true for
|
|
* booleans and empty strings. See http://es5.github.com/#x15.1.2.5.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is finite, else `false`.
|
|
* @example
|
|
*
|
|
* _.isFinite(-101);
|
|
* // => true
|
|
*
|
|
* _.isFinite('10');
|
|
* // => true
|
|
*
|
|
* _.isFinite(true);
|
|
* // => false
|
|
*
|
|
* _.isFinite('');
|
|
* // => false
|
|
*
|
|
* _.isFinite(Infinity);
|
|
* // => false
|
|
*/
|
|
function isFinite(value) {
|
|
return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value));
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a function, else `false`.
|
|
* @example
|
|
*
|
|
* _.isFunction(_);
|
|
* // => true
|
|
*/
|
|
function isFunction(value) {
|
|
return typeof value == 'function';
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is the language type of Object.
|
|
* (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is an object, else `false`.
|
|
* @example
|
|
*
|
|
* _.isObject({});
|
|
* // => true
|
|
*
|
|
* _.isObject([1, 2, 3]);
|
|
* // => true
|
|
*
|
|
* _.isObject(1);
|
|
* // => false
|
|
*/
|
|
function isObject(value) {
|
|
// check if the value is the ECMAScript language type of Object
|
|
// http://es5.github.com/#x8
|
|
// and avoid a V8 bug
|
|
// http://code.google.com/p/v8/issues/detail?id=2291
|
|
return !!(value && objectTypes[typeof value]);
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is `NaN`.
|
|
*
|
|
* Note: This is not the same as native `isNaN`, which will return `true` for
|
|
* `undefined` and other values. See http://es5.github.com/#x15.1.2.4.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is `NaN`, else `false`.
|
|
* @example
|
|
*
|
|
* _.isNaN(NaN);
|
|
* // => true
|
|
*
|
|
* _.isNaN(new Number(NaN));
|
|
* // => true
|
|
*
|
|
* isNaN(undefined);
|
|
* // => true
|
|
*
|
|
* _.isNaN(undefined);
|
|
* // => false
|
|
*/
|
|
function isNaN(value) {
|
|
// `NaN` as a primitive is the only value that is not equal to itself
|
|
// (perform the [[Class]] check first to avoid errors with some host objects in IE)
|
|
return isNumber(value) && value != +value
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is `null`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is `null`, else `false`.
|
|
* @example
|
|
*
|
|
* _.isNull(null);
|
|
* // => true
|
|
*
|
|
* _.isNull(undefined);
|
|
* // => false
|
|
*/
|
|
function isNull(value) {
|
|
return value === null;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a number.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a number, else `false`.
|
|
* @example
|
|
*
|
|
* _.isNumber(8.4 * 5);
|
|
* // => true
|
|
*/
|
|
function isNumber(value) {
|
|
return typeof value == 'number' || toString.call(value) == numberClass;
|
|
}
|
|
|
|
/**
|
|
* Checks if a given `value` is an object created by the `Object` constructor.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if `value` is a plain object, else `false`.
|
|
* @example
|
|
*
|
|
* function Stooge(name, age) {
|
|
* this.name = name;
|
|
* this.age = age;
|
|
* }
|
|
*
|
|
* _.isPlainObject(new Stooge('moe', 40));
|
|
* // => false
|
|
*
|
|
* _.isPlainObject([1, 2, 3]);
|
|
* // => false
|
|
*
|
|
* _.isPlainObject({ 'name': 'moe', 'age': 40 });
|
|
* // => true
|
|
*/
|
|
var isPlainObject = function(value) {
|
|
if (!(value && toString.call(value) == objectClass)) {
|
|
return false;
|
|
}
|
|
var valueOf = value.valueOf,
|
|
objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto);
|
|
|
|
return objProto
|
|
? (value == objProto || getPrototypeOf(value) == objProto)
|
|
: shimIsPlainObject(value);
|
|
};
|
|
|
|
/**
|
|
* Checks if `value` is a regular expression.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a regular expression, else `false`.
|
|
* @example
|
|
*
|
|
* _.isRegExp(/moe/);
|
|
* // => true
|
|
*/
|
|
function isRegExp(value) {
|
|
return value ? (typeof value == 'object' && toString.call(value) == regexpClass) : false;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is a string.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is a string, else `false`.
|
|
* @example
|
|
*
|
|
* _.isString('moe');
|
|
* // => true
|
|
*/
|
|
function isString(value) {
|
|
return typeof value == 'string' || toString.call(value) == stringClass;
|
|
}
|
|
|
|
/**
|
|
* Checks if `value` is `undefined`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Mixed} value The value to check.
|
|
* @returns {Boolean} Returns `true`, if the `value` is `undefined`, else `false`.
|
|
* @example
|
|
*
|
|
* _.isUndefined(void 0);
|
|
* // => true
|
|
*/
|
|
function isUndefined(value) {
|
|
return typeof value == 'undefined';
|
|
}
|
|
|
|
/**
|
|
* Recursively merges own enumerable properties of the source object(s), that
|
|
* don't resolve to `undefined`, into the destination object. Subsequent sources
|
|
* will overwrite property assignments of previous sources. If a `callback` function
|
|
* is passed, it will be executed to produce the merged values of the destination
|
|
* and source properties. If `callback` returns `undefined`, merging will be
|
|
* handled by the method instead. The `callback` is bound to `thisArg` and
|
|
* invoked with two arguments; (objectValue, sourceValue).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The destination object.
|
|
* @param {Object} [source1, source2, ...] The source objects.
|
|
* @param {Function} [callback] The function to customize merging properties.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @param- {Object} [deepIndicator] Indicates that `stackA` and `stackB` are
|
|
* arrays of traversed objects, instead of source objects.
|
|
* @param- {Array} [stackA=[]] Tracks traversed source objects.
|
|
* @param- {Array} [stackB=[]] Associates values with source counterparts.
|
|
* @returns {Object} Returns the destination object.
|
|
* @example
|
|
*
|
|
* var names = {
|
|
* 'stooges': [
|
|
* { 'name': 'moe' },
|
|
* { 'name': 'larry' }
|
|
* ]
|
|
* };
|
|
*
|
|
* var ages = {
|
|
* 'stooges': [
|
|
* { 'age': 40 },
|
|
* { 'age': 50 }
|
|
* ]
|
|
* };
|
|
*
|
|
* _.merge(names, ages);
|
|
* // => { 'stooges': [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }] }
|
|
*
|
|
* var food = {
|
|
* 'fruits': ['apple'],
|
|
* 'vegetables': ['beet']
|
|
* };
|
|
*
|
|
* var otherFood = {
|
|
* 'fruits': ['banana'],
|
|
* 'vegetables': ['carrot']
|
|
* };
|
|
*
|
|
* _.merge(food, otherFood, function(a, b) {
|
|
* return _.isArray(a) ? a.concat(b) : undefined;
|
|
* });
|
|
* // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot] }
|
|
*/
|
|
function merge(object, source, deepIndicator) {
|
|
var args = arguments,
|
|
index = 0,
|
|
length = 2;
|
|
|
|
if (!isObject(object)) {
|
|
return object;
|
|
}
|
|
if (deepIndicator === indicatorObject) {
|
|
var callback = args[3],
|
|
stackA = args[4],
|
|
stackB = args[5];
|
|
} else {
|
|
var initedStack = true;
|
|
stackA = getArray();
|
|
stackB = getArray();
|
|
|
|
// allows working with `_.reduce` and `_.reduceRight` without
|
|
// using their `callback` arguments, `index|key` and `collection`
|
|
if (typeof deepIndicator != 'number') {
|
|
length = args.length;
|
|
}
|
|
if (length > 3 && typeof args[length - 2] == 'function') {
|
|
callback = lodash.createCallback(args[--length - 1], args[length--], 2);
|
|
} else if (length > 2 && typeof args[length - 1] == 'function') {
|
|
callback = args[--length];
|
|
}
|
|
}
|
|
while (++index < length) {
|
|
(isArray(args[index]) ? forEach : forOwn)(args[index], function(source, key) {
|
|
var found,
|
|
isArr,
|
|
result = source,
|
|
value = object[key];
|
|
|
|
if (source && ((isArr = isArray(source)) || isPlainObject(source))) {
|
|
// avoid merging previously merged cyclic sources
|
|
var stackLength = stackA.length;
|
|
while (stackLength--) {
|
|
if ((found = stackA[stackLength] == source)) {
|
|
value = stackB[stackLength];
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
var isShallow;
|
|
if (callback) {
|
|
result = callback(value, source);
|
|
if ((isShallow = typeof result != 'undefined')) {
|
|
value = result;
|
|
}
|
|
}
|
|
if (!isShallow) {
|
|
value = isArr
|
|
? (isArray(value) ? value : [])
|
|
: (isPlainObject(value) ? value : {});
|
|
}
|
|
// add `source` and associated `value` to the stack of traversed objects
|
|
stackA.push(source);
|
|
stackB.push(value);
|
|
|
|
// recursively merge objects and arrays (susceptible to call stack limits)
|
|
if (!isShallow) {
|
|
value = merge(value, source, indicatorObject, callback, stackA, stackB);
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if (callback) {
|
|
result = callback(value, source);
|
|
if (typeof result == 'undefined') {
|
|
result = source;
|
|
}
|
|
}
|
|
if (typeof result != 'undefined') {
|
|
value = result;
|
|
}
|
|
}
|
|
object[key] = value;
|
|
});
|
|
}
|
|
|
|
if (initedStack) {
|
|
releaseArray(stackA);
|
|
releaseArray(stackB);
|
|
}
|
|
return object;
|
|
}
|
|
|
|
/**
|
|
* Creates a shallow clone of `object` excluding the specified properties.
|
|
* Property names may be specified as individual arguments or as arrays of
|
|
* property names. If a `callback` function is passed, it will be executed
|
|
* for each property in the `object`, omitting the properties `callback`
|
|
* returns truthy for. The `callback` is bound to `thisArg` and invoked
|
|
* with three arguments; (value, key, object).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The source object.
|
|
* @param {Function|String} callback|[prop1, prop2, ...] The properties to omit
|
|
* or the function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns an object without the omitted properties.
|
|
* @example
|
|
*
|
|
* _.omit({ 'name': 'moe', 'age': 40 }, 'age');
|
|
* // => { 'name': 'moe' }
|
|
*
|
|
* _.omit({ 'name': 'moe', 'age': 40 }, function(value) {
|
|
* return typeof value == 'number';
|
|
* });
|
|
* // => { 'name': 'moe' }
|
|
*/
|
|
function omit(object, callback, thisArg) {
|
|
var indexOf = getIndexOf(),
|
|
isFunc = typeof callback == 'function',
|
|
result = {};
|
|
|
|
if (isFunc) {
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
} else {
|
|
var props = concat.apply(arrayRef, nativeSlice.call(arguments, 1));
|
|
}
|
|
forIn(object, function(value, key, object) {
|
|
if (isFunc
|
|
? !callback(value, key, object)
|
|
: indexOf(props, key) < 0
|
|
) {
|
|
result[key] = value;
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates a two dimensional array of the given object's key-value pairs,
|
|
* i.e. `[[key1, value1], [key2, value2]]`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to inspect.
|
|
* @returns {Array} Returns new array of key-value pairs.
|
|
* @example
|
|
*
|
|
* _.pairs({ 'moe': 30, 'larry': 40 });
|
|
* // => [['moe', 30], ['larry', 40]] (order is not guaranteed)
|
|
*/
|
|
function pairs(object) {
|
|
var index = -1,
|
|
props = keys(object),
|
|
length = props.length,
|
|
result = Array(length);
|
|
|
|
while (++index < length) {
|
|
var key = props[index];
|
|
result[index] = [key, object[key]];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates a shallow clone of `object` composed of the specified properties.
|
|
* Property names may be specified as individual arguments or as arrays of property
|
|
* names. If `callback` is passed, it will be executed for each property in the
|
|
* `object`, picking the properties `callback` returns truthy for. The `callback`
|
|
* is bound to `thisArg` and invoked with three arguments; (value, key, object).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The source object.
|
|
* @param {Array|Function|String} callback|[prop1, prop2, ...] The function called
|
|
* per iteration or properties to pick, either as individual arguments or arrays.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns an object composed of the picked properties.
|
|
* @example
|
|
*
|
|
* _.pick({ 'name': 'moe', '_userid': 'moe1' }, 'name');
|
|
* // => { 'name': 'moe' }
|
|
*
|
|
* _.pick({ 'name': 'moe', '_userid': 'moe1' }, function(value, key) {
|
|
* return key.charAt(0) != '_';
|
|
* });
|
|
* // => { 'name': 'moe' }
|
|
*/
|
|
function pick(object, callback, thisArg) {
|
|
var result = {};
|
|
if (typeof callback != 'function') {
|
|
var index = -1,
|
|
props = concat.apply(arrayRef, nativeSlice.call(arguments, 1)),
|
|
length = isObject(object) ? props.length : 0;
|
|
|
|
while (++index < length) {
|
|
var key = props[index];
|
|
if (key in object) {
|
|
result[key] = object[key];
|
|
}
|
|
}
|
|
} else {
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
forIn(object, function(value, key, object) {
|
|
if (callback(value, key, object)) {
|
|
result[key] = value;
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* An alternative to `_.reduce`, this method transforms an `object` to a new
|
|
* `accumulator` object which is the result of running each of its elements
|
|
* through the `callback`, with each `callback` execution potentially mutating
|
|
* the `accumulator` object. The `callback` is bound to `thisArg` and invoked
|
|
* with four arguments; (accumulator, value, key, object). Callbacks may exit
|
|
* iteration early by explicitly returning `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Array|Object} collection The collection to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [accumulator] The custom accumulator value.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the accumulated value.
|
|
* @example
|
|
*
|
|
* var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
|
|
* num *= num;
|
|
* if (num % 2) {
|
|
* return result.push(num) < 3;
|
|
* }
|
|
* });
|
|
* // => [1, 9, 25]
|
|
*
|
|
* var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
|
|
* result[key] = num * 3;
|
|
* });
|
|
* // => { 'a': 3, 'b': 6, 'c': 9 }
|
|
*/
|
|
function transform(object, callback, accumulator, thisArg) {
|
|
var isArr = isArray(object);
|
|
callback = lodash.createCallback(callback, thisArg, 4);
|
|
|
|
if (accumulator == null) {
|
|
if (isArr) {
|
|
accumulator = [];
|
|
} else {
|
|
var ctor = object && object.constructor,
|
|
proto = ctor && ctor.prototype;
|
|
|
|
accumulator = createObject(proto);
|
|
}
|
|
}
|
|
(isArr ? forEach : forOwn)(object, function(value, index, object) {
|
|
return callback(accumulator, value, index, object);
|
|
});
|
|
return accumulator;
|
|
}
|
|
|
|
/**
|
|
* Creates an array composed of the own enumerable property values of `object`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Objects
|
|
* @param {Object} object The object to inspect.
|
|
* @returns {Array} Returns a new array of property values.
|
|
* @example
|
|
*
|
|
* _.values({ 'one': 1, 'two': 2, 'three': 3 });
|
|
* // => [1, 2, 3] (order is not guaranteed)
|
|
*/
|
|
function values(object) {
|
|
var index = -1,
|
|
props = keys(object),
|
|
length = props.length,
|
|
result = Array(length);
|
|
|
|
while (++index < length) {
|
|
result[index] = object[props[index]];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Creates an array of elements from the specified indexes, or keys, of the
|
|
* `collection`. Indexes may be specified as individual arguments or as arrays
|
|
* of indexes.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Array|Number|String} [index1, index2, ...] The indexes of
|
|
* `collection` to retrieve, either as individual arguments or arrays.
|
|
* @returns {Array} Returns a new array of elements corresponding to the
|
|
* provided indexes.
|
|
* @example
|
|
*
|
|
* _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
|
|
* // => ['a', 'c', 'e']
|
|
*
|
|
* _.at(['moe', 'larry', 'curly'], 0, 2);
|
|
* // => ['moe', 'curly']
|
|
*/
|
|
function at(collection) {
|
|
var index = -1,
|
|
props = concat.apply(arrayRef, nativeSlice.call(arguments, 1)),
|
|
length = props.length,
|
|
result = Array(length);
|
|
|
|
while(++index < length) {
|
|
result[index] = collection[props[index]];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Checks if a given `target` element is present in a `collection` using strict
|
|
* equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
|
|
* as the offset from the end of the collection.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias include
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Mixed} target The value to check for.
|
|
* @param {Number} [fromIndex=0] The index to search from.
|
|
* @returns {Boolean} Returns `true` if the `target` element is found, else `false`.
|
|
* @example
|
|
*
|
|
* _.contains([1, 2, 3], 1);
|
|
* // => true
|
|
*
|
|
* _.contains([1, 2, 3], 1, 2);
|
|
* // => false
|
|
*
|
|
* _.contains({ 'name': 'moe', 'age': 40 }, 'moe');
|
|
* // => true
|
|
*
|
|
* _.contains('curly', 'ur');
|
|
* // => true
|
|
*/
|
|
function contains(collection, target, fromIndex) {
|
|
var index = -1,
|
|
indexOf = getIndexOf(),
|
|
length = collection ? collection.length : 0,
|
|
result = false;
|
|
|
|
fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
|
|
if (length && typeof length == 'number') {
|
|
result = (isString(collection)
|
|
? collection.indexOf(target, fromIndex)
|
|
: indexOf(collection, target, fromIndex)
|
|
) > -1;
|
|
} else {
|
|
forOwn(collection, function(value) {
|
|
if (++index >= fromIndex) {
|
|
return !(result = value === target);
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates an object composed of keys returned from running each element of the
|
|
* `collection` through the given `callback`. The corresponding value of each key
|
|
* is the number of times the key was returned by the `callback`. The `callback`
|
|
* is bound to `thisArg` and invoked with three arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns the composed aggregate object.
|
|
* @example
|
|
*
|
|
* _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); });
|
|
* // => { '4': 1, '6': 2 }
|
|
*
|
|
* _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
|
|
* // => { '4': 1, '6': 2 }
|
|
*
|
|
* _.countBy(['one', 'two', 'three'], 'length');
|
|
* // => { '3': 2, '5': 1 }
|
|
*/
|
|
function countBy(collection, callback, thisArg) {
|
|
var result = {};
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
|
|
forEach(collection, function(value, key, collection) {
|
|
key = String(callback(value, key, collection));
|
|
(hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Checks if the `callback` returns a truthy value for **all** elements of a
|
|
* `collection`. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias all
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Boolean} Returns `true` if all elements pass the callback check,
|
|
* else `false`.
|
|
* @example
|
|
*
|
|
* _.every([true, 1, null, 'yes'], Boolean);
|
|
* // => false
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.every(stooges, 'age');
|
|
* // => true
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.every(stooges, { 'age': 50 });
|
|
* // => false
|
|
*/
|
|
function every(collection, callback, thisArg) {
|
|
var result = true;
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
|
|
var index = -1,
|
|
length = collection ? collection.length : 0;
|
|
|
|
if (typeof length == 'number') {
|
|
while (++index < length) {
|
|
if (!(result = !!callback(collection[index], index, collection))) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
forOwn(collection, function(value, index, collection) {
|
|
return (result = !!callback(value, index, collection));
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Examines each element in a `collection`, returning an array of all elements
|
|
* the `callback` returns truthy for. The `callback` is bound to `thisArg` and
|
|
* invoked with three arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias select
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new array of elements that passed the callback check.
|
|
* @example
|
|
*
|
|
* var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
|
|
* // => [2, 4, 6]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'organic': false, 'type': 'fruit' },
|
|
* { 'name': 'carrot', 'organic': true, 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.filter(food, 'organic');
|
|
* // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }]
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.filter(food, { 'type': 'fruit' });
|
|
* // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }]
|
|
*/
|
|
function filter(collection, callback, thisArg) {
|
|
var result = [];
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
|
|
var index = -1,
|
|
length = collection ? collection.length : 0;
|
|
|
|
if (typeof length == 'number') {
|
|
while (++index < length) {
|
|
var value = collection[index];
|
|
if (callback(value, index, collection)) {
|
|
result.push(value);
|
|
}
|
|
}
|
|
} else {
|
|
forOwn(collection, function(value, index, collection) {
|
|
if (callback(value, index, collection)) {
|
|
result.push(value);
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Examines each element in a `collection`, returning the first that the `callback`
|
|
* returns truthy for. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias detect, findWhere
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the found element, else `undefined`.
|
|
* @example
|
|
*
|
|
* _.find([1, 2, 3, 4], function(num) {
|
|
* return num % 2 == 0;
|
|
* });
|
|
* // => 2
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'organic': false, 'type': 'fruit' },
|
|
* { 'name': 'banana', 'organic': true, 'type': 'fruit' },
|
|
* { 'name': 'beet', 'organic': false, 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.find(food, { 'type': 'vegetable' });
|
|
* // => { 'name': 'beet', 'organic': false, 'type': 'vegetable' }
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.find(food, 'organic');
|
|
* // => { 'name': 'banana', 'organic': true, 'type': 'fruit' }
|
|
*/
|
|
function find(collection, callback, thisArg) {
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
|
|
var index = -1,
|
|
length = collection ? collection.length : 0;
|
|
|
|
if (typeof length == 'number') {
|
|
while (++index < length) {
|
|
var value = collection[index];
|
|
if (callback(value, index, collection)) {
|
|
return value;
|
|
}
|
|
}
|
|
} else {
|
|
var result;
|
|
forOwn(collection, function(value, index, collection) {
|
|
if (callback(value, index, collection)) {
|
|
result = value;
|
|
return false;
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Iterates over a `collection`, executing the `callback` for each element in
|
|
* the `collection`. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index|key, collection). Callbacks may exit iteration early
|
|
* by explicitly returning `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias each
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array|Object|String} Returns `collection`.
|
|
* @example
|
|
*
|
|
* _([1, 2, 3]).forEach(alert).join(',');
|
|
* // => alerts each number and returns '1,2,3'
|
|
*
|
|
* _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert);
|
|
* // => alerts each number value (order is not guaranteed)
|
|
*/
|
|
function forEach(collection, callback, thisArg) {
|
|
var index = -1,
|
|
length = collection ? collection.length : 0;
|
|
|
|
callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg);
|
|
if (typeof length == 'number') {
|
|
while (++index < length) {
|
|
if (callback(collection[index], index, collection) === false) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
forOwn(collection, callback);
|
|
}
|
|
return collection;
|
|
}
|
|
|
|
/**
|
|
* Creates an object composed of keys returned from running each element of the
|
|
* `collection` through the `callback`. The corresponding value of each key is
|
|
* an array of elements passed to `callback` that returned the key. The `callback`
|
|
* is bound to `thisArg` and invoked with three arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Object} Returns the composed aggregate object.
|
|
* @example
|
|
*
|
|
* _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); });
|
|
* // => { '4': [4.2], '6': [6.1, 6.4] }
|
|
*
|
|
* _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math);
|
|
* // => { '4': [4.2], '6': [6.1, 6.4] }
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.groupBy(['one', 'two', 'three'], 'length');
|
|
* // => { '3': ['one', 'two'], '5': ['three'] }
|
|
*/
|
|
function groupBy(collection, callback, thisArg) {
|
|
var result = {};
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
|
|
forEach(collection, function(value, key, collection) {
|
|
key = String(callback(value, key, collection));
|
|
(hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Invokes the method named by `methodName` on each element in the `collection`,
|
|
* returning an array of the results of each invoked method. Additional arguments
|
|
* will be passed to each invoked method. If `methodName` is a function, it will
|
|
* be invoked for, and `this` bound to, each element in the `collection`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|String} methodName The name of the method to invoke or
|
|
* the function invoked per iteration.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with.
|
|
* @returns {Array} Returns a new array of the results of each invoked method.
|
|
* @example
|
|
*
|
|
* _.invoke([[5, 1, 7], [3, 2, 1]], 'sort');
|
|
* // => [[1, 5, 7], [1, 2, 3]]
|
|
*
|
|
* _.invoke([123, 456], String.prototype.split, '');
|
|
* // => [['1', '2', '3'], ['4', '5', '6']]
|
|
*/
|
|
function invoke(collection, methodName) {
|
|
var args = nativeSlice.call(arguments, 2),
|
|
index = -1,
|
|
isFunc = typeof methodName == 'function',
|
|
length = collection ? collection.length : 0,
|
|
result = Array(typeof length == 'number' ? length : 0);
|
|
|
|
forEach(collection, function(value) {
|
|
result[++index] = (isFunc ? methodName : value[methodName]).apply(value, args);
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates an array of values by running each element in the `collection`
|
|
* through the `callback`. The `callback` is bound to `thisArg` and invoked with
|
|
* three arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias collect
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new array of the results of each `callback` execution.
|
|
* @example
|
|
*
|
|
* _.map([1, 2, 3], function(num) { return num * 3; });
|
|
* // => [3, 6, 9]
|
|
*
|
|
* _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
|
|
* // => [3, 6, 9] (order is not guaranteed)
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.map(stooges, 'name');
|
|
* // => ['moe', 'larry']
|
|
*/
|
|
function map(collection, callback, thisArg) {
|
|
var index = -1,
|
|
length = collection ? collection.length : 0;
|
|
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
if (typeof length == 'number') {
|
|
var result = Array(length);
|
|
while (++index < length) {
|
|
result[index] = callback(collection[index], index, collection);
|
|
}
|
|
} else {
|
|
result = [];
|
|
forOwn(collection, function(value, key, collection) {
|
|
result[++index] = callback(value, key, collection);
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the maximum value of an `array`. If `callback` is passed,
|
|
* it will be executed for each value in the `array` to generate the
|
|
* criterion by which the value is ranked. The `callback` is bound to
|
|
* `thisArg` and invoked with three arguments; (value, index, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the maximum value.
|
|
* @example
|
|
*
|
|
* _.max([4, 2, 8, 6]);
|
|
* // => 8
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* _.max(stooges, function(stooge) { return stooge.age; });
|
|
* // => { 'name': 'larry', 'age': 50 };
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.max(stooges, 'age');
|
|
* // => { 'name': 'larry', 'age': 50 };
|
|
*/
|
|
function max(collection, callback, thisArg) {
|
|
var computed = -Infinity,
|
|
result = computed;
|
|
|
|
if (!callback && isArray(collection)) {
|
|
var index = -1,
|
|
length = collection.length;
|
|
|
|
while (++index < length) {
|
|
var value = collection[index];
|
|
if (value > result) {
|
|
result = value;
|
|
}
|
|
}
|
|
} else {
|
|
callback = (!callback && isString(collection))
|
|
? charAtCallback
|
|
: lodash.createCallback(callback, thisArg);
|
|
|
|
forEach(collection, function(value, index, collection) {
|
|
var current = callback(value, index, collection);
|
|
if (current > computed) {
|
|
computed = current;
|
|
result = value;
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the minimum value of an `array`. If `callback` is passed,
|
|
* it will be executed for each value in the `array` to generate the
|
|
* criterion by which the value is ranked. The `callback` is bound to `thisArg`
|
|
* and invoked with three arguments; (value, index, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the minimum value.
|
|
* @example
|
|
*
|
|
* _.min([4, 2, 8, 6]);
|
|
* // => 2
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* _.min(stooges, function(stooge) { return stooge.age; });
|
|
* // => { 'name': 'moe', 'age': 40 };
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.min(stooges, 'age');
|
|
* // => { 'name': 'moe', 'age': 40 };
|
|
*/
|
|
function min(collection, callback, thisArg) {
|
|
var computed = Infinity,
|
|
result = computed;
|
|
|
|
if (!callback && isArray(collection)) {
|
|
var index = -1,
|
|
length = collection.length;
|
|
|
|
while (++index < length) {
|
|
var value = collection[index];
|
|
if (value < result) {
|
|
result = value;
|
|
}
|
|
}
|
|
} else {
|
|
callback = (!callback && isString(collection))
|
|
? charAtCallback
|
|
: lodash.createCallback(callback, thisArg);
|
|
|
|
forEach(collection, function(value, index, collection) {
|
|
var current = callback(value, index, collection);
|
|
if (current < computed) {
|
|
computed = current;
|
|
result = value;
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Retrieves the value of a specified property from all elements in the `collection`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {String} property The property to pluck.
|
|
* @returns {Array} Returns a new array of property values.
|
|
* @example
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* _.pluck(stooges, 'name');
|
|
* // => ['moe', 'larry']
|
|
*/
|
|
function pluck(collection, property) {
|
|
var index = -1,
|
|
length = collection ? collection.length : 0;
|
|
|
|
if (typeof length == 'number') {
|
|
var result = Array(length);
|
|
while (++index < length) {
|
|
result[index] = collection[index][property];
|
|
}
|
|
}
|
|
return result || map(collection, property);
|
|
}
|
|
|
|
/**
|
|
* Reduces a `collection` to a value which is the accumulated result of running
|
|
* each element in the `collection` through the `callback`, where each successive
|
|
* `callback` execution consumes the return value of the previous execution.
|
|
* If `accumulator` is not passed, the first element of the `collection` will be
|
|
* used as the initial `accumulator` value. The `callback` is bound to `thisArg`
|
|
* and invoked with four arguments; (accumulator, value, index|key, collection).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias foldl, inject
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [accumulator] Initial value of the accumulator.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the accumulated value.
|
|
* @example
|
|
*
|
|
* var sum = _.reduce([1, 2, 3], function(sum, num) {
|
|
* return sum + num;
|
|
* });
|
|
* // => 6
|
|
*
|
|
* var mapped = _.reduce({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
|
|
* result[key] = num * 3;
|
|
* return result;
|
|
* }, {});
|
|
* // => { 'a': 3, 'b': 6, 'c': 9 }
|
|
*/
|
|
function reduce(collection, callback, accumulator, thisArg) {
|
|
if (!collection) return accumulator;
|
|
var noaccum = arguments.length < 3;
|
|
callback = lodash.createCallback(callback, thisArg, 4);
|
|
|
|
var index = -1,
|
|
length = collection.length;
|
|
|
|
if (typeof length == 'number') {
|
|
if (noaccum) {
|
|
accumulator = collection[++index];
|
|
}
|
|
while (++index < length) {
|
|
accumulator = callback(accumulator, collection[index], index, collection);
|
|
}
|
|
} else {
|
|
forOwn(collection, function(value, index, collection) {
|
|
accumulator = noaccum
|
|
? (noaccum = false, value)
|
|
: callback(accumulator, value, index, collection)
|
|
});
|
|
}
|
|
return accumulator;
|
|
}
|
|
|
|
/**
|
|
* This method is similar to `_.reduce`, except that it iterates over a
|
|
* `collection` from right to left.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias foldr
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function} [callback=identity] The function called per iteration.
|
|
* @param {Mixed} [accumulator] Initial value of the accumulator.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the accumulated value.
|
|
* @example
|
|
*
|
|
* var list = [[0, 1], [2, 3], [4, 5]];
|
|
* var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []);
|
|
* // => [4, 5, 2, 3, 0, 1]
|
|
*/
|
|
function reduceRight(collection, callback, accumulator, thisArg) {
|
|
var iterable = collection,
|
|
length = collection ? collection.length : 0,
|
|
noaccum = arguments.length < 3;
|
|
|
|
if (typeof length != 'number') {
|
|
var props = keys(collection);
|
|
length = props.length;
|
|
}
|
|
callback = lodash.createCallback(callback, thisArg, 4);
|
|
forEach(collection, function(value, index, collection) {
|
|
index = props ? props[--length] : --length;
|
|
accumulator = noaccum
|
|
? (noaccum = false, iterable[index])
|
|
: callback(accumulator, iterable[index], index, collection);
|
|
});
|
|
return accumulator;
|
|
}
|
|
|
|
/**
|
|
* The opposite of `_.filter`, this method returns the elements of a
|
|
* `collection` that `callback` does **not** return truthy for.
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new array of elements that did **not** pass the
|
|
* callback check.
|
|
* @example
|
|
*
|
|
* var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
|
|
* // => [1, 3, 5]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'organic': false, 'type': 'fruit' },
|
|
* { 'name': 'carrot', 'organic': true, 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.reject(food, 'organic');
|
|
* // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }]
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.reject(food, { 'type': 'fruit' });
|
|
* // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }]
|
|
*/
|
|
function reject(collection, callback, thisArg) {
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
return filter(collection, function(value, index, collection) {
|
|
return !callback(value, index, collection);
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Creates an array of shuffled `array` values, using a version of the
|
|
* Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to shuffle.
|
|
* @returns {Array} Returns a new shuffled collection.
|
|
* @example
|
|
*
|
|
* _.shuffle([1, 2, 3, 4, 5, 6]);
|
|
* // => [4, 1, 6, 3, 5, 2]
|
|
*/
|
|
function shuffle(collection) {
|
|
var index = -1,
|
|
length = collection ? collection.length : 0,
|
|
result = Array(typeof length == 'number' ? length : 0);
|
|
|
|
forEach(collection, function(value) {
|
|
var rand = floor(nativeRandom() * (++index + 1));
|
|
result[index] = result[rand];
|
|
result[rand] = value;
|
|
});
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Gets the size of the `collection` by returning `collection.length` for arrays
|
|
* and array-like objects or the number of own enumerable properties for objects.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to inspect.
|
|
* @returns {Number} Returns `collection.length` or number of own enumerable properties.
|
|
* @example
|
|
*
|
|
* _.size([1, 2]);
|
|
* // => 2
|
|
*
|
|
* _.size({ 'one': 1, 'two': 2, 'three': 3 });
|
|
* // => 3
|
|
*
|
|
* _.size('curly');
|
|
* // => 5
|
|
*/
|
|
function size(collection) {
|
|
var length = collection ? collection.length : 0;
|
|
return typeof length == 'number' ? length : keys(collection).length;
|
|
}
|
|
|
|
/**
|
|
* Checks if the `callback` returns a truthy value for **any** element of a
|
|
* `collection`. The function returns as soon as it finds passing value, and
|
|
* does not iterate over the entire `collection`. The `callback` is bound to
|
|
* `thisArg` and invoked with three arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias any
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Boolean} Returns `true` if any element passes the callback check,
|
|
* else `false`.
|
|
* @example
|
|
*
|
|
* _.some([null, 0, 'yes', false], Boolean);
|
|
* // => true
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'organic': false, 'type': 'fruit' },
|
|
* { 'name': 'carrot', 'organic': true, 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.some(food, 'organic');
|
|
* // => true
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.some(food, { 'type': 'meat' });
|
|
* // => false
|
|
*/
|
|
function some(collection, callback, thisArg) {
|
|
var result;
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
|
|
var index = -1,
|
|
length = collection ? collection.length : 0;
|
|
|
|
if (typeof length == 'number') {
|
|
while (++index < length) {
|
|
if ((result = callback(collection[index], index, collection))) {
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
forOwn(collection, function(value, index, collection) {
|
|
return !(result = callback(value, index, collection));
|
|
});
|
|
}
|
|
return !!result;
|
|
}
|
|
|
|
/**
|
|
* Creates an array of elements, sorted in ascending order by the results of
|
|
* running each element in the `collection` through the `callback`. This method
|
|
* performs a stable sort, that is, it will preserve the original sort order of
|
|
* equal elements. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index|key, collection).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new array of sorted elements.
|
|
* @example
|
|
*
|
|
* _.sortBy([1, 2, 3], function(num) { return Math.sin(num); });
|
|
* // => [3, 1, 2]
|
|
*
|
|
* _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
|
|
* // => [3, 1, 2]
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.sortBy(['banana', 'strawberry', 'apple'], 'length');
|
|
* // => ['apple', 'banana', 'strawberry']
|
|
*/
|
|
function sortBy(collection, callback, thisArg) {
|
|
var index = -1,
|
|
length = collection ? collection.length : 0,
|
|
result = Array(typeof length == 'number' ? length : 0);
|
|
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
forEach(collection, function(value, key, collection) {
|
|
var object = result[++index] = getObject();
|
|
object.criteria = callback(value, key, collection);
|
|
object.index = index;
|
|
object.value = value;
|
|
});
|
|
|
|
length = result.length;
|
|
result.sort(compareAscending);
|
|
while (length--) {
|
|
var object = result[length];
|
|
result[length] = object.value;
|
|
releaseObject(object);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Converts the `collection` to an array.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to convert.
|
|
* @returns {Array} Returns the new converted array.
|
|
* @example
|
|
*
|
|
* (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4);
|
|
* // => [2, 3, 4]
|
|
*/
|
|
function toArray(collection) {
|
|
if (collection && typeof collection.length == 'number') {
|
|
return slice(collection);
|
|
}
|
|
return values(collection);
|
|
}
|
|
|
|
/**
|
|
* Examines each element in a `collection`, returning an array of all elements
|
|
* that have the given `properties`. When checking `properties`, this method
|
|
* performs a deep comparison between values to determine if they are equivalent
|
|
* to each other.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type Function
|
|
* @category Collections
|
|
* @param {Array|Object|String} collection The collection to iterate over.
|
|
* @param {Object} properties The object of property values to filter by.
|
|
* @returns {Array} Returns a new array of elements that have the given `properties`.
|
|
* @example
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* _.where(stooges, { 'age': 40 });
|
|
* // => [{ 'name': 'moe', 'age': 40 }]
|
|
*/
|
|
var where = filter;
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Creates an array with all falsey values of `array` removed. The values
|
|
* `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to compact.
|
|
* @returns {Array} Returns a new filtered array.
|
|
* @example
|
|
*
|
|
* _.compact([0, 1, false, 2, '', 3]);
|
|
* // => [1, 2, 3]
|
|
*/
|
|
function compact(array) {
|
|
var index = -1,
|
|
length = array ? array.length : 0,
|
|
result = [];
|
|
|
|
while (++index < length) {
|
|
var value = array[index];
|
|
if (value) {
|
|
result.push(value);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates an array of `array` elements not present in the other arrays
|
|
* using strict equality for comparisons, i.e. `===`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to process.
|
|
* @param {Array} [array1, array2, ...] Arrays to check.
|
|
* @returns {Array} Returns a new array of `array` elements not present in the
|
|
* other arrays.
|
|
* @example
|
|
*
|
|
* _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
|
|
* // => [1, 3, 4]
|
|
*/
|
|
function difference(array) {
|
|
var index = -1,
|
|
indexOf = getIndexOf(),
|
|
length = array ? array.length : 0,
|
|
seen = concat.apply(arrayRef, nativeSlice.call(arguments, 1)),
|
|
result = [];
|
|
|
|
var isLarge = length >= largeArraySize && indexOf === basicIndexOf;
|
|
|
|
if (isLarge) {
|
|
var cache = createCache(seen);
|
|
if (cache) {
|
|
indexOf = cacheIndexOf;
|
|
seen = cache;
|
|
} else {
|
|
isLarge = false;
|
|
}
|
|
}
|
|
while (++index < length) {
|
|
var value = array[index];
|
|
if (indexOf(seen, value) < 0) {
|
|
result.push(value);
|
|
}
|
|
}
|
|
if (isLarge) {
|
|
releaseObject(seen);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* This method is similar to `_.find`, except that it returns the index of
|
|
* the element that passes the callback check, instead of the element itself.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to search.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the index of the found element, else `-1`.
|
|
* @example
|
|
*
|
|
* _.findIndex(['apple', 'banana', 'beet'], function(food) {
|
|
* return /^b/.test(food);
|
|
* });
|
|
* // => 1
|
|
*/
|
|
function findIndex(array, callback, thisArg) {
|
|
var index = -1,
|
|
length = array ? array.length : 0;
|
|
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
while (++index < length) {
|
|
if (callback(array[index], index, array)) {
|
|
return index;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Gets the first element of the `array`. If a number `n` is passed, the first
|
|
* `n` elements of the `array` are returned. If a `callback` function is passed,
|
|
* elements at the beginning of the array are returned as long as the `callback`
|
|
* returns truthy. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index, array).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias head, take
|
|
* @category Arrays
|
|
* @param {Array} array The array to query.
|
|
* @param {Function|Object|Number|String} [callback|n] The function called
|
|
* per element or the number of elements to return. If a property name or
|
|
* object is passed, it will be used to create a "_.pluck" or "_.where"
|
|
* style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the first element(s) of `array`.
|
|
* @example
|
|
*
|
|
* _.first([1, 2, 3]);
|
|
* // => 1
|
|
*
|
|
* _.first([1, 2, 3], 2);
|
|
* // => [1, 2]
|
|
*
|
|
* _.first([1, 2, 3], function(num) {
|
|
* return num < 3;
|
|
* });
|
|
* // => [1, 2]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'banana', 'organic': true },
|
|
* { 'name': 'beet', 'organic': false },
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.first(food, 'organic');
|
|
* // => [{ 'name': 'banana', 'organic': true }]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'type': 'fruit' },
|
|
* { 'name': 'banana', 'type': 'fruit' },
|
|
* { 'name': 'beet', 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.first(food, { 'type': 'fruit' });
|
|
* // => [{ 'name': 'apple', 'type': 'fruit' }, { 'name': 'banana', 'type': 'fruit' }]
|
|
*/
|
|
function first(array, callback, thisArg) {
|
|
if (array) {
|
|
var n = 0,
|
|
length = array.length;
|
|
|
|
if (typeof callback != 'number' && callback != null) {
|
|
var index = -1;
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
while (++index < length && callback(array[index], index, array)) {
|
|
n++;
|
|
}
|
|
} else {
|
|
n = callback;
|
|
if (n == null || thisArg) {
|
|
return array[0];
|
|
}
|
|
}
|
|
return slice(array, 0, nativeMin(nativeMax(0, n), length));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Flattens a nested array (the nesting can be to any depth). If `isShallow`
|
|
* is truthy, `array` will only be flattened a single level. If `callback`
|
|
* is passed, each element of `array` is passed through a `callback` before
|
|
* flattening. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index, array).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to flatten.
|
|
* @param {Boolean} [isShallow=false] A flag to indicate only flattening a single level.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new flattened array.
|
|
* @example
|
|
*
|
|
* _.flatten([1, [2], [3, [[4]]]]);
|
|
* // => [1, 2, 3, 4];
|
|
*
|
|
* _.flatten([1, [2], [3, [[4]]]], true);
|
|
* // => [1, 2, 3, [[4]]];
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'curly', 'quotes': ['Oh, a wise guy, eh?', 'Poifect!'] },
|
|
* { 'name': 'moe', 'quotes': ['Spread out!', 'You knucklehead!'] }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.flatten(stooges, 'quotes');
|
|
* // => ['Oh, a wise guy, eh?', 'Poifect!', 'Spread out!', 'You knucklehead!']
|
|
*/
|
|
var flatten = overloadWrapper(function flatten(array, isShallow, callback) {
|
|
var index = -1,
|
|
length = array ? array.length : 0,
|
|
result = [];
|
|
|
|
while (++index < length) {
|
|
var value = array[index];
|
|
if (callback) {
|
|
value = callback(value, index, array);
|
|
}
|
|
// recursively flatten arrays (susceptible to call stack limits)
|
|
if (isArray(value)) {
|
|
push.apply(result, isShallow ? value : flatten(value));
|
|
} else {
|
|
result.push(value);
|
|
}
|
|
}
|
|
return result;
|
|
});
|
|
|
|
/**
|
|
* Gets the index at which the first occurrence of `value` is found using
|
|
* strict equality for comparisons, i.e. `===`. If the `array` is already
|
|
* sorted, passing `true` for `fromIndex` will run a faster binary search.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to search.
|
|
* @param {Mixed} value The value to search for.
|
|
* @param {Boolean|Number} [fromIndex=0] The index to search from or `true` to
|
|
* perform a binary search on a sorted `array`.
|
|
* @returns {Number} Returns the index of the matched value or `-1`.
|
|
* @example
|
|
*
|
|
* _.indexOf([1, 2, 3, 1, 2, 3], 2);
|
|
* // => 1
|
|
*
|
|
* _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
|
|
* // => 4
|
|
*
|
|
* _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
|
|
* // => 2
|
|
*/
|
|
function indexOf(array, value, fromIndex) {
|
|
if (typeof fromIndex == 'number') {
|
|
var length = array ? array.length : 0;
|
|
fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
|
|
} else if (fromIndex) {
|
|
var index = sortedIndex(array, value);
|
|
return array[index] === value ? index : -1;
|
|
}
|
|
return array ? basicIndexOf(array, value, fromIndex) : -1;
|
|
}
|
|
|
|
/**
|
|
* Gets all but the last element of `array`. If a number `n` is passed, the
|
|
* last `n` elements are excluded from the result. If a `callback` function
|
|
* is passed, elements at the end of the array are excluded from the result
|
|
* as long as the `callback` returns truthy. The `callback` is bound to
|
|
* `thisArg` and invoked with three arguments; (value, index, array).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to query.
|
|
* @param {Function|Object|Number|String} [callback|n=1] The function called
|
|
* per element or the number of elements to exclude. If a property name or
|
|
* object is passed, it will be used to create a "_.pluck" or "_.where"
|
|
* style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a slice of `array`.
|
|
* @example
|
|
*
|
|
* _.initial([1, 2, 3]);
|
|
* // => [1, 2]
|
|
*
|
|
* _.initial([1, 2, 3], 2);
|
|
* // => [1]
|
|
*
|
|
* _.initial([1, 2, 3], function(num) {
|
|
* return num > 1;
|
|
* });
|
|
* // => [1]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'beet', 'organic': false },
|
|
* { 'name': 'carrot', 'organic': true }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.initial(food, 'organic');
|
|
* // => [{ 'name': 'beet', 'organic': false }]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'banana', 'type': 'fruit' },
|
|
* { 'name': 'beet', 'type': 'vegetable' },
|
|
* { 'name': 'carrot', 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.initial(food, { 'type': 'vegetable' });
|
|
* // => [{ 'name': 'banana', 'type': 'fruit' }]
|
|
*/
|
|
function initial(array, callback, thisArg) {
|
|
if (!array) {
|
|
return [];
|
|
}
|
|
var n = 0,
|
|
length = array.length;
|
|
|
|
if (typeof callback != 'number' && callback != null) {
|
|
var index = length;
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
while (index-- && callback(array[index], index, array)) {
|
|
n++;
|
|
}
|
|
} else {
|
|
n = (callback == null || thisArg) ? 1 : callback || n;
|
|
}
|
|
return slice(array, 0, nativeMin(nativeMax(0, length - n), length));
|
|
}
|
|
|
|
/**
|
|
* Computes the intersection of all the passed-in arrays using strict equality
|
|
* for comparisons, i.e. `===`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} [array1, array2, ...] Arrays to process.
|
|
* @returns {Array} Returns a new array of unique elements that are present
|
|
* in **all** of the arrays.
|
|
* @example
|
|
*
|
|
* _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]);
|
|
* // => [1, 2]
|
|
*/
|
|
function intersection(array) {
|
|
var args = arguments,
|
|
argsLength = args.length,
|
|
argsIndex = -1,
|
|
caches = getArray(),
|
|
index = -1,
|
|
indexOf = getIndexOf(),
|
|
length = array ? array.length : 0,
|
|
result = [],
|
|
seen = getArray();
|
|
|
|
while (++argsIndex < argsLength) {
|
|
var value = args[argsIndex];
|
|
caches[argsIndex] = indexOf === basicIndexOf &&
|
|
(value ? value.length : 0) >= largeArraySize &&
|
|
createCache(argsIndex ? args[argsIndex] : seen);
|
|
}
|
|
outer:
|
|
while (++index < length) {
|
|
var cache = caches[0];
|
|
value = array[index];
|
|
|
|
if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
|
|
argsIndex = argsLength;
|
|
(cache || seen).push(value);
|
|
while (--argsIndex) {
|
|
cache = caches[argsIndex];
|
|
if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
|
|
continue outer;
|
|
}
|
|
}
|
|
result.push(value);
|
|
}
|
|
}
|
|
while (argsLength--) {
|
|
cache = caches[argsLength];
|
|
if (cache) {
|
|
releaseObject(cache);
|
|
}
|
|
}
|
|
releaseArray(caches);
|
|
releaseArray(seen);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Gets the last element of the `array`. If a number `n` is passed, the
|
|
* last `n` elements of the `array` are returned. If a `callback` function
|
|
* is passed, elements at the end of the array are returned as long as the
|
|
* `callback` returns truthy. The `callback` is bound to `thisArg` and
|
|
* invoked with three arguments;(value, index, array).
|
|
*
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to query.
|
|
* @param {Function|Object|Number|String} [callback|n] The function called
|
|
* per element or the number of elements to return. If a property name or
|
|
* object is passed, it will be used to create a "_.pluck" or "_.where"
|
|
* style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Mixed} Returns the last element(s) of `array`.
|
|
* @example
|
|
*
|
|
* _.last([1, 2, 3]);
|
|
* // => 3
|
|
*
|
|
* _.last([1, 2, 3], 2);
|
|
* // => [2, 3]
|
|
*
|
|
* _.last([1, 2, 3], function(num) {
|
|
* return num > 1;
|
|
* });
|
|
* // => [2, 3]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'beet', 'organic': false },
|
|
* { 'name': 'carrot', 'organic': true }
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.last(food, 'organic');
|
|
* // => [{ 'name': 'carrot', 'organic': true }]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'banana', 'type': 'fruit' },
|
|
* { 'name': 'beet', 'type': 'vegetable' },
|
|
* { 'name': 'carrot', 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.last(food, { 'type': 'vegetable' });
|
|
* // => [{ 'name': 'beet', 'type': 'vegetable' }, { 'name': 'carrot', 'type': 'vegetable' }]
|
|
*/
|
|
function last(array, callback, thisArg) {
|
|
if (array) {
|
|
var n = 0,
|
|
length = array.length;
|
|
|
|
if (typeof callback != 'number' && callback != null) {
|
|
var index = length;
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
while (index-- && callback(array[index], index, array)) {
|
|
n++;
|
|
}
|
|
} else {
|
|
n = callback;
|
|
if (n == null || thisArg) {
|
|
return array[length - 1];
|
|
}
|
|
}
|
|
return slice(array, nativeMax(0, length - n));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Gets the index at which the last occurrence of `value` is found using strict
|
|
* equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used
|
|
* as the offset from the end of the collection.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to search.
|
|
* @param {Mixed} value The value to search for.
|
|
* @param {Number} [fromIndex=array.length-1] The index to search from.
|
|
* @returns {Number} Returns the index of the matched value or `-1`.
|
|
* @example
|
|
*
|
|
* _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
|
|
* // => 4
|
|
*
|
|
* _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
|
|
* // => 1
|
|
*/
|
|
function lastIndexOf(array, value, fromIndex) {
|
|
var index = array ? array.length : 0;
|
|
if (typeof fromIndex == 'number') {
|
|
index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1;
|
|
}
|
|
while (index--) {
|
|
if (array[index] === value) {
|
|
return index;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Creates an array of numbers (positive and/or negative) progressing from
|
|
* `start` up to but not including `end`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Number} [start=0] The start of the range.
|
|
* @param {Number} end The end of the range.
|
|
* @param {Number} [step=1] The value to increment or decrement by.
|
|
* @returns {Array} Returns a new range array.
|
|
* @example
|
|
*
|
|
* _.range(10);
|
|
* // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
*
|
|
* _.range(1, 11);
|
|
* // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
*
|
|
* _.range(0, 30, 5);
|
|
* // => [0, 5, 10, 15, 20, 25]
|
|
*
|
|
* _.range(0, -10, -1);
|
|
* // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
|
|
*
|
|
* _.range(0);
|
|
* // => []
|
|
*/
|
|
function range(start, end, step) {
|
|
start = +start || 0;
|
|
step = +step || 1;
|
|
|
|
if (end == null) {
|
|
end = start;
|
|
start = 0;
|
|
}
|
|
// use `Array(length)` so V8 will avoid the slower "dictionary" mode
|
|
// http://youtu.be/XAqIpGU8ZZk#t=17m25s
|
|
var index = -1,
|
|
length = nativeMax(0, ceil((end - start) / step)),
|
|
result = Array(length);
|
|
|
|
while (++index < length) {
|
|
result[index] = start;
|
|
start += step;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* The opposite of `_.initial`, this method gets all but the first value of
|
|
* `array`. If a number `n` is passed, the first `n` values are excluded from
|
|
* the result. If a `callback` function is passed, elements at the beginning
|
|
* of the array are excluded from the result as long as the `callback` returns
|
|
* truthy. The `callback` is bound to `thisArg` and invoked with three
|
|
* arguments; (value, index, array).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias drop, tail
|
|
* @category Arrays
|
|
* @param {Array} array The array to query.
|
|
* @param {Function|Object|Number|String} [callback|n=1] The function called
|
|
* per element or the number of elements to exclude. If a property name or
|
|
* object is passed, it will be used to create a "_.pluck" or "_.where"
|
|
* style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a slice of `array`.
|
|
* @example
|
|
*
|
|
* _.rest([1, 2, 3]);
|
|
* // => [2, 3]
|
|
*
|
|
* _.rest([1, 2, 3], 2);
|
|
* // => [3]
|
|
*
|
|
* _.rest([1, 2, 3], function(num) {
|
|
* return num < 3;
|
|
* });
|
|
* // => [3]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'banana', 'organic': true },
|
|
* { 'name': 'beet', 'organic': false },
|
|
* ];
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.rest(food, 'organic');
|
|
* // => [{ 'name': 'beet', 'organic': false }]
|
|
*
|
|
* var food = [
|
|
* { 'name': 'apple', 'type': 'fruit' },
|
|
* { 'name': 'banana', 'type': 'fruit' },
|
|
* { 'name': 'beet', 'type': 'vegetable' }
|
|
* ];
|
|
*
|
|
* // using "_.where" callback shorthand
|
|
* _.rest(food, { 'type': 'fruit' });
|
|
* // => [{ 'name': 'beet', 'type': 'vegetable' }]
|
|
*/
|
|
function rest(array, callback, thisArg) {
|
|
if (typeof callback != 'number' && callback != null) {
|
|
var n = 0,
|
|
index = -1,
|
|
length = array ? array.length : 0;
|
|
|
|
callback = lodash.createCallback(callback, thisArg);
|
|
while (++index < length && callback(array[index], index, array)) {
|
|
n++;
|
|
}
|
|
} else {
|
|
n = (callback == null || thisArg) ? 1 : nativeMax(0, callback);
|
|
}
|
|
return slice(array, n);
|
|
}
|
|
|
|
/**
|
|
* Uses a binary search to determine the smallest index at which the `value`
|
|
* should be inserted into `array` in order to maintain the sort order of the
|
|
* sorted `array`. If `callback` is passed, it will be executed for `value` and
|
|
* each element in `array` to compute their sort ranking. The `callback` is
|
|
* bound to `thisArg` and invoked with one argument; (value).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to inspect.
|
|
* @param {Mixed} value The value to evaluate.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Number} Returns the index at which the value should be inserted
|
|
* into `array`.
|
|
* @example
|
|
*
|
|
* _.sortedIndex([20, 30, 50], 40);
|
|
* // => 2
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x');
|
|
* // => 2
|
|
*
|
|
* var dict = {
|
|
* 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 }
|
|
* };
|
|
*
|
|
* _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
|
|
* return dict.wordToNumber[word];
|
|
* });
|
|
* // => 2
|
|
*
|
|
* _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) {
|
|
* return this.wordToNumber[word];
|
|
* }, dict);
|
|
* // => 2
|
|
*/
|
|
function sortedIndex(array, value, callback, thisArg) {
|
|
var low = 0,
|
|
high = array ? array.length : low;
|
|
|
|
// explicitly reference `identity` for better inlining in Firefox
|
|
callback = callback ? lodash.createCallback(callback, thisArg, 1) : identity;
|
|
value = callback(value);
|
|
|
|
while (low < high) {
|
|
var mid = (low + high) >>> 1;
|
|
(callback(array[mid]) < value)
|
|
? low = mid + 1
|
|
: high = mid;
|
|
}
|
|
return low;
|
|
}
|
|
|
|
/**
|
|
* Computes the union of the passed-in arrays using strict equality for
|
|
* comparisons, i.e. `===`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} [array1, array2, ...] Arrays to process.
|
|
* @returns {Array} Returns a new array of unique values, in order, that are
|
|
* present in one or more of the arrays.
|
|
* @example
|
|
*
|
|
* _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]);
|
|
* // => [1, 2, 3, 101, 10]
|
|
*/
|
|
function union(array) {
|
|
if (!isArray(array)) {
|
|
arguments[0] = array ? nativeSlice.call(array) : arrayRef;
|
|
}
|
|
return uniq(concat.apply(arrayRef, arguments));
|
|
}
|
|
|
|
/**
|
|
* Creates a duplicate-value-free version of the `array` using strict equality
|
|
* for comparisons, i.e. `===`. If the `array` is already sorted, passing `true`
|
|
* for `isSorted` will run a faster algorithm. If `callback` is passed, each
|
|
* element of `array` is passed through the `callback` before uniqueness is computed.
|
|
* The `callback` is bound to `thisArg` and invoked with three arguments; (value, index, array).
|
|
*
|
|
* If a property name is passed for `callback`, the created "_.pluck" style
|
|
* callback will return the property value of the given element.
|
|
*
|
|
* If an object is passed for `callback`, the created "_.where" style callback
|
|
* will return `true` for elements that have the properties of the given object,
|
|
* else `false`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias unique
|
|
* @category Arrays
|
|
* @param {Array} array The array to process.
|
|
* @param {Boolean} [isSorted=false] A flag to indicate that the `array` is already sorted.
|
|
* @param {Function|Object|String} [callback=identity] The function called per
|
|
* iteration. If a property name or object is passed, it will be used to create
|
|
* a "_.pluck" or "_.where" style callback, respectively.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a duplicate-value-free array.
|
|
* @example
|
|
*
|
|
* _.uniq([1, 2, 1, 3, 1]);
|
|
* // => [1, 2, 3]
|
|
*
|
|
* _.uniq([1, 1, 2, 2, 3], true);
|
|
* // => [1, 2, 3]
|
|
*
|
|
* _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
|
|
* // => ['A', 'b', 'C']
|
|
*
|
|
* _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
|
|
* // => [1, 2.5, 3]
|
|
*
|
|
* // using "_.pluck" callback shorthand
|
|
* _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
|
|
* // => [{ 'x': 1 }, { 'x': 2 }]
|
|
*/
|
|
var uniq = overloadWrapper(function(array, isSorted, callback) {
|
|
var index = -1,
|
|
indexOf = getIndexOf(),
|
|
length = array ? array.length : 0,
|
|
result = [];
|
|
|
|
var isLarge = !isSorted && length >= largeArraySize && indexOf === basicIndexOf,
|
|
seen = (callback || isLarge) ? getArray() : result;
|
|
|
|
if (isLarge) {
|
|
var cache = createCache(seen);
|
|
if (cache) {
|
|
indexOf = cacheIndexOf;
|
|
seen = cache;
|
|
} else {
|
|
isLarge = false;
|
|
seen = callback ? seen : (releaseArray(seen), result);
|
|
}
|
|
}
|
|
while (++index < length) {
|
|
var value = array[index],
|
|
computed = callback ? callback(value, index, array) : value;
|
|
|
|
if (isSorted
|
|
? !index || seen[seen.length - 1] !== computed
|
|
: indexOf(seen, computed) < 0
|
|
) {
|
|
if (callback || isLarge) {
|
|
seen.push(computed);
|
|
}
|
|
result.push(value);
|
|
}
|
|
}
|
|
if (isLarge) {
|
|
releaseArray(seen.array);
|
|
releaseObject(seen);
|
|
} else if (callback) {
|
|
releaseArray(seen);
|
|
}
|
|
return result;
|
|
});
|
|
|
|
/**
|
|
* The inverse of `_.zip`, this method splits groups of elements into arrays
|
|
* composed of elements from each group at their corresponding indexes.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to process.
|
|
* @returns {Array} Returns a new array of the composed arrays.
|
|
* @example
|
|
*
|
|
* _.unzip([['moe', 30, true], ['larry', 40, false]]);
|
|
* // => [['moe', 'larry'], [30, 40], [true, false]];
|
|
*/
|
|
function unzip(array) {
|
|
var index = -1,
|
|
length = array ? max(pluck(array, 'length')) : 0,
|
|
result = Array(length < 0 ? 0 : length);
|
|
|
|
while (++index < length) {
|
|
result[index] = pluck(array, index);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates an array with all occurrences of the passed values removed using
|
|
* strict equality for comparisons, i.e. `===`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} array The array to filter.
|
|
* @param {Mixed} [value1, value2, ...] Values to remove.
|
|
* @returns {Array} Returns a new filtered array.
|
|
* @example
|
|
*
|
|
* _.without([1, 2, 1, 0, 3, 1, 4], 0, 1);
|
|
* // => [2, 3, 4]
|
|
*/
|
|
function without(array) {
|
|
return difference(array, nativeSlice.call(arguments, 1));
|
|
}
|
|
|
|
/**
|
|
* Groups the elements of each array at their corresponding indexes. Useful for
|
|
* separate data sources that are coordinated through matching array indexes.
|
|
* For a matrix of nested arrays, `_.zip.apply(...)` can transpose the matrix
|
|
* in a similar fashion.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Arrays
|
|
* @param {Array} [array1, array2, ...] Arrays to process.
|
|
* @returns {Array} Returns a new array of grouped elements.
|
|
* @example
|
|
*
|
|
* _.zip(['moe', 'larry'], [30, 40], [true, false]);
|
|
* // => [['moe', 30, true], ['larry', 40, false]]
|
|
*/
|
|
function zip(array) {
|
|
return array ? unzip(arguments) : [];
|
|
}
|
|
|
|
/**
|
|
* Creates an object composed from arrays of `keys` and `values`. Pass either
|
|
* a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`, or
|
|
* two arrays, one of `keys` and one of corresponding `values`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @alias object
|
|
* @category Arrays
|
|
* @param {Array} keys The array of keys.
|
|
* @param {Array} [values=[]] The array of values.
|
|
* @returns {Object} Returns an object composed of the given keys and
|
|
* corresponding values.
|
|
* @example
|
|
*
|
|
* _.zipObject(['moe', 'larry'], [30, 40]);
|
|
* // => { 'moe': 30, 'larry': 40 }
|
|
*/
|
|
function zipObject(keys, values) {
|
|
var index = -1,
|
|
length = keys ? keys.length : 0,
|
|
result = {};
|
|
|
|
while (++index < length) {
|
|
var key = keys[index];
|
|
if (values) {
|
|
result[key] = values[index];
|
|
} else {
|
|
result[key[0]] = key[1];
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* If `n` is greater than `0`, a function is created that is restricted to
|
|
* executing `func`, with the `this` binding and arguments of the created
|
|
* function, only after it is called `n` times. If `n` is less than `1`,
|
|
* `func` is executed immediately, without a `this` binding or additional
|
|
* arguments, and its result is returned.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Number} n The number of times the function must be called before
|
|
* it is executed.
|
|
* @param {Function} func The function to restrict.
|
|
* @returns {Function} Returns the new restricted function.
|
|
* @example
|
|
*
|
|
* var renderNotes = _.after(notes.length, render);
|
|
* _.forEach(notes, function(note) {
|
|
* note.asyncSave({ 'success': renderNotes });
|
|
* });
|
|
* // `renderNotes` is run once, after all notes have saved
|
|
*/
|
|
function after(n, func) {
|
|
if (n < 1) {
|
|
return func();
|
|
}
|
|
return function() {
|
|
if (--n < 1) {
|
|
return func.apply(this, arguments);
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a function that, when called, invokes `func` with the `this`
|
|
* binding of `thisArg` and prepends any additional `bind` arguments to those
|
|
* passed to the bound function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to bind.
|
|
* @param {Mixed} [thisArg] The `this` binding of `func`.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
|
|
* @returns {Function} Returns the new bound function.
|
|
* @example
|
|
*
|
|
* var func = function(greeting) {
|
|
* return greeting + ' ' + this.name;
|
|
* };
|
|
*
|
|
* func = _.bind(func, { 'name': 'moe' }, 'hi');
|
|
* func();
|
|
* // => 'hi moe'
|
|
*/
|
|
function bind(func, thisArg) {
|
|
// use `Function#bind` if it exists and is fast
|
|
// (in V8 `Function#bind` is slower except when partially applied)
|
|
return support.fastBind || (nativeBind && arguments.length > 2)
|
|
? nativeBind.call.apply(nativeBind, arguments)
|
|
: createBound(func, thisArg, nativeSlice.call(arguments, 2));
|
|
}
|
|
|
|
/**
|
|
* Binds methods on `object` to `object`, overwriting the existing method.
|
|
* Method names may be specified as individual arguments or as arrays of method
|
|
* names. If no method names are provided, all the function properties of `object`
|
|
* will be bound.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Object} object The object to bind and assign the bound methods to.
|
|
* @param {String} [methodName1, methodName2, ...] Method names on the object to bind.
|
|
* @returns {Object} Returns `object`.
|
|
* @example
|
|
*
|
|
* var view = {
|
|
* 'label': 'docs',
|
|
* 'onClick': function() { alert('clicked ' + this.label); }
|
|
* };
|
|
*
|
|
* _.bindAll(view);
|
|
* jQuery('#docs').on('click', view.onClick);
|
|
* // => alerts 'clicked docs', when the button is clicked
|
|
*/
|
|
function bindAll(object) {
|
|
var funcs = arguments.length > 1 ? concat.apply(arrayRef, nativeSlice.call(arguments, 1)) : functions(object),
|
|
index = -1,
|
|
length = funcs.length;
|
|
|
|
while (++index < length) {
|
|
var key = funcs[index];
|
|
object[key] = bind(object[key], object);
|
|
}
|
|
return object;
|
|
}
|
|
|
|
/**
|
|
* Creates a function that, when called, invokes the method at `object[key]`
|
|
* and prepends any additional `bindKey` arguments to those passed to the bound
|
|
* function. This method differs from `_.bind` by allowing bound functions to
|
|
* reference methods that will be redefined or don't yet exist.
|
|
* See http://michaux.ca/articles/lazy-function-definition-pattern.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Object} object The object the method belongs to.
|
|
* @param {String} key The key of the method.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
|
|
* @returns {Function} Returns the new bound function.
|
|
* @example
|
|
*
|
|
* var object = {
|
|
* 'name': 'moe',
|
|
* 'greet': function(greeting) {
|
|
* return greeting + ' ' + this.name;
|
|
* }
|
|
* };
|
|
*
|
|
* var func = _.bindKey(object, 'greet', 'hi');
|
|
* func();
|
|
* // => 'hi moe'
|
|
*
|
|
* object.greet = function(greeting) {
|
|
* return greeting + ', ' + this.name + '!';
|
|
* };
|
|
*
|
|
* func();
|
|
* // => 'hi, moe!'
|
|
*/
|
|
function bindKey(object, key) {
|
|
return createBound(object, key, nativeSlice.call(arguments, 2), indicatorObject);
|
|
}
|
|
|
|
/**
|
|
* Creates a function that is the composition of the passed functions,
|
|
* where each function consumes the return value of the function that follows.
|
|
* For example, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
|
|
* Each function is executed with the `this` binding of the composed function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} [func1, func2, ...] Functions to compose.
|
|
* @returns {Function} Returns the new composed function.
|
|
* @example
|
|
*
|
|
* var greet = function(name) { return 'hi ' + name; };
|
|
* var exclaim = function(statement) { return statement + '!'; };
|
|
* var welcome = _.compose(exclaim, greet);
|
|
* welcome('moe');
|
|
* // => 'hi moe!'
|
|
*/
|
|
function compose() {
|
|
var funcs = arguments;
|
|
return function() {
|
|
var args = arguments,
|
|
length = funcs.length;
|
|
|
|
while (length--) {
|
|
args = [funcs[length].apply(this, args)];
|
|
}
|
|
return args[0];
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Produces a callback bound to an optional `thisArg`. If `func` is a property
|
|
* name, the created callback will return the property value for a given element.
|
|
* If `func` is an object, the created callback will return `true` for elements
|
|
* that contain the equivalent object properties, otherwise it will return `false`.
|
|
*
|
|
* Note: All Lo-Dash methods, that accept a `callback` argument, use `_.createCallback`.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Mixed} [func=identity] The value to convert to a callback.
|
|
* @param {Mixed} [thisArg] The `this` binding of the created callback.
|
|
* @param {Number} [argCount=3] The number of arguments the callback accepts.
|
|
* @returns {Function} Returns a callback function.
|
|
* @example
|
|
*
|
|
* var stooges = [
|
|
* { 'name': 'moe', 'age': 40 },
|
|
* { 'name': 'larry', 'age': 50 }
|
|
* ];
|
|
*
|
|
* // wrap to create custom callback shorthands
|
|
* _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) {
|
|
* var match = /^(.+?)__([gl]t)(.+)$/.exec(callback);
|
|
* return !match ? func(callback, thisArg) : function(object) {
|
|
* return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3];
|
|
* };
|
|
* });
|
|
*
|
|
* _.filter(stooges, 'age__gt45');
|
|
* // => [{ 'name': 'larry', 'age': 50 }]
|
|
*
|
|
* // create mixins with support for "_.pluck" and "_.where" callback shorthands
|
|
* _.mixin({
|
|
* 'toLookup': function(collection, callback, thisArg) {
|
|
* callback = _.createCallback(callback, thisArg);
|
|
* return _.reduce(collection, function(result, value, index, collection) {
|
|
* return (result[callback(value, index, collection)] = value, result);
|
|
* }, {});
|
|
* }
|
|
* });
|
|
*
|
|
* _.toLookup(stooges, 'name');
|
|
* // => { 'moe': { 'name': 'moe', 'age': 40 }, 'larry': { 'name': 'larry', 'age': 50 } }
|
|
*/
|
|
function createCallback(func, thisArg, argCount) {
|
|
if (func == null) {
|
|
return identity;
|
|
}
|
|
var type = typeof func;
|
|
if (type != 'function') {
|
|
if (type != 'object') {
|
|
return function(object) {
|
|
return object[func];
|
|
};
|
|
}
|
|
var props = keys(func);
|
|
return function(object) {
|
|
var length = props.length,
|
|
result = false;
|
|
while (length--) {
|
|
if (!(result = isEqual(object[props[length]], func[props[length]], indicatorObject))) {
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
}
|
|
if (typeof thisArg == 'undefined' || (reThis && !reThis.test(fnToString.call(func)))) {
|
|
return func;
|
|
}
|
|
if (argCount === 1) {
|
|
return function(value) {
|
|
return func.call(thisArg, value);
|
|
};
|
|
}
|
|
if (argCount === 2) {
|
|
return function(a, b) {
|
|
return func.call(thisArg, a, b);
|
|
};
|
|
}
|
|
if (argCount === 4) {
|
|
return function(accumulator, value, index, collection) {
|
|
return func.call(thisArg, accumulator, value, index, collection);
|
|
};
|
|
}
|
|
return function(value, index, collection) {
|
|
return func.call(thisArg, value, index, collection);
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a function that will delay the execution of `func` until after
|
|
* `wait` milliseconds have elapsed since the last time it was invoked. Pass
|
|
* an `options` object to indicate that `func` should be invoked on the leading
|
|
* and/or trailing edge of the `wait` timeout. Subsequent calls to the debounced
|
|
* function will return the result of the last `func` call.
|
|
*
|
|
* Note: If `leading` and `trailing` options are `true`, `func` will be called
|
|
* on the trailing edge of the timeout only if the the debounced function is
|
|
* invoked more than once during the `wait` timeout.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to debounce.
|
|
* @param {Number} wait The number of milliseconds to delay.
|
|
* @param {Object} options The options object.
|
|
* [leading=false] A boolean to specify execution on the leading edge of the timeout.
|
|
* [maxWait] The maximum time `func` is allowed to be delayed before it's called.
|
|
* [trailing=true] A boolean to specify execution on the trailing edge of the timeout.
|
|
* @returns {Function} Returns the new debounced function.
|
|
* @example
|
|
*
|
|
* var lazyLayout = _.debounce(calculateLayout, 300);
|
|
* jQuery(window).on('resize', lazyLayout);
|
|
*
|
|
* jQuery('#postbox').on('click', _.debounce(sendMail, 200, {
|
|
* 'leading': true,
|
|
* 'trailing': false
|
|
* });
|
|
*/
|
|
function debounce(func, wait, options) {
|
|
var args,
|
|
result,
|
|
thisArg,
|
|
callCount = 0,
|
|
lastCalled = 0,
|
|
maxWait = false,
|
|
maxTimeoutId = null,
|
|
timeoutId = null,
|
|
trailing = true;
|
|
|
|
function clear() {
|
|
clearTimeout(maxTimeoutId);
|
|
clearTimeout(timeoutId);
|
|
callCount = 0;
|
|
maxTimeoutId = timeoutId = null;
|
|
}
|
|
|
|
function delayed() {
|
|
var isCalled = trailing && (!leading || callCount > 1);
|
|
clear();
|
|
if (isCalled) {
|
|
if (maxWait !== false) {
|
|
lastCalled = new Date;
|
|
}
|
|
result = func.apply(thisArg, args);
|
|
}
|
|
}
|
|
|
|
function maxDelayed() {
|
|
clear();
|
|
if (trailing || (maxWait !== wait)) {
|
|
lastCalled = new Date;
|
|
result = func.apply(thisArg, args);
|
|
}
|
|
}
|
|
|
|
wait = nativeMax(0, wait || 0);
|
|
if (options === true) {
|
|
var leading = true;
|
|
trailing = false;
|
|
} else if (isObject(options)) {
|
|
leading = options.leading;
|
|
maxWait = 'maxWait' in options && nativeMax(wait, options.maxWait || 0);
|
|
trailing = 'trailing' in options ? options.trailing : trailing;
|
|
}
|
|
return function() {
|
|
args = arguments;
|
|
thisArg = this;
|
|
callCount++;
|
|
|
|
// avoid issues with Titanium and `undefined` timeout ids
|
|
// https://github.com/appcelerator/titanium_mobile/blob/3_1_0_GA/android/titanium/src/java/ti/modules/titanium/TitaniumModule.java#L185-L192
|
|
clearTimeout(timeoutId);
|
|
|
|
if (maxWait === false) {
|
|
if (leading && callCount < 2) {
|
|
result = func.apply(thisArg, args);
|
|
}
|
|
} else {
|
|
var now = new Date;
|
|
if (!maxTimeoutId && !leading) {
|
|
lastCalled = now;
|
|
}
|
|
var remaining = maxWait - (now - lastCalled);
|
|
if (remaining <= 0) {
|
|
clearTimeout(maxTimeoutId);
|
|
maxTimeoutId = null;
|
|
lastCalled = now;
|
|
result = func.apply(thisArg, args);
|
|
}
|
|
else if (!maxTimeoutId) {
|
|
maxTimeoutId = setTimeout(maxDelayed, remaining);
|
|
}
|
|
}
|
|
if (wait !== maxWait) {
|
|
timeoutId = setTimeout(delayed, wait);
|
|
}
|
|
return result;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Defers executing the `func` function until the current call stack has cleared.
|
|
* Additional arguments will be passed to `func` when it is invoked.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to defer.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with.
|
|
* @returns {Number} Returns the timer id.
|
|
* @example
|
|
*
|
|
* _.defer(function() { alert('deferred'); });
|
|
* // returns from the function before `alert` is called
|
|
*/
|
|
function defer(func) {
|
|
var args = nativeSlice.call(arguments, 1);
|
|
return setTimeout(function() { func.apply(undefined, args); }, 1);
|
|
}
|
|
// use `setImmediate` if it's available in Node.js
|
|
if (isV8 && freeModule && typeof setImmediate == 'function') {
|
|
defer = bind(setImmediate, context);
|
|
}
|
|
|
|
/**
|
|
* Executes the `func` function after `wait` milliseconds. Additional arguments
|
|
* will be passed to `func` when it is invoked.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to delay.
|
|
* @param {Number} wait The number of milliseconds to delay execution.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with.
|
|
* @returns {Number} Returns the timer id.
|
|
* @example
|
|
*
|
|
* var log = _.bind(console.log, console);
|
|
* _.delay(log, 1000, 'logged later');
|
|
* // => 'logged later' (Appears after one second.)
|
|
*/
|
|
function delay(func, wait) {
|
|
var args = nativeSlice.call(arguments, 2);
|
|
return setTimeout(function() { func.apply(undefined, args); }, wait);
|
|
}
|
|
|
|
/**
|
|
* Creates a function that memoizes the result of `func`. If `resolver` is
|
|
* passed, it will be used to determine the cache key for storing the result
|
|
* based on the arguments passed to the memoized function. By default, the first
|
|
* argument passed to the memoized function is used as the cache key. The `func`
|
|
* is executed with the `this` binding of the memoized function. The result
|
|
* cache is exposed as the `cache` property on the memoized function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to have its output memoized.
|
|
* @param {Function} [resolver] A function used to resolve the cache key.
|
|
* @returns {Function} Returns the new memoizing function.
|
|
* @example
|
|
*
|
|
* var fibonacci = _.memoize(function(n) {
|
|
* return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
|
|
* });
|
|
*/
|
|
function memoize(func, resolver) {
|
|
function memoized() {
|
|
var cache = memoized.cache,
|
|
key = keyPrefix + (resolver ? resolver.apply(this, arguments) : arguments[0]);
|
|
|
|
return hasOwnProperty.call(cache, key)
|
|
? cache[key]
|
|
: (cache[key] = func.apply(this, arguments));
|
|
}
|
|
memoized.cache = {};
|
|
return memoized;
|
|
}
|
|
|
|
/**
|
|
* Creates a function that is restricted to execute `func` once. Repeat calls to
|
|
* the function will return the value of the first call. The `func` is executed
|
|
* with the `this` binding of the created function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to restrict.
|
|
* @returns {Function} Returns the new restricted function.
|
|
* @example
|
|
*
|
|
* var initialize = _.once(createApplication);
|
|
* initialize();
|
|
* initialize();
|
|
* // `initialize` executes `createApplication` once
|
|
*/
|
|
function once(func) {
|
|
var ran,
|
|
result;
|
|
|
|
return function() {
|
|
if (ran) {
|
|
return result;
|
|
}
|
|
ran = true;
|
|
result = func.apply(this, arguments);
|
|
|
|
// clear the `func` variable so the function may be garbage collected
|
|
func = null;
|
|
return result;
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates a function that, when called, invokes `func` with any additional
|
|
* `partial` arguments prepended to those passed to the new function. This
|
|
* method is similar to `_.bind`, except it does **not** alter the `this` binding.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to partially apply arguments to.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
|
|
* @returns {Function} Returns the new partially applied function.
|
|
* @example
|
|
*
|
|
* var greet = function(greeting, name) { return greeting + ' ' + name; };
|
|
* var hi = _.partial(greet, 'hi');
|
|
* hi('moe');
|
|
* // => 'hi moe'
|
|
*/
|
|
function partial(func) {
|
|
return createBound(func, nativeSlice.call(arguments, 1));
|
|
}
|
|
|
|
/**
|
|
* This method is similar to `_.partial`, except that `partial` arguments are
|
|
* appended to those passed to the new function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to partially apply arguments to.
|
|
* @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
|
|
* @returns {Function} Returns the new partially applied function.
|
|
* @example
|
|
*
|
|
* var defaultsDeep = _.partialRight(_.merge, _.defaults);
|
|
*
|
|
* var options = {
|
|
* 'variable': 'data',
|
|
* 'imports': { 'jq': $ }
|
|
* };
|
|
*
|
|
* defaultsDeep(options, _.templateSettings);
|
|
*
|
|
* options.variable
|
|
* // => 'data'
|
|
*
|
|
* options.imports
|
|
* // => { '_': _, 'jq': $ }
|
|
*/
|
|
function partialRight(func) {
|
|
return createBound(func, nativeSlice.call(arguments, 1), null, indicatorObject);
|
|
}
|
|
|
|
/**
|
|
* Creates a function that, when executed, will only call the `func` function
|
|
* at most once per every `wait` milliseconds. Pass an `options` object to
|
|
* indicate that `func` should be invoked on the leading and/or trailing edge
|
|
* of the `wait` timeout. Subsequent calls to the throttled function will
|
|
* return the result of the last `func` call.
|
|
*
|
|
* Note: If `leading` and `trailing` options are `true`, `func` will be called
|
|
* on the trailing edge of the timeout only if the the throttled function is
|
|
* invoked more than once during the `wait` timeout.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Function} func The function to throttle.
|
|
* @param {Number} wait The number of milliseconds to throttle executions to.
|
|
* @param {Object} options The options object.
|
|
* [leading=true] A boolean to specify execution on the leading edge of the timeout.
|
|
* [trailing=true] A boolean to specify execution on the trailing edge of the timeout.
|
|
* @returns {Function} Returns the new throttled function.
|
|
* @example
|
|
*
|
|
* var throttled = _.throttle(updatePosition, 100);
|
|
* jQuery(window).on('scroll', throttled);
|
|
*
|
|
* jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
|
|
* 'trailing': false
|
|
* }));
|
|
*/
|
|
function throttle(func, wait, options) {
|
|
var leading = true,
|
|
trailing = true;
|
|
|
|
if (options === false) {
|
|
leading = false;
|
|
} else if (isObject(options)) {
|
|
leading = 'leading' in options ? options.leading : leading;
|
|
trailing = 'trailing' in options ? options.trailing : trailing;
|
|
}
|
|
options = getObject();
|
|
options.leading = leading;
|
|
options.maxWait = wait;
|
|
options.trailing = trailing;
|
|
|
|
var result = debounce(func, wait, options);
|
|
releaseObject(options);
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Creates a function that passes `value` to the `wrapper` function as its
|
|
* first argument. Additional arguments passed to the function are appended
|
|
* to those passed to the `wrapper` function. The `wrapper` is executed with
|
|
* the `this` binding of the created function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Functions
|
|
* @param {Mixed} value The value to wrap.
|
|
* @param {Function} wrapper The wrapper function.
|
|
* @returns {Function} Returns the new function.
|
|
* @example
|
|
*
|
|
* var hello = function(name) { return 'hello ' + name; };
|
|
* hello = _.wrap(hello, function(func) {
|
|
* return 'before, ' + func('moe') + ', after';
|
|
* });
|
|
* hello();
|
|
* // => 'before, hello moe, after'
|
|
*/
|
|
function wrap(value, wrapper) {
|
|
return function() {
|
|
var args = [value];
|
|
push.apply(args, arguments);
|
|
return wrapper.apply(this, args);
|
|
};
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their
|
|
* corresponding HTML entities.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {String} string The string to escape.
|
|
* @returns {String} Returns the escaped string.
|
|
* @example
|
|
*
|
|
* _.escape('Moe, Larry & Curly');
|
|
* // => 'Moe, Larry & Curly'
|
|
*/
|
|
function escape(string) {
|
|
return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
|
|
}
|
|
|
|
/**
|
|
* This method returns the first argument passed to it.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Mixed} value Any value.
|
|
* @returns {Mixed} Returns `value`.
|
|
* @example
|
|
*
|
|
* var moe = { 'name': 'moe' };
|
|
* moe === _.identity(moe);
|
|
* // => true
|
|
*/
|
|
function identity(value) {
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Adds functions properties of `object` to the `lodash` function and chainable
|
|
* wrapper.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Object} object The object of function properties to add to `lodash`.
|
|
* @example
|
|
*
|
|
* _.mixin({
|
|
* 'capitalize': function(string) {
|
|
* return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase();
|
|
* }
|
|
* });
|
|
*
|
|
* _.capitalize('moe');
|
|
* // => 'Moe'
|
|
*
|
|
* _('moe').capitalize();
|
|
* // => 'Moe'
|
|
*/
|
|
function mixin(object) {
|
|
forEach(functions(object), function(methodName) {
|
|
var func = lodash[methodName] = object[methodName];
|
|
|
|
lodash.prototype[methodName] = function() {
|
|
var value = this.__wrapped__,
|
|
args = [value];
|
|
|
|
push.apply(args, arguments);
|
|
var result = func.apply(lodash, args);
|
|
return (value && typeof value == 'object' && value === result)
|
|
? this
|
|
: new lodashWrapper(result);
|
|
};
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Reverts the '_' variable to its previous value and returns a reference to
|
|
* the `lodash` function.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @returns {Function} Returns the `lodash` function.
|
|
* @example
|
|
*
|
|
* var lodash = _.noConflict();
|
|
*/
|
|
function noConflict() {
|
|
context._ = oldDash;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Converts the given `value` into an integer of the specified `radix`.
|
|
* If `radix` is `undefined` or `0`, a `radix` of `10` is used unless the
|
|
* `value` is a hexadecimal, in which case a `radix` of `16` is used.
|
|
*
|
|
* Note: This method avoids differences in native ES3 and ES5 `parseInt`
|
|
* implementations. See http://es5.github.com/#E.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {String} value The value to parse.
|
|
* @param {Number} [radix] The radix used to interpret the value to parse.
|
|
* @returns {Number} Returns the new integer value.
|
|
* @example
|
|
*
|
|
* _.parseInt('08');
|
|
* // => 8
|
|
*/
|
|
var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) {
|
|
// Firefox and Opera still follow the ES3 specified implementation of `parseInt`
|
|
return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0);
|
|
};
|
|
|
|
/**
|
|
* Produces a random number between `min` and `max` (inclusive). If only one
|
|
* argument is passed, a number between `0` and the given number will be returned.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Number} [min=0] The minimum possible value.
|
|
* @param {Number} [max=1] The maximum possible value.
|
|
* @returns {Number} Returns a random number.
|
|
* @example
|
|
*
|
|
* _.random(0, 5);
|
|
* // => a number between 0 and 5
|
|
*
|
|
* _.random(5);
|
|
* // => also a number between 0 and 5
|
|
*/
|
|
function random(min, max) {
|
|
if (min == null && max == null) {
|
|
max = 1;
|
|
}
|
|
min = +min || 0;
|
|
if (max == null) {
|
|
max = min;
|
|
min = 0;
|
|
} else {
|
|
max = +max || 0;
|
|
}
|
|
var rand = nativeRandom();
|
|
return (min % 1 || max % 1)
|
|
? min + nativeMin(rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1))), max)
|
|
: min + floor(rand * (max - min + 1));
|
|
}
|
|
|
|
/**
|
|
* Resolves the value of `property` on `object`. If `property` is a function,
|
|
* it will be invoked with the `this` binding of `object` and its result returned,
|
|
* else the property value is returned. If `object` is falsey, then `undefined`
|
|
* is returned.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Object} object The object to inspect.
|
|
* @param {String} property The property to get the value of.
|
|
* @returns {Mixed} Returns the resolved value.
|
|
* @example
|
|
*
|
|
* var object = {
|
|
* 'cheese': 'crumpets',
|
|
* 'stuff': function() {
|
|
* return 'nonsense';
|
|
* }
|
|
* };
|
|
*
|
|
* _.result(object, 'cheese');
|
|
* // => 'crumpets'
|
|
*
|
|
* _.result(object, 'stuff');
|
|
* // => 'nonsense'
|
|
*/
|
|
function result(object, property) {
|
|
var value = object ? object[property] : undefined;
|
|
return isFunction(value) ? object[property]() : value;
|
|
}
|
|
|
|
/**
|
|
* A micro-templating method that handles arbitrary delimiters, preserves
|
|
* whitespace, and correctly escapes quotes within interpolated code.
|
|
*
|
|
* Note: In the development build, `_.template` utilizes sourceURLs for easier
|
|
* debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
|
|
*
|
|
* For more information on precompiling templates see:
|
|
* http://lodash.com/#custom-builds
|
|
*
|
|
* For more information on Chrome extension sandboxes see:
|
|
* http://developer.chrome.com/stable/extensions/sandboxingEval.html
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {String} text The template text.
|
|
* @param {Object} data The data object used to populate the text.
|
|
* @param {Object} options The options object.
|
|
* escape - The "escape" delimiter regexp.
|
|
* evaluate - The "evaluate" delimiter regexp.
|
|
* interpolate - The "interpolate" delimiter regexp.
|
|
* sourceURL - The sourceURL of the template's compiled source.
|
|
* variable - The data object variable name.
|
|
* @returns {Function|String} Returns a compiled function when no `data` object
|
|
* is given, else it returns the interpolated text.
|
|
* @example
|
|
*
|
|
* // using a compiled template
|
|
* var compiled = _.template('hello <%= name %>');
|
|
* compiled({ 'name': 'moe' });
|
|
* // => 'hello moe'
|
|
*
|
|
* var list = '<% _.forEach(people, function(name) { %><li><%= name %></li><% }); %>';
|
|
* _.template(list, { 'people': ['moe', 'larry'] });
|
|
* // => '<li>moe</li><li>larry</li>'
|
|
*
|
|
* // using the "escape" delimiter to escape HTML in data property values
|
|
* _.template('<b><%- value %></b>', { 'value': '<script>' });
|
|
* // => '<b><script></b>'
|
|
*
|
|
* // using the ES6 delimiter as an alternative to the default "interpolate" delimiter
|
|
* _.template('hello ${ name }', { 'name': 'curly' });
|
|
* // => 'hello curly'
|
|
*
|
|
* // using the internal `print` function in "evaluate" delimiters
|
|
* _.template('<% print("hello " + epithet); %>!', { 'epithet': 'stooge' });
|
|
* // => 'hello stooge!'
|
|
*
|
|
* // using custom template delimiters
|
|
* _.templateSettings = {
|
|
* 'interpolate': /{{([\s\S]+?)}}/g
|
|
* };
|
|
*
|
|
* _.template('hello {{ name }}!', { 'name': 'mustache' });
|
|
* // => 'hello mustache!'
|
|
*
|
|
* // using the `sourceURL` option to specify a custom sourceURL for the template
|
|
* var compiled = _.template('hello <%= name %>', null, { 'sourceURL': '/basic/greeting.jst' });
|
|
* compiled(data);
|
|
* // => find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector
|
|
*
|
|
* // using the `variable` option to ensure a with-statement isn't used in the compiled template
|
|
* var compiled = _.template('hi <%= data.name %>!', null, { 'variable': 'data' });
|
|
* compiled.source;
|
|
* // => function(data) {
|
|
* var __t, __p = '', __e = _.escape;
|
|
* __p += 'hi ' + ((__t = ( data.name )) == null ? '' : __t) + '!';
|
|
* return __p;
|
|
* }
|
|
*
|
|
* // using the `source` property to inline compiled templates for meaningful
|
|
* // line numbers in error messages and a stack trace
|
|
* fs.writeFileSync(path.join(cwd, 'jst.js'), '\
|
|
* var JST = {\
|
|
* "main": ' + _.template(mainText).source + '\
|
|
* };\
|
|
* ');
|
|
*/
|
|
function template(text, data, options) {
|
|
// based on John Resig's `tmpl` implementation
|
|
// http://ejohn.org/blog/javascript-micro-templating/
|
|
// and Laura Doktorova's doT.js
|
|
// https://github.com/olado/doT
|
|
var settings = lodash.templateSettings;
|
|
text || (text = '');
|
|
|
|
// avoid missing dependencies when `iteratorTemplate` is not defined
|
|
options = defaults({}, options, settings);
|
|
|
|
var imports = defaults({}, options.imports, settings.imports),
|
|
importsKeys = keys(imports),
|
|
importsValues = values(imports);
|
|
|
|
var isEvaluating,
|
|
index = 0,
|
|
interpolate = options.interpolate || reNoMatch,
|
|
source = "__p += '";
|
|
|
|
// compile the regexp to match each delimiter
|
|
var reDelimiters = RegExp(
|
|
(options.escape || reNoMatch).source + '|' +
|
|
interpolate.source + '|' +
|
|
(interpolate === reInterpolate ? reEsTemplate : reNoMatch).source + '|' +
|
|
(options.evaluate || reNoMatch).source + '|$'
|
|
, 'g');
|
|
|
|
text.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
|
|
interpolateValue || (interpolateValue = esTemplateValue);
|
|
|
|
// escape characters that cannot be included in string literals
|
|
source += text.slice(index, offset).replace(reUnescapedString, escapeStringChar);
|
|
|
|
// replace delimiters with snippets
|
|
if (escapeValue) {
|
|
source += "' +\n__e(" + escapeValue + ") +\n'";
|
|
}
|
|
if (evaluateValue) {
|
|
isEvaluating = true;
|
|
source += "';\n" + evaluateValue + ";\n__p += '";
|
|
}
|
|
if (interpolateValue) {
|
|
source += "' +\n((__t = (" + interpolateValue + ")) == null ? '' : __t) +\n'";
|
|
}
|
|
index = offset + match.length;
|
|
|
|
// the JS engine embedded in Adobe products requires returning the `match`
|
|
// string in order to produce the correct `offset` value
|
|
return match;
|
|
});
|
|
|
|
source += "';\n";
|
|
|
|
// if `variable` is not specified, wrap a with-statement around the generated
|
|
// code to add the data object to the top of the scope chain
|
|
var variable = options.variable,
|
|
hasVariable = variable;
|
|
|
|
if (!hasVariable) {
|
|
variable = 'obj';
|
|
source = 'with (' + variable + ') {\n' + source + '\n}\n';
|
|
}
|
|
// cleanup code by stripping empty strings
|
|
source = (isEvaluating ? source.replace(reEmptyStringLeading, '') : source)
|
|
.replace(reEmptyStringMiddle, '$1')
|
|
.replace(reEmptyStringTrailing, '$1;');
|
|
|
|
// frame code as the function body
|
|
source = 'function(' + variable + ') {\n' +
|
|
(hasVariable ? '' : variable + ' || (' + variable + ' = {});\n') +
|
|
"var __t, __p = '', __e = _.escape" +
|
|
(isEvaluating
|
|
? ', __j = Array.prototype.join;\n' +
|
|
"function print() { __p += __j.call(arguments, '') }\n"
|
|
: ';\n'
|
|
) +
|
|
source +
|
|
'return __p\n}';
|
|
|
|
// Use a sourceURL for easier debugging and wrap in a multi-line comment to
|
|
// avoid issues with Narwhal, IE conditional compilation, and the JS engine
|
|
// embedded in Adobe products.
|
|
// http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
|
|
var sourceURL = '\n/*\n//@ sourceURL=' + (options.sourceURL || '/lodash/template/source[' + (templateCounter++) + ']') + '\n*/';
|
|
|
|
try {
|
|
var result = Function(importsKeys, 'return ' + source + sourceURL).apply(undefined, importsValues);
|
|
} catch(e) {
|
|
e.source = source;
|
|
throw e;
|
|
}
|
|
if (data) {
|
|
return result(data);
|
|
}
|
|
// provide the compiled function's source via its `toString` method, in
|
|
// supported environments, or the `source` property as a convenience for
|
|
// inlining compiled templates during the build process
|
|
result.source = source;
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* Executes the `callback` function `n` times, returning an array of the results
|
|
* of each `callback` execution. The `callback` is bound to `thisArg` and invoked
|
|
* with one argument; (index).
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {Number} n The number of times to execute the callback.
|
|
* @param {Function} callback The function called per iteration.
|
|
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
|
* @returns {Array} Returns a new array of the results of each `callback` execution.
|
|
* @example
|
|
*
|
|
* var diceRolls = _.times(3, _.partial(_.random, 1, 6));
|
|
* // => [3, 6, 4]
|
|
*
|
|
* _.times(3, function(n) { mage.castSpell(n); });
|
|
* // => calls `mage.castSpell(n)` three times, passing `n` of `0`, `1`, and `2` respectively
|
|
*
|
|
* _.times(3, function(n) { this.cast(n); }, mage);
|
|
* // => also calls `mage.castSpell(n)` three times
|
|
*/
|
|
function times(n, callback, thisArg) {
|
|
n = (n = +n) > -1 ? n : 0;
|
|
var index = -1,
|
|
result = Array(n);
|
|
|
|
callback = lodash.createCallback(callback, thisArg, 1);
|
|
while (++index < n) {
|
|
result[index] = callback(index);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* The inverse of `_.escape`, this method converts the HTML entities
|
|
* `&`, `<`, `>`, `"`, and `'` in `string` to their
|
|
* corresponding characters.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {String} string The string to unescape.
|
|
* @returns {String} Returns the unescaped string.
|
|
* @example
|
|
*
|
|
* _.unescape('Moe, Larry & Curly');
|
|
* // => 'Moe, Larry & Curly'
|
|
*/
|
|
function unescape(string) {
|
|
return string == null ? '' : String(string).replace(reEscapedHtml, unescapeHtmlChar);
|
|
}
|
|
|
|
/**
|
|
* Generates a unique ID. If `prefix` is passed, the ID will be appended to it.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Utilities
|
|
* @param {String} [prefix] The value to prefix the ID with.
|
|
* @returns {String} Returns the unique ID.
|
|
* @example
|
|
*
|
|
* _.uniqueId('contact_');
|
|
* // => 'contact_104'
|
|
*
|
|
* _.uniqueId();
|
|
* // => '105'
|
|
*/
|
|
function uniqueId(prefix) {
|
|
var id = ++idCounter;
|
|
return String(prefix == null ? '' : prefix) + id;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* Invokes `interceptor` with the `value` as the first argument, and then
|
|
* returns `value`. The purpose of this method is to "tap into" a method chain,
|
|
* in order to perform operations on intermediate results within the chain.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @category Chaining
|
|
* @param {Mixed} value The value to pass to `interceptor`.
|
|
* @param {Function} interceptor The function to invoke.
|
|
* @returns {Mixed} Returns `value`.
|
|
* @example
|
|
*
|
|
* _([1, 2, 3, 4])
|
|
* .filter(function(num) { return num % 2 == 0; })
|
|
* .tap(alert)
|
|
* .map(function(num) { return num * num; })
|
|
* .value();
|
|
* // => // [2, 4] (alerted)
|
|
* // => [4, 16]
|
|
*/
|
|
function tap(value, interceptor) {
|
|
interceptor(value);
|
|
return value;
|
|
}
|
|
|
|
/**
|
|
* Produces the `toString` result of the wrapped value.
|
|
*
|
|
* @name toString
|
|
* @memberOf _
|
|
* @category Chaining
|
|
* @returns {String} Returns the string result.
|
|
* @example
|
|
*
|
|
* _([1, 2, 3]).toString();
|
|
* // => '1,2,3'
|
|
*/
|
|
function wrapperToString() {
|
|
return String(this.__wrapped__);
|
|
}
|
|
|
|
/**
|
|
* Extracts the wrapped value.
|
|
*
|
|
* @name valueOf
|
|
* @memberOf _
|
|
* @alias value
|
|
* @category Chaining
|
|
* @returns {Mixed} Returns the wrapped value.
|
|
* @example
|
|
*
|
|
* _([1, 2, 3]).valueOf();
|
|
* // => [1, 2, 3]
|
|
*/
|
|
function wrapperValueOf() {
|
|
return this.__wrapped__;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
// add functions that return wrapped values when chaining
|
|
lodash.after = after;
|
|
lodash.assign = assign;
|
|
lodash.at = at;
|
|
lodash.bind = bind;
|
|
lodash.bindAll = bindAll;
|
|
lodash.bindKey = bindKey;
|
|
lodash.compact = compact;
|
|
lodash.compose = compose;
|
|
lodash.countBy = countBy;
|
|
lodash.createCallback = createCallback;
|
|
lodash.debounce = debounce;
|
|
lodash.defaults = defaults;
|
|
lodash.defer = defer;
|
|
lodash.delay = delay;
|
|
lodash.difference = difference;
|
|
lodash.filter = filter;
|
|
lodash.flatten = flatten;
|
|
lodash.forEach = forEach;
|
|
lodash.forIn = forIn;
|
|
lodash.forOwn = forOwn;
|
|
lodash.functions = functions;
|
|
lodash.groupBy = groupBy;
|
|
lodash.initial = initial;
|
|
lodash.intersection = intersection;
|
|
lodash.invert = invert;
|
|
lodash.invoke = invoke;
|
|
lodash.keys = keys;
|
|
lodash.map = map;
|
|
lodash.max = max;
|
|
lodash.memoize = memoize;
|
|
lodash.merge = merge;
|
|
lodash.min = min;
|
|
lodash.omit = omit;
|
|
lodash.once = once;
|
|
lodash.pairs = pairs;
|
|
lodash.partial = partial;
|
|
lodash.partialRight = partialRight;
|
|
lodash.pick = pick;
|
|
lodash.pluck = pluck;
|
|
lodash.range = range;
|
|
lodash.reject = reject;
|
|
lodash.rest = rest;
|
|
lodash.shuffle = shuffle;
|
|
lodash.sortBy = sortBy;
|
|
lodash.tap = tap;
|
|
lodash.throttle = throttle;
|
|
lodash.times = times;
|
|
lodash.toArray = toArray;
|
|
lodash.transform = transform;
|
|
lodash.union = union;
|
|
lodash.uniq = uniq;
|
|
lodash.unzip = unzip;
|
|
lodash.values = values;
|
|
lodash.where = where;
|
|
lodash.without = without;
|
|
lodash.wrap = wrap;
|
|
lodash.zip = zip;
|
|
lodash.zipObject = zipObject;
|
|
|
|
// add aliases
|
|
lodash.collect = map;
|
|
lodash.drop = rest;
|
|
lodash.each = forEach;
|
|
lodash.extend = assign;
|
|
lodash.methods = functions;
|
|
lodash.object = zipObject;
|
|
lodash.select = filter;
|
|
lodash.tail = rest;
|
|
lodash.unique = uniq;
|
|
|
|
// add functions to `lodash.prototype`
|
|
mixin(lodash);
|
|
|
|
// add Underscore compat
|
|
lodash.chain = lodash;
|
|
lodash.prototype.chain = function() { return this; };
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
// add functions that return unwrapped values when chaining
|
|
lodash.clone = clone;
|
|
lodash.cloneDeep = cloneDeep;
|
|
lodash.contains = contains;
|
|
lodash.escape = escape;
|
|
lodash.every = every;
|
|
lodash.find = find;
|
|
lodash.findIndex = findIndex;
|
|
lodash.findKey = findKey;
|
|
lodash.has = has;
|
|
lodash.identity = identity;
|
|
lodash.indexOf = indexOf;
|
|
lodash.isArguments = isArguments;
|
|
lodash.isArray = isArray;
|
|
lodash.isBoolean = isBoolean;
|
|
lodash.isDate = isDate;
|
|
lodash.isElement = isElement;
|
|
lodash.isEmpty = isEmpty;
|
|
lodash.isEqual = isEqual;
|
|
lodash.isFinite = isFinite;
|
|
lodash.isFunction = isFunction;
|
|
lodash.isNaN = isNaN;
|
|
lodash.isNull = isNull;
|
|
lodash.isNumber = isNumber;
|
|
lodash.isObject = isObject;
|
|
lodash.isPlainObject = isPlainObject;
|
|
lodash.isRegExp = isRegExp;
|
|
lodash.isString = isString;
|
|
lodash.isUndefined = isUndefined;
|
|
lodash.lastIndexOf = lastIndexOf;
|
|
lodash.mixin = mixin;
|
|
lodash.noConflict = noConflict;
|
|
lodash.parseInt = parseInt;
|
|
lodash.random = random;
|
|
lodash.reduce = reduce;
|
|
lodash.reduceRight = reduceRight;
|
|
lodash.result = result;
|
|
lodash.runInContext = runInContext;
|
|
lodash.size = size;
|
|
lodash.some = some;
|
|
lodash.sortedIndex = sortedIndex;
|
|
lodash.template = template;
|
|
lodash.unescape = unescape;
|
|
lodash.uniqueId = uniqueId;
|
|
|
|
// add aliases
|
|
lodash.all = every;
|
|
lodash.any = some;
|
|
lodash.detect = find;
|
|
lodash.findWhere = find;
|
|
lodash.foldl = reduce;
|
|
lodash.foldr = reduceRight;
|
|
lodash.include = contains;
|
|
lodash.inject = reduce;
|
|
|
|
forOwn(lodash, function(func, methodName) {
|
|
if (!lodash.prototype[methodName]) {
|
|
lodash.prototype[methodName] = function() {
|
|
var args = [this.__wrapped__];
|
|
push.apply(args, arguments);
|
|
return func.apply(lodash, args);
|
|
};
|
|
}
|
|
});
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
// add functions capable of returning wrapped and unwrapped values when chaining
|
|
lodash.first = first;
|
|
lodash.last = last;
|
|
|
|
// add aliases
|
|
lodash.take = first;
|
|
lodash.head = first;
|
|
|
|
forOwn(lodash, function(func, methodName) {
|
|
if (!lodash.prototype[methodName]) {
|
|
lodash.prototype[methodName]= function(callback, thisArg) {
|
|
var result = func(this.__wrapped__, callback, thisArg);
|
|
return callback == null || (thisArg && typeof callback != 'function')
|
|
? result
|
|
: new lodashWrapper(result);
|
|
};
|
|
}
|
|
});
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* The semantic version number.
|
|
*
|
|
* @static
|
|
* @memberOf _
|
|
* @type String
|
|
*/
|
|
lodash.VERSION = '1.3.1';
|
|
|
|
// add "Chaining" functions to the wrapper
|
|
lodash.prototype.toString = wrapperToString;
|
|
lodash.prototype.value = wrapperValueOf;
|
|
lodash.prototype.valueOf = wrapperValueOf;
|
|
|
|
// add `Array` functions that return unwrapped values
|
|
forEach(['join', 'pop', 'shift'], function(methodName) {
|
|
var func = arrayRef[methodName];
|
|
lodash.prototype[methodName] = function() {
|
|
return func.apply(this.__wrapped__, arguments);
|
|
};
|
|
});
|
|
|
|
// add `Array` functions that return the wrapped value
|
|
forEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
|
|
var func = arrayRef[methodName];
|
|
lodash.prototype[methodName] = function() {
|
|
func.apply(this.__wrapped__, arguments);
|
|
return this;
|
|
};
|
|
});
|
|
|
|
// add `Array` functions that return new wrapped values
|
|
forEach(['concat', 'slice', 'splice'], function(methodName) {
|
|
var func = arrayRef[methodName];
|
|
lodash.prototype[methodName] = function() {
|
|
return new lodashWrapper(func.apply(this.__wrapped__, arguments));
|
|
};
|
|
});
|
|
|
|
return lodash;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
// expose Lo-Dash
|
|
var _ = runInContext();
|
|
|
|
// some AMD build optimizers, like r.js, check for specific condition patterns like the following:
|
|
if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
|
|
// Expose Lo-Dash to the global object even when an AMD loader is present in
|
|
// case Lo-Dash was injected by a third-party script and not intended to be
|
|
// loaded as a module. The global assignment can be reverted in the Lo-Dash
|
|
// module via its `noConflict()` method.
|
|
window._ = _;
|
|
|
|
// define as an anonymous module so, through path mapping, it can be
|
|
// referenced as the "underscore" module
|
|
define(function() {
|
|
return _;
|
|
});
|
|
}
|
|
// check for `exports` after `define` in case a build optimizer adds an `exports` object
|
|
else if (freeExports && !freeExports.nodeType) {
|
|
// in Node.js or RingoJS v0.8.0+
|
|
if (freeModule) {
|
|
(freeModule.exports = _)._ = _;
|
|
}
|
|
// in Narwhal or RingoJS v0.7.0-
|
|
else {
|
|
freeExports._ = _;
|
|
}
|
|
}
|
|
else {
|
|
// in a browser or Rhino
|
|
window._ = _;
|
|
}
|
|
}(this));
|
|
|
|
}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
|
},{}],39:[function(_dereq_,module,exports){
|
|
module.exports={
|
|
"name": "amqp",
|
|
"description": "AMQP driver for node",
|
|
"keywords": [
|
|
"amqp"
|
|
],
|
|
"version": "0.2.0",
|
|
"author": {
|
|
"name": "Ryan Dahl"
|
|
},
|
|
"contributors": [
|
|
{
|
|
"name": "Vasili Sviridov"
|
|
},
|
|
{
|
|
"name": "Theo Schlossnagle"
|
|
},
|
|
{
|
|
"name": "Vincent Desjardins"
|
|
},
|
|
{
|
|
"name": "Liang-Chi Hsieh"
|
|
},
|
|
{
|
|
"name": "Tim Baga"
|
|
},
|
|
{
|
|
"name": "Stéphane Alnet"
|
|
},
|
|
{
|
|
"name": "Alen Mujezinovic"
|
|
},
|
|
{
|
|
"name": "Michael Bridgen"
|
|
},
|
|
{
|
|
"name": "Chris Bond"
|
|
},
|
|
{
|
|
"name": "Andrei Vereha"
|
|
},
|
|
{
|
|
"name": "Mike Bardzinski"
|
|
},
|
|
{
|
|
"name": "James Carr"
|
|
},
|
|
{
|
|
"name": "David Barshow"
|
|
},
|
|
{
|
|
"name": "Jason Pincin"
|
|
},
|
|
{
|
|
"name": "Carl Hörberg"
|
|
}
|
|
],
|
|
"repository": {
|
|
"type": "git",
|
|
"url": "git://github.com/postwait/node-amqp.git"
|
|
},
|
|
"bugs": {
|
|
"url": "http://github.com/postwait/node-amqp/issues"
|
|
},
|
|
"main": "./amqp",
|
|
"engines": {
|
|
"node": "0.4 || 0.6 || 0.8 || 0.9 || 0.10 || 0.11"
|
|
},
|
|
"licenses": [
|
|
{
|
|
"type": "MIT",
|
|
"url": "http://github.com/postwait/node-amqp/raw/master/LICENSE-MIT"
|
|
}
|
|
],
|
|
"dependencies": {
|
|
"lodash": "~1.3.1"
|
|
},
|
|
"devDependencies": {
|
|
"optimist": "~0.6.0",
|
|
"longjohn": "~0.2.1"
|
|
},
|
|
"scripts": {
|
|
"test": "make test"
|
|
},
|
|
"_id": "amqp@0.2.0",
|
|
"dist": {
|
|
"shasum": "caed3d5a1ef5f419663f80dcf6e95312e5fca2ca",
|
|
"tarball": "http://registry.npmjs.org/amqp/-/amqp-0.2.0.tgz"
|
|
},
|
|
"_from": "amqp@^0.2.0",
|
|
"_npmVersion": "1.2.18",
|
|
"_npmUser": {
|
|
"name": "postwait",
|
|
"email": "jesus@omniti.com"
|
|
},
|
|
"maintainers": [
|
|
{
|
|
"name": "ry",
|
|
"email": "ry@tinyclouds.org"
|
|
},
|
|
{
|
|
"name": "postwait",
|
|
"email": "jesus@omniti.com"
|
|
}
|
|
],
|
|
"directories": {},
|
|
"_shasum": "caed3d5a1ef5f419663f80dcf6e95312e5fca2ca",
|
|
"_resolved": "https://registry.npmjs.org/amqp/-/amqp-0.2.0.tgz",
|
|
"readme": "ERROR: No README data found!",
|
|
"homepage": "https://github.com/postwait/node-amqp"
|
|
}
|
|
|
|
},{}],40:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
module.exports = _dereq_('./lib/babble');
|
|
|
|
},{"./lib/babble":43}],41:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var uuid = _dereq_('node-uuid');
|
|
var Promise = _dereq_('es6-promise').Promise;
|
|
|
|
var messagebus = _dereq_('./messagebus');
|
|
var Conversation = _dereq_('./Conversation');
|
|
var Block = _dereq_('./block/Block');
|
|
var Then = _dereq_('./block/Then');
|
|
var Tell = _dereq_('./block/Tell');
|
|
var Listen = _dereq_('./block/Listen');
|
|
|
|
_dereq_('./block/IIf'); // append iif function to Block
|
|
|
|
/**
|
|
* Babbler
|
|
* @param {String} id
|
|
* @constructor
|
|
*/
|
|
function Babbler (id) {
|
|
if (!(this instanceof Babbler)) {
|
|
throw new SyntaxError('Constructor must be called with the new operator');
|
|
}
|
|
|
|
if (!id) {
|
|
throw new Error('id required');
|
|
}
|
|
|
|
this.id = id;
|
|
this.listeners = []; // Array.<Listen>
|
|
this.conversations = {}; // Array.<Array.<Conversation>> all open conversations
|
|
|
|
this.connect(); // automatically connect to the local message bus
|
|
}
|
|
|
|
/**
|
|
* Connect to a message bus
|
|
* @param {{connect: function, disconnect: function, send: function}} [bus]
|
|
* A messaging interface. Must have the following functions:
|
|
* - connect(params: {id: string,
|
|
* message: function, callback: function}) : string
|
|
* must return a token to disconnects again.
|
|
* parameter callback is optional.
|
|
* - disconnect(token: string)
|
|
* disconnect from a message bus.
|
|
* - send(id: string, message: *)
|
|
* send a message
|
|
* A number of interfaces is provided under babble.messagebus.
|
|
* Default interface is babble.messagebus['default']
|
|
* @return {Promise.<Babbler>} Returns a Promise which resolves when the
|
|
* babbler is connected.
|
|
*/
|
|
Babbler.prototype.connect = function (bus) {
|
|
// disconnect (in case we are already connected)
|
|
this.disconnect();
|
|
|
|
if (!bus) {
|
|
bus = messagebus['default']();
|
|
}
|
|
|
|
// validate the message bus functions
|
|
if (typeof bus.connect !== 'function') {
|
|
throw new Error('message bus must contain a function ' +
|
|
'connect(params: {id: string, callback: function}) : string');
|
|
}
|
|
if (typeof bus.disconnect !== 'function') {
|
|
throw new Error('message bus must contain a function ' +
|
|
'disconnect(token: string)');
|
|
}
|
|
if (typeof bus.send !== 'function') {
|
|
throw new Error('message bus must contain a function ' +
|
|
'send(params: {id: string, message: *})');
|
|
}
|
|
|
|
// we return a promise, but we run the message.connect function immediately
|
|
// (outside of the Promise), so that synchronous connects are done without
|
|
// the need to await the promise to resolve on the next tick.
|
|
var _resolve = null;
|
|
var connected = new Promise(function (resolve, reject) {
|
|
_resolve = resolve;
|
|
});
|
|
|
|
var token = bus.connect({
|
|
id: this.id,
|
|
message: this._receive.bind(this),
|
|
callback: _resolve
|
|
});
|
|
|
|
// link functions to disconnect and send
|
|
this.disconnect = function () {
|
|
bus.disconnect(token);
|
|
};
|
|
this.send = bus.send;
|
|
|
|
// return a promise
|
|
return connected;
|
|
};
|
|
|
|
/**
|
|
* Handle an incoming message
|
|
* @param {{id: string, from: string, to: string, message: string}} envelope
|
|
* @private
|
|
*/
|
|
Babbler.prototype._receive = function (envelope) {
|
|
// ignore when envelope does not contain an id and message
|
|
if (!envelope || !('id' in envelope) || !('message' in envelope)) {
|
|
return;
|
|
}
|
|
|
|
// console.log('_receive', envelope) // TODO: cleanup
|
|
|
|
var me = this;
|
|
var id = envelope.id;
|
|
var conversations = this.conversations[id];
|
|
if (conversations && conversations.length) {
|
|
// directly deliver to all open conversations with this id
|
|
conversations.forEach(function (conversation) {
|
|
conversation.deliver(envelope);
|
|
})
|
|
}
|
|
else {
|
|
// start new conversations at each of the listeners
|
|
if (!conversations) {
|
|
conversations = [];
|
|
}
|
|
this.conversations[id] = conversations;
|
|
|
|
this.listeners.forEach(function (block) {
|
|
// create a new conversation
|
|
var conversation = new Conversation({
|
|
id: id,
|
|
self: me.id,
|
|
other: envelope.from,
|
|
context: {
|
|
from: envelope.from
|
|
},
|
|
send: me.send
|
|
});
|
|
|
|
// append this conversation to the list with conversations
|
|
conversations.push(conversation);
|
|
|
|
// deliver the first message to the new conversation
|
|
conversation.deliver(envelope);
|
|
|
|
// process the conversation
|
|
return me._process(block, conversation)
|
|
.then(function() {
|
|
// remove the conversation from the list again
|
|
var index = conversations.indexOf(conversation);
|
|
if (index !== -1) {
|
|
conversations.splice(index, 1);
|
|
}
|
|
if (conversations.length === 0) {
|
|
delete me.conversations[id];
|
|
}
|
|
});
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Disconnect from the babblebox
|
|
*/
|
|
Babbler.prototype.disconnect = function () {
|
|
// by default, do nothing. The disconnect function will be overwritten
|
|
// when the Babbler is connected to a message bus.
|
|
};
|
|
|
|
/**
|
|
* Send a message
|
|
* @param {String} to Id of a babbler
|
|
* @param {*} message Any message. Message must be a stringifiable JSON object.
|
|
*/
|
|
Babbler.prototype.send = function (to, message) {
|
|
// send is overridden when running connect
|
|
throw new Error('Cannot send: not connected');
|
|
};
|
|
|
|
/**
|
|
* Listen for a specific event
|
|
*
|
|
* Providing a condition will only start the flow when condition is met,
|
|
* this is equivalent of doing `listen().iif(condition)`
|
|
*
|
|
* Providing a callback function is equivalent of doing either
|
|
* `listen(message).then(callback)` or `listen().iif(message).then(callback)`.
|
|
*
|
|
* @param {function | RegExp | String | *} [condition]
|
|
* @param {Function} [callback] Invoked as callback(message, context),
|
|
* where `message` is the just received message,
|
|
* and `context` is an object where state can be
|
|
* stored during a conversation. This is equivalent
|
|
* of doing `listen().then(callback)`
|
|
* @return {Block} block Start block of a control flow.
|
|
*/
|
|
Babbler.prototype.listen = function (condition, callback) {
|
|
var listen = new Listen();
|
|
this.listeners.push(listen);
|
|
|
|
var block = listen;
|
|
if (condition) {
|
|
block = block.iif(condition);
|
|
}
|
|
if (callback) {
|
|
block = block.then(callback);
|
|
}
|
|
return block;
|
|
};
|
|
|
|
/**
|
|
* Listen for a specific event, and execute the flow once.
|
|
*
|
|
* Providing a condition will only start the flow when condition is met,
|
|
* this is equivalent of doing `listen().iif(condition)`
|
|
*
|
|
* Providing a callback function is equivalent of doing either
|
|
* `listen(message).then(callback)` or `listen().iif(message).then(callback)`.
|
|
*
|
|
* @param {function | RegExp | String | *} [condition]
|
|
* @param {Function} [callback] Invoked as callback(message, context),
|
|
* where `message` is the just received message,
|
|
* and `context` is an object where state can be
|
|
* stored during a conversation. This is equivalent
|
|
* of doing `listen().then(callback)`
|
|
* @return {Block} block Start block of a control flow.
|
|
*/
|
|
Babbler.prototype.listenOnce = function (condition, callback) {
|
|
var listen = new Listen();
|
|
this.listeners.push(listen);
|
|
|
|
var me = this;
|
|
var block = listen;
|
|
|
|
if (condition) {
|
|
block = block.iif(condition);
|
|
}
|
|
|
|
block = block.then(function (message) {
|
|
// remove the flow from the listeners after fired once
|
|
var index = me.listeners.indexOf(listen);
|
|
if (index !== -1) {
|
|
me.listeners.splice(index, 1);
|
|
}
|
|
return message;
|
|
});
|
|
|
|
if (callback) {
|
|
block = block.then(callback);
|
|
}
|
|
|
|
return block;
|
|
};
|
|
|
|
/**
|
|
* Send a message to the other peer
|
|
* Creates a block Tell, and runs the block immediately.
|
|
* @param {String} to Babbler id
|
|
* @param {Function | *} message
|
|
* @return {Block} block Last block in the created control flow
|
|
*/
|
|
Babbler.prototype.tell = function (to, message) {
|
|
var me = this;
|
|
var cid = uuid.v4(); // create an id for this conversation
|
|
|
|
// create a new conversation
|
|
var conversation = new Conversation({
|
|
id: cid,
|
|
self: this.id,
|
|
other: to,
|
|
context: {
|
|
from: to
|
|
},
|
|
send: me.send
|
|
});
|
|
this.conversations[cid] = [conversation];
|
|
|
|
var block = new Tell(message);
|
|
|
|
// run the Tell block on the next tick, when the conversation flow is created
|
|
setTimeout(function () {
|
|
me._process(block, conversation)
|
|
.then(function () {
|
|
// cleanup the conversation
|
|
delete me.conversations[cid];
|
|
})
|
|
}, 0);
|
|
|
|
return block;
|
|
};
|
|
|
|
/**
|
|
* Send a question, listen for a response.
|
|
* Creates two blocks: Tell and Listen, and runs them immediately.
|
|
* This is equivalent of doing `Babbler.tell(to, message).listen(callback)`
|
|
* @param {String} to Babbler id
|
|
* @param {* | Function} message A message or a callback returning a message.
|
|
* @param {Function} [callback] Invoked as callback(message, context),
|
|
* where `message` is the just received message,
|
|
* and `context` is an object where state can be
|
|
* stored during a conversation. This is equivalent
|
|
* of doing `listen().then(callback)`
|
|
* @return {Block} block Last block in the created control flow
|
|
*/
|
|
Babbler.prototype.ask = function (to, message, callback) {
|
|
return this
|
|
.tell(to, message)
|
|
.listen(callback);
|
|
};
|
|
|
|
/**
|
|
* Process a flow starting with `block`, given a conversation
|
|
* @param {Block} block
|
|
* @param {Conversation} conversation
|
|
* @return {Promise.<Conversation>} Resolves when the conversation is finished
|
|
* @private
|
|
*/
|
|
Babbler.prototype._process = function (block, conversation) {
|
|
return new Promise(function (resolve, reject) {
|
|
/**
|
|
* Process a block, given the conversation and a message which is chained
|
|
* from block to block.
|
|
* @param {Block} block
|
|
* @param {*} [message]
|
|
*/
|
|
function process(block, message) {
|
|
//console.log('process', conversation.self, conversation.id, block.constructor.name, message) // TODO: cleanup
|
|
|
|
block.execute(conversation, message)
|
|
.then(function (next) {
|
|
if (next.block) {
|
|
// recursively evaluate the next block in the conversation flow
|
|
process(next.block, next.result);
|
|
}
|
|
else {
|
|
// we are done, this is the end of the conversation
|
|
resolve(conversation);
|
|
}
|
|
});
|
|
}
|
|
|
|
// process the first block
|
|
process(block);
|
|
});
|
|
};
|
|
|
|
module.exports = Babbler;
|
|
|
|
},{"./Conversation":42,"./block/Block":44,"./block/IIf":46,"./block/Listen":47,"./block/Tell":48,"./block/Then":49,"./messagebus":50,"es6-promise":52,"node-uuid":113}],42:[function(_dereq_,module,exports){
|
|
var uuid = _dereq_('node-uuid');
|
|
var Promise = _dereq_('es6-promise').Promise;
|
|
|
|
/**
|
|
* A conversation
|
|
* Holds meta data for a conversation between two peers
|
|
* @param {Object} [config] Configuration options:
|
|
* {string} [id] A unique id for the conversation. If not provided, a uuid is generated
|
|
* {string} self Id of the peer on this side of the conversation
|
|
* {string} other Id of the peer on the other side of the conversation
|
|
* {Object} [context] Context passed with all callbacks of the conversation
|
|
* {function(to: string, message: *): Promise} send Function to send a message
|
|
* @constructor
|
|
*/
|
|
function Conversation (config) {
|
|
if (!(this instanceof Conversation)) {
|
|
throw new SyntaxError('Constructor must be called with the new operator');
|
|
}
|
|
|
|
// public properties
|
|
this.id = config && config.id || uuid.v4();
|
|
this.self = config && config.self || null;
|
|
this.other = config && config.other || null;
|
|
this.context = config && config.context || {};
|
|
|
|
// private properties
|
|
this._send = config && config.send || null;
|
|
this._inbox = []; // queue with received but not yet picked messages
|
|
this._receivers = []; // queue with handlers waiting for a new message
|
|
}
|
|
|
|
/**
|
|
* Send a message
|
|
* @param {*} message
|
|
* @return {Promise.<null>} Resolves when the message has been sent
|
|
*/
|
|
Conversation.prototype.send = function (message) {
|
|
return this._send(this.other, {
|
|
id: this.id,
|
|
from: this.self,
|
|
to: this.other,
|
|
message: message
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Deliver a message
|
|
* @param {{id: string, from: string, to: string, message: string}} envelope
|
|
*/
|
|
Conversation.prototype.deliver = function (envelope) {
|
|
if (this._receivers.length) {
|
|
var receiver = this._receivers.shift();
|
|
receiver(envelope.message);
|
|
}
|
|
else {
|
|
this._inbox.push(envelope.message);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Receive a message.
|
|
* @returns {Promise.<*>} Resolves with a message as soon as a message
|
|
* is delivered.
|
|
*/
|
|
Conversation.prototype.receive = function () {
|
|
var me = this;
|
|
|
|
if (this._inbox.length) {
|
|
return Promise.resolve(this._inbox.shift());
|
|
}
|
|
else {
|
|
return new Promise(function (resolve) {
|
|
me._receivers.push(resolve);
|
|
})
|
|
}
|
|
};
|
|
|
|
module.exports = Conversation;
|
|
|
|
},{"es6-promise":52,"node-uuid":113}],43:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Babbler = _dereq_('./Babbler');
|
|
|
|
var Tell = _dereq_('./block/Tell');
|
|
var Listen = _dereq_('./block/Listen');
|
|
var Then = _dereq_('./block/Then');
|
|
var Decision = _dereq_('./block/Decision');
|
|
var IIf = _dereq_('./block/IIf');
|
|
|
|
/**
|
|
* Create a new babbler
|
|
* @param {String} id
|
|
* @return {Babbler} babbler
|
|
*/
|
|
exports.babbler = function (id) {
|
|
return new Babbler(id);
|
|
};
|
|
|
|
/**
|
|
* Create a control flow starting with a tell block
|
|
* @param {* | Function} [message] A static message or callback function
|
|
* returning a message dynamically.
|
|
* When `message` is a function, it will be
|
|
* invoked as callback(message, context),
|
|
* where `message` is the output from the
|
|
* previous block in the chain, and `context` is
|
|
* an object where state can be stored during a
|
|
* conversation.
|
|
* @return {Tell} tell
|
|
*/
|
|
exports.tell = function (message) {
|
|
return new Tell(message);
|
|
};
|
|
|
|
/**
|
|
* Send a question, listen for a response.
|
|
* Creates two blocks: Tell and Listen.
|
|
* This is equivalent of doing `babble.tell(message).listen(callback)`
|
|
* @param {* | Function} message
|
|
* @param {Function} [callback] Invoked as callback(message, context),
|
|
* where `message` is the just received message,
|
|
* and `context` is an object where state can be
|
|
* stored during a conversation. This is equivalent
|
|
* of doing `listen().then(callback)`
|
|
* @return {Block} block Last block in the created control flow
|
|
*/
|
|
exports.ask = function (message, callback) {
|
|
return exports
|
|
.tell(message)
|
|
.listen(callback);
|
|
};
|
|
|
|
/**
|
|
* Create a decision block and chain it to the current block.
|
|
*
|
|
* Syntax:
|
|
*
|
|
* decide(choices)
|
|
* decide(decision, choices)
|
|
*
|
|
* Where:
|
|
*
|
|
* {Function | Object} [decision]
|
|
* When a `decision` function is provided, the
|
|
* function is invoked as decision(message, context),
|
|
* where `message` is the output from the previous
|
|
* block in the chain, and `context` is an object
|
|
* where state can be stored during a conversation.
|
|
* The function must return the id for the next
|
|
* block in the control flow, which must be
|
|
* available in the provided `choices`.
|
|
* If `decision` is not provided, the next block
|
|
* will be mapped directly from the message.
|
|
* {Object.<String, Block>} choices
|
|
* A map with the possible next blocks in the flow
|
|
* The next block is selected by the id returned
|
|
* by the decision function.
|
|
*
|
|
* There is one special id for choices: 'default'. This id is called when either
|
|
* the decision function returns an id which does not match any of the available
|
|
* choices.
|
|
*
|
|
* @param {Function | Object} arg1 Can be {function} decision or {Object} choices
|
|
* @param {Object} [arg2] choices
|
|
* @return {Block} decision The created decision block
|
|
*/
|
|
exports.decide = function (arg1, arg2) {
|
|
// TODO: test arguments.length > 2
|
|
return new Decision(arg1, arg2);
|
|
};
|
|
|
|
/**
|
|
* Listen for a message.
|
|
*
|
|
* Optionally a callback function can be provided, which is equivalent of
|
|
* doing `listen().then(callback)`.
|
|
*
|
|
* @param {Function} [callback] Invoked as callback(message, context),
|
|
* where `message` is the just received message,
|
|
* and `context` is an object where state can be
|
|
* stored during a conversation. This is equivalent
|
|
* of doing `listen().then(callback)`
|
|
* @return {Block} Returns the created Listen block
|
|
*/
|
|
exports.listen = function(callback) {
|
|
var block = new Listen();
|
|
if (callback) {
|
|
return block.then(callback);
|
|
}
|
|
return block;
|
|
};
|
|
|
|
/**
|
|
* Create a control flow starting with a Then block
|
|
* @param {Function} callback Invoked as callback(message, context),
|
|
* where `message` is the output from the previous
|
|
* block in the chain, and `context` is an object
|
|
* where state can be stored during a conversation.
|
|
* @return {Then} then
|
|
*/
|
|
exports.then = function (callback) {
|
|
return new Then(callback);
|
|
};
|
|
|
|
/**
|
|
* IIf
|
|
* Create an iif block, which checks a condition and continues either with
|
|
* the trueBlock or the falseBlock. The input message is passed to the next
|
|
* block in the flow.
|
|
*
|
|
* Can be used as follows:
|
|
* - When `condition` evaluates true:
|
|
* - when `trueBlock` is provided, the flow continues with `trueBlock`
|
|
* - else, when there is a block connected to the IIf block, the flow continues
|
|
* with that block.
|
|
* - When `condition` evaluates false:
|
|
* - when `falseBlock` is provided, the flow continues with `falseBlock`
|
|
*
|
|
* Syntax:
|
|
*
|
|
* new IIf(condition, trueBlock)
|
|
* new IIf(condition, trueBlock [, falseBlock])
|
|
* new IIf(condition).then(...)
|
|
*
|
|
* @param {Function | RegExp | *} condition A condition returning true or false
|
|
* In case of a function,
|
|
* the function is invoked as
|
|
* `condition(message, context)` and
|
|
* must return a boolean. In case of
|
|
* a RegExp, condition will be tested
|
|
* to return true. In other cases,
|
|
* non-strict equality is tested on
|
|
* the input.
|
|
* @param {Block} [trueBlock]
|
|
* @param {Block} [falseBlock]
|
|
* @returns {Block}
|
|
*/
|
|
exports.iif = function (condition, trueBlock, falseBlock) {
|
|
return new IIf(condition, trueBlock, falseBlock);
|
|
};
|
|
|
|
// export the babbler prototype
|
|
exports.Babbler = Babbler;
|
|
|
|
// export all flow blocks
|
|
exports.block = {
|
|
Block: _dereq_('./block/Block'),
|
|
Then: _dereq_('./block/Then'),
|
|
Decision: _dereq_('./block/Decision'),
|
|
IIf: _dereq_('./block/IIf'),
|
|
Listen: _dereq_('./block/Listen'),
|
|
Tell: _dereq_('./block/Tell')
|
|
};
|
|
|
|
// export messagebus interfaces
|
|
exports.messagebus = _dereq_('./messagebus');
|
|
|
|
/**
|
|
* Babblify an actor. The babblified actor will be extended with functions
|
|
* `ask`, `tell`, and `listen`.
|
|
*
|
|
* Babble expects that messages sent via `actor.send(to, message)` will be
|
|
* delivered by the recipient on a function `actor.receive(from, message)`.
|
|
* Babble replaces the original `receive` with a new one, which is used to
|
|
* listen for all incoming messages. Messages ignored by babble are propagated
|
|
* to the original `receive` function.
|
|
*
|
|
* The actor can be restored in its original state using `unbabblify(actor)`.
|
|
*
|
|
* @param {Object} actor The actor to be babblified. Must be an object
|
|
* containing functions `send(to, message)` and
|
|
* `receive(from, message)`.
|
|
* @param {Object} [params] Optional parameters. Can contain properties:
|
|
* - id: string The id for the babbler
|
|
* - send: string The name of an alternative
|
|
* send function available on
|
|
* the actor.
|
|
* - receive: string The name of an alternative
|
|
* receive function available
|
|
* on the actor.
|
|
* @returns {Object} Returns the babblified actor.
|
|
*/
|
|
exports.babblify = function (actor, params) {
|
|
var babblerId;
|
|
if (params && params.id !== undefined) {
|
|
babblerId = params.id;
|
|
}
|
|
else if (actor.id !== undefined) {
|
|
babblerId = actor.id
|
|
}
|
|
else {
|
|
throw new Error('Id missing. Ensure that either actor has a property "id", ' +
|
|
'or provide an id as a property in second argument params')
|
|
}
|
|
|
|
// validate actor
|
|
['ask', 'tell', 'listen'].forEach(function (prop) {
|
|
if (actor[prop] !== undefined) {
|
|
throw new Error('Conflict: actor already has a property "' + prop + '"');
|
|
}
|
|
});
|
|
|
|
var sendName = params && params.send || 'send';
|
|
if (typeof actor[sendName] !== 'function') {
|
|
throw new Error('Missing function. ' +
|
|
'Function "' + sendName + '(to, message)" expected on actor or on params');
|
|
}
|
|
|
|
// create a new babbler
|
|
var babbler = exports.babbler(babblerId);
|
|
|
|
// attach receive function to the babbler
|
|
var receiveName = params && params.receive || 'receive';
|
|
var receiveOriginal = actor.hasOwnProperty(receiveName) ? actor[receiveName] : null;
|
|
if (receiveOriginal) {
|
|
actor[receiveName] = function (from, message) {
|
|
babbler._receive(message);
|
|
receiveOriginal.call(actor, from, message);
|
|
};
|
|
}
|
|
else {
|
|
actor[receiveName] = function (from, message) {
|
|
babbler._receive(message);
|
|
};
|
|
}
|
|
|
|
// attach send function to the babbler
|
|
babbler.send = function (to, message) {
|
|
// FIXME: there should be no need to send a message on next tick
|
|
setTimeout(function () {
|
|
actor[sendName](to, message)
|
|
}, 0)
|
|
};
|
|
|
|
// attach babbler functions and properties to the actor
|
|
actor.__babbler__ = {
|
|
babbler: babbler,
|
|
receive: receiveOriginal,
|
|
receiveName: receiveName
|
|
};
|
|
actor.ask = babbler.ask.bind(babbler);
|
|
actor.tell = babbler.tell.bind(babbler);
|
|
actor.listen = babbler.listen.bind(babbler);
|
|
actor.listenOnce = babbler.listenOnce.bind(babbler);
|
|
|
|
return actor;
|
|
};
|
|
|
|
/**
|
|
* Unbabblify an actor.
|
|
* @param {Object} actor
|
|
* @return {Object} Returns the unbabblified actor.
|
|
*/
|
|
exports.unbabblify = function (actor) {
|
|
var __babbler__ = actor.__babbler__;
|
|
if (__babbler__) {
|
|
delete actor.__babbler__;
|
|
delete actor.ask;
|
|
delete actor.tell;
|
|
delete actor.listen;
|
|
delete actor.listenOnce;
|
|
delete actor[__babbler__.receiveName];
|
|
|
|
// restore any original receive method
|
|
if (__babbler__.receive) {
|
|
actor[__babbler__.receiveName] = __babbler__.receive;
|
|
}
|
|
}
|
|
|
|
return actor;
|
|
};
|
|
|
|
},{"./Babbler":41,"./block/Block":44,"./block/Decision":45,"./block/IIf":46,"./block/Listen":47,"./block/Tell":48,"./block/Then":49,"./messagebus":50}],44:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
/**
|
|
* Abstract control flow diagram block
|
|
* @constructor
|
|
*/
|
|
function Block() {
|
|
this.next = null;
|
|
this.previous = null;
|
|
}
|
|
|
|
/**
|
|
* Execute the block
|
|
* @param {Conversation} conversation
|
|
* @param {*} message
|
|
* @return {Promise.<{result: *, block: Block}, Error>} next
|
|
*/
|
|
Block.prototype.execute = function (conversation, message) {
|
|
throw new Error('Cannot run an abstract Block');
|
|
};
|
|
|
|
module.exports = Block;
|
|
|
|
},{}],45:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Promise = _dereq_('es6-promise').Promise;
|
|
var Block = _dereq_('./Block');
|
|
var isPromise =_dereq_('../util').isPromise;
|
|
|
|
_dereq_('./Then'); // extend Block with function then
|
|
|
|
/**
|
|
* Decision
|
|
* A decision is made by executing the provided callback function, which returns
|
|
* a next control flow block.
|
|
*
|
|
* Syntax:
|
|
*
|
|
* new Decision(choices)
|
|
* new Decision(decision, choices)
|
|
*
|
|
* Where:
|
|
*
|
|
* {Function | Object} [decision]
|
|
* When a `decision` function is provided, the
|
|
* function is invoked as decision(message, context),
|
|
* where `message` is the output from the previous
|
|
* block in the chain, and `context` is an object
|
|
* where state can be stored during a conversation.
|
|
* The function must return the id for the next
|
|
* block in the control flow, which must be
|
|
* available in the provided `choices`.
|
|
* If `decision` is not provided, the next block
|
|
* will be mapped directly from the message.
|
|
* {Object.<String, Block>} choices
|
|
* A map with the possible next blocks in the flow
|
|
* The next block is selected by the id returned
|
|
* by the decision function.
|
|
*
|
|
* There is one special id for choices: 'default'. This id is called when either
|
|
* the decision function returns an id which does not match any of the available
|
|
* choices.
|
|
*
|
|
* @param arg1
|
|
* @param arg2
|
|
* @constructor
|
|
* @extends {Block}
|
|
*/
|
|
function Decision (arg1, arg2) {
|
|
var decision, choices;
|
|
|
|
if (!(this instanceof Decision)) {
|
|
throw new SyntaxError('Constructor must be called with the new operator');
|
|
}
|
|
|
|
if (typeof arg1 === 'function') {
|
|
decision = arg1;
|
|
choices = arg2;
|
|
}
|
|
else {
|
|
decision = null;
|
|
choices = arg1;
|
|
}
|
|
|
|
if (decision) {
|
|
if (typeof decision !== 'function') {
|
|
throw new TypeError('Parameter decision must be a function');
|
|
}
|
|
}
|
|
else {
|
|
decision = function (message, context) {
|
|
return message;
|
|
}
|
|
}
|
|
|
|
if (choices && (choices instanceof Function)) {
|
|
throw new TypeError('Parameter choices must be an object');
|
|
}
|
|
|
|
this.decision = decision;
|
|
this.choices = {};
|
|
|
|
// append all choices
|
|
if (choices) {
|
|
var me = this;
|
|
Object.keys(choices).forEach(function (id) {
|
|
me.addChoice(id, choices[id]);
|
|
});
|
|
}
|
|
}
|
|
|
|
Decision.prototype = Object.create(Block.prototype);
|
|
Decision.prototype.constructor = Decision;
|
|
|
|
/**
|
|
* Execute the block
|
|
* @param {Conversation} conversation
|
|
* @param {*} message
|
|
* @return {Promise.<{result: *, block: Block}, Error>} next
|
|
*/
|
|
Decision.prototype.execute = function (conversation, message) {
|
|
var me = this;
|
|
var id = this.decision(message, conversation.context);
|
|
|
|
var resolve = isPromise(id) ? id : Promise.resolve(id);
|
|
return resolve.then(function (id) {
|
|
var next = me.choices[id];
|
|
|
|
if (!next) {
|
|
// there is no match, fall back on the default choice
|
|
next = me.choices['default'];
|
|
}
|
|
|
|
if (!next) {
|
|
throw new Error('Block with id "' + id + '" not found');
|
|
}
|
|
|
|
return {
|
|
result: message,
|
|
block: next
|
|
};
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Add a choice to the decision block.
|
|
* The choice can be a new chain of blocks. The first block of the chain
|
|
* will be triggered when the this id comes out of the decision function.
|
|
* @param {String | 'default'} id
|
|
* @param {Block} block
|
|
* @return {Decision} self
|
|
*/
|
|
Decision.prototype.addChoice = function (id, block) {
|
|
if (typeof id !== 'string') {
|
|
throw new TypeError('String expected as choice id');
|
|
}
|
|
|
|
if (!(block instanceof Block)) {
|
|
throw new TypeError('Block expected as choice');
|
|
}
|
|
|
|
if (id in this.choices) {
|
|
throw new Error('Choice with id "' + id + '" already exists');
|
|
}
|
|
|
|
// find the first block of the chain
|
|
var first = block;
|
|
while (first && first.previous) {
|
|
first = first.previous;
|
|
}
|
|
|
|
this.choices[id] = first;
|
|
|
|
return this;
|
|
};
|
|
|
|
/**
|
|
* Create a decision block and chain it to the current block.
|
|
* Returns the first block in the chain.
|
|
*
|
|
* Syntax:
|
|
*
|
|
* decide(choices)
|
|
* decide(decision, choices)
|
|
*
|
|
* Where:
|
|
*
|
|
* {Function | Object} [decision]
|
|
* When a `decision` function is provided, the
|
|
* function is invoked as decision(message, context),
|
|
* where `message` is the output from the previous
|
|
* block in the chain, and `context` is an object
|
|
* where state can be stored during a conversation.
|
|
* The function must return the id for the next
|
|
* block in the control flow, which must be
|
|
* available in the provided `choices`.
|
|
* If `decision` is not provided, the next block
|
|
* will be mapped directly from the message.
|
|
* {Object.<String, Block>} choices
|
|
* A map with the possible next blocks in the flow
|
|
* The next block is selected by the id returned
|
|
* by the decision function.
|
|
*
|
|
* There is one special id for choices: 'default'. This id is called when either
|
|
* the decision function returns an id which does not match any of the available
|
|
* choices.
|
|
*
|
|
* @param {Function | Object} arg1 Can be {function} decision or {Object} choices
|
|
* @param {Object} [arg2] choices
|
|
* @return {Block} first First block in the chain
|
|
*/
|
|
Block.prototype.decide = function (arg1, arg2) {
|
|
var decision = new Decision(arg1, arg2);
|
|
|
|
return this.then(decision);
|
|
};
|
|
|
|
module.exports = Decision;
|
|
|
|
},{"../util":51,"./Block":44,"./Then":49,"es6-promise":52}],46:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Promise = _dereq_('es6-promise').Promise;
|
|
var Block = _dereq_('./Block');
|
|
var isPromise = _dereq_('../util').isPromise;
|
|
|
|
_dereq_('./Then'); // extend Block with function then
|
|
|
|
/**
|
|
* IIf
|
|
* Create an iif block, which checks a condition and continues either with
|
|
* the trueBlock or the falseBlock. The input message is passed to the next
|
|
* block in the flow.
|
|
*
|
|
* Can be used as follows:
|
|
* - When `condition` evaluates true:
|
|
* - when `trueBlock` is provided, the flow continues with `trueBlock`
|
|
* - else, when there is a block connected to the IIf block, the flow continues
|
|
* with that block.
|
|
* - When `condition` evaluates false:
|
|
* - when `falseBlock` is provided, the flow continues with `falseBlock`
|
|
*
|
|
* Syntax:
|
|
*
|
|
* new IIf(condition, trueBlock)
|
|
* new IIf(condition, trueBlock [, falseBlock])
|
|
* new IIf(condition).then(...)
|
|
*
|
|
* @param {Function | RegExp | *} condition A condition returning true or false
|
|
* In case of a function,
|
|
* the function is invoked as
|
|
* `condition(message, context)` and
|
|
* must return a boolean. In case of
|
|
* a RegExp, condition will be tested
|
|
* to return true. In other cases,
|
|
* non-strict equality is tested on
|
|
* the input.
|
|
* @param {Block} [trueBlock]
|
|
* @param {Block} [falseBlock]
|
|
* @constructor
|
|
* @extends {Block}
|
|
*/
|
|
function IIf (condition, trueBlock, falseBlock) {
|
|
if (!(this instanceof IIf)) {
|
|
throw new SyntaxError('Constructor must be called with the new operator');
|
|
}
|
|
|
|
if (condition instanceof Function) {
|
|
this.condition = condition;
|
|
}
|
|
else if (condition instanceof RegExp) {
|
|
this.condition = function (message, context) {
|
|
return condition.test(message);
|
|
}
|
|
}
|
|
else {
|
|
this.condition = function (message, context) {
|
|
return message == condition;
|
|
}
|
|
}
|
|
|
|
if (trueBlock && !(trueBlock instanceof Block)) {
|
|
throw new TypeError('Parameter trueBlock must be a Block');
|
|
}
|
|
|
|
if (falseBlock && !(falseBlock instanceof Block)) {
|
|
throw new TypeError('Parameter falseBlock must be a Block');
|
|
}
|
|
|
|
this.trueBlock = trueBlock || null;
|
|
this.falseBlock = falseBlock || null;
|
|
}
|
|
|
|
IIf.prototype = Object.create(Block.prototype);
|
|
IIf.prototype.constructor = IIf;
|
|
|
|
/**
|
|
* Execute the block
|
|
* @param {Conversation} conversation
|
|
* @param {*} message
|
|
* @return {Promise.<{result: *, block: Block}, Error>} next
|
|
*/
|
|
IIf.prototype.execute = function (conversation, message) {
|
|
var me = this;
|
|
var condition = this.condition(message, conversation.context);
|
|
|
|
var resolve = isPromise(condition) ? condition : Promise.resolve(condition);
|
|
|
|
return resolve.then(function (condition) {
|
|
var next = condition ? (me.trueBlock || me.next) : me.falseBlock;
|
|
|
|
return {
|
|
result: message,
|
|
block: next
|
|
};
|
|
});
|
|
};
|
|
|
|
/**
|
|
* IIf
|
|
* Create an iif block, which checks a condition and continues either with
|
|
* the trueBlock or the falseBlock. The input message is passed to the next
|
|
* block in the flow.
|
|
*
|
|
* Can be used as follows:
|
|
* - When `condition` evaluates true:
|
|
* - when `trueBlock` is provided, the flow continues with `trueBlock`
|
|
* - else, when there is a block connected to the IIf block, the flow continues
|
|
* with that block.
|
|
* - When `condition` evaluates false:
|
|
* - when `falseBlock` is provided, the flow continues with `falseBlock`
|
|
*
|
|
* Syntax:
|
|
*
|
|
* new IIf(condition, trueBlock)
|
|
* new IIf(condition, trueBlock [, falseBlock])
|
|
* new IIf(condition).then(...)
|
|
*
|
|
* @param {Function | RegExp | *} condition A condition returning true or false
|
|
* In case of a function,
|
|
* the function is invoked as
|
|
* `condition(message, context)` and
|
|
* must return a boolean. In case of
|
|
* a RegExp, condition will be tested
|
|
* to return true. In other cases,
|
|
* non-strict equality is tested on
|
|
* the input.
|
|
* @param {Block} [trueBlock]
|
|
* @param {Block} [falseBlock]
|
|
* @returns {Block} Returns the created IIf block
|
|
*/
|
|
Block.prototype.iif = function (condition, trueBlock, falseBlock) {
|
|
var iif = new IIf(condition, trueBlock, falseBlock);
|
|
|
|
return this.then(iif);
|
|
};
|
|
|
|
module.exports = IIf;
|
|
|
|
},{"../util":51,"./Block":44,"./Then":49,"es6-promise":52}],47:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Promise = _dereq_('es6-promise').Promise;
|
|
var Block = _dereq_('./Block');
|
|
var Then = _dereq_('./Then');
|
|
|
|
/**
|
|
* Listen
|
|
* Wait until a message comes in from the connected peer, then continue
|
|
* with the next block in the control flow.
|
|
*
|
|
* @constructor
|
|
* @extends {Block}
|
|
*/
|
|
function Listen () {
|
|
if (!(this instanceof Listen)) {
|
|
throw new SyntaxError('Constructor must be called with the new operator');
|
|
}
|
|
}
|
|
|
|
Listen.prototype = Object.create(Block.prototype);
|
|
Listen.prototype.constructor = Listen;
|
|
|
|
/**
|
|
* Execute the block
|
|
* @param {Conversation} conversation
|
|
* @param {*} [message] Message is ignored by Listen blocks
|
|
* @return {Promise.<{result: *, block: Block}, Error>} next
|
|
*/
|
|
Listen.prototype.execute = function (conversation, message) {
|
|
var me = this;
|
|
|
|
// wait until a message is received
|
|
return conversation.receive()
|
|
.then(function (message) {
|
|
return {
|
|
result: message,
|
|
block: me.next
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Create a Listen block and chain it to the current block
|
|
*
|
|
* Optionally a callback function can be provided, which is equivalent of
|
|
* doing `listen().then(callback)`.
|
|
*
|
|
* @param {Function} [callback] Executed as callback(message: *, context: Object)
|
|
* Must return a result
|
|
* @return {Block} Returns the appended block
|
|
*/
|
|
Block.prototype.listen = function (callback) {
|
|
var listen = new Listen();
|
|
var block = this.then(listen);
|
|
if (callback) {
|
|
block = block.then(callback);
|
|
}
|
|
return block;
|
|
};
|
|
|
|
module.exports = Listen;
|
|
|
|
},{"./Block":44,"./Then":49,"es6-promise":52}],48:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Promise = _dereq_('es6-promise').Promise;
|
|
var Block = _dereq_('./Block');
|
|
var isPromise = _dereq_('../util').isPromise;
|
|
|
|
_dereq_('./Then'); // extend Block with function then
|
|
_dereq_('./Listen'); // extend Block with function listen
|
|
|
|
/**
|
|
* Tell
|
|
* Send a message to the other peer.
|
|
* @param {* | Function} message A static message or callback function
|
|
* returning a message dynamically.
|
|
* When `message` is a function, it will be
|
|
* invoked as callback(message, context),
|
|
* where `message` is the output from the
|
|
* previous block in the chain, and `context` is
|
|
* an object where state can be stored during a
|
|
* conversation.
|
|
* @constructor
|
|
* @extends {Block}
|
|
*/
|
|
function Tell (message) {
|
|
if (!(this instanceof Tell)) {
|
|
throw new SyntaxError('Constructor must be called with the new operator');
|
|
}
|
|
|
|
this.message = message;
|
|
}
|
|
|
|
Tell.prototype = Object.create(Block.prototype);
|
|
Tell.prototype.constructor = Tell;
|
|
|
|
/**
|
|
* Execute the block
|
|
* @param {Conversation} conversation
|
|
* @param {*} [message] A message is ignored by the Tell block
|
|
* @return {Promise.<{result: *, block: Block}, Error>} next
|
|
*/
|
|
Tell.prototype.execute = function (conversation, message) {
|
|
// resolve the message
|
|
var me = this;
|
|
var resolve;
|
|
if (typeof this.message === 'function') {
|
|
var result = this.message(message, conversation.context);
|
|
resolve = isPromise(result) ? result : Promise.resolve(result);
|
|
}
|
|
else {
|
|
resolve = Promise.resolve(this.message); // static string or value
|
|
}
|
|
|
|
return resolve
|
|
.then(function (result) {
|
|
var res = conversation.send(result);
|
|
var done = isPromise(res) ? res : Promise.resolve(res);
|
|
|
|
return done.then(function () {
|
|
return {
|
|
result: result,
|
|
block: me.next
|
|
};
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Create a Tell block and chain it to the current block
|
|
* @param {* | Function} [message] A static message or callback function
|
|
* returning a message dynamically.
|
|
* When `message` is a function, it will be
|
|
* invoked as callback(message, context),
|
|
* where `message` is the output from the
|
|
* previous block in the chain, and `context` is
|
|
* an object where state can be stored during a
|
|
* conversation.
|
|
* @return {Block} Returns the appended block
|
|
*/
|
|
Block.prototype.tell = function (message) {
|
|
var block = new Tell(message);
|
|
|
|
return this.then(block);
|
|
};
|
|
|
|
/**
|
|
* Send a question, listen for a response.
|
|
* Creates two blocks: Tell and Listen.
|
|
* This is equivalent of doing `babble.tell(message).listen(callback)`
|
|
* @param {* | Function} message
|
|
* @param {Function} [callback] Invoked as callback(message, context),
|
|
* where `message` is the just received message,
|
|
* and `context` is an object where state can be
|
|
* stored during a conversation. This is equivalent
|
|
* of doing `listen().then(callback)`
|
|
* @return {Block} Returns the appended block
|
|
*/
|
|
Block.prototype.ask = function (message, callback) {
|
|
// FIXME: this doesn't work
|
|
return this
|
|
.tell(message)
|
|
.listen(callback);
|
|
};
|
|
|
|
module.exports = Tell;
|
|
|
|
},{"../util":51,"./Block":44,"./Listen":47,"./Then":49,"es6-promise":52}],49:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Promise = _dereq_('es6-promise').Promise;
|
|
var Block = _dereq_('./Block');
|
|
var isPromise = _dereq_('../util').isPromise;
|
|
|
|
/**
|
|
* Then
|
|
* Execute a callback function or a next block in the chain.
|
|
* @param {Function} callback Invoked as callback(message, context),
|
|
* where `message` is the output from the previous
|
|
* block in the chain, and `context` is an object
|
|
* where state can be stored during a conversation.
|
|
* @constructor
|
|
* @extends {Block}
|
|
*/
|
|
function Then (callback) {
|
|
if (!(this instanceof Then)) {
|
|
throw new SyntaxError('Constructor must be called with the new operator');
|
|
}
|
|
|
|
if (!(typeof callback === 'function')) {
|
|
throw new TypeError('Parameter callback must be a Function');
|
|
}
|
|
|
|
this.callback = callback;
|
|
}
|
|
|
|
Then.prototype = Object.create(Block.prototype);
|
|
Then.prototype.constructor = Then;
|
|
|
|
/**
|
|
* Execute the block
|
|
* @param {Conversation} conversation
|
|
* @param {*} message
|
|
* @return {Promise.<{result: *, block: Block}, Error>} next
|
|
*/
|
|
Then.prototype.execute = function (conversation, message) {
|
|
var me = this;
|
|
var result = this.callback(message, conversation.context);
|
|
|
|
var resolve = isPromise(result) ? result : Promise.resolve(result);
|
|
|
|
return resolve.then(function (result) {
|
|
return {
|
|
result: result,
|
|
block: me.next
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Chain a block to the current block.
|
|
*
|
|
* When a function is provided, a Then block will be generated which
|
|
* executes the function. The function is invoked as callback(message, context),
|
|
* where `message` is the output from the previous block in the chain,
|
|
* and `context` is an object where state can be stored during a conversation.
|
|
*
|
|
* @param {Block | function} next A callback function or Block.
|
|
* @return {Block} Returns the appended block
|
|
*/
|
|
Block.prototype.then = function (next) {
|
|
// turn a callback function into a Then block
|
|
if (typeof next === 'function') {
|
|
next = new Then(next);
|
|
}
|
|
|
|
if (!(next instanceof Block)) {
|
|
throw new TypeError('Parameter next must be a Block or function');
|
|
}
|
|
|
|
// append after the last block
|
|
next.previous = this;
|
|
this.next = next;
|
|
|
|
// return the appended block
|
|
return next;
|
|
};
|
|
|
|
module.exports = Then;
|
|
|
|
},{"../util":51,"./Block":44,"es6-promise":52}],50:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Promise = _dereq_('es6-promise').Promise;
|
|
|
|
// built-in messaging interfaces
|
|
|
|
/**
|
|
* pubsub-js messaging interface
|
|
* @returns {{connect: function, disconnect: function, send: function}}
|
|
*/
|
|
exports['pubsub-js'] = function () {
|
|
var PubSub = _dereq_('pubsub-js');
|
|
|
|
return {
|
|
connect: function (params) {
|
|
var token = PubSub.subscribe(params.id, function (id, message) {
|
|
params.message(message);
|
|
});
|
|
|
|
if (typeof params.callback === 'function') {
|
|
params.callback();
|
|
}
|
|
|
|
return token;
|
|
},
|
|
|
|
disconnect: function(token) {
|
|
PubSub.unsubscribe(token);
|
|
},
|
|
|
|
send: function (to, message) {
|
|
PubSub.publish(to, message);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* // pubnub messaging interface
|
|
* @param {{publish_key: string, subscribe_key: string}} params
|
|
* @returns {{connect: function, disconnect: function, send: function}}
|
|
*/
|
|
exports['pubnub'] = function (params) {
|
|
var PUBNUB;
|
|
if (typeof window !== 'undefined') {
|
|
// browser
|
|
if (typeof window['PUBNUB'] === 'undefined') {
|
|
throw new Error('Please load pubnub first in the browser');
|
|
}
|
|
PUBNUB = window['PUBNUB'];
|
|
}
|
|
else {
|
|
// node.js
|
|
PUBNUB = _dereq_('pubnub');
|
|
}
|
|
|
|
var pubnub = PUBNUB.init(params);
|
|
|
|
return {
|
|
connect: function (params) {
|
|
pubnub.subscribe({
|
|
channel: params.id,
|
|
message: params.message,
|
|
connect: params.callback
|
|
});
|
|
|
|
return params.id;
|
|
},
|
|
|
|
disconnect: function (id) {
|
|
pubnub.unsubscribe(id);
|
|
},
|
|
|
|
send: function (to, message) {
|
|
return new Promise(function (resolve, reject) {
|
|
pubnub.publish({
|
|
channel: to,
|
|
message: message,
|
|
callback: resolve
|
|
});
|
|
})
|
|
}
|
|
}
|
|
};
|
|
|
|
// default interface
|
|
exports['default'] = exports['pubsub-js'];
|
|
|
|
},{"es6-promise":52,"pubnub":65,"pubsub-js":66}],51:[function(_dereq_,module,exports){
|
|
/**
|
|
* Test whether the provided value is a Promise.
|
|
* A value is marked as a Promise when it is an object containing functions
|
|
* `then` and `catch`.
|
|
* @param {*} value
|
|
* @return {boolean} Returns true when `value` is a Promise
|
|
*/
|
|
exports.isPromise = function (value) {
|
|
return value &&
|
|
typeof value['then'] === 'function' &&
|
|
typeof value['catch'] === 'function'
|
|
};
|
|
|
|
},{}],52:[function(_dereq_,module,exports){
|
|
"use strict";
|
|
var Promise = _dereq_("./promise/promise").Promise;
|
|
var polyfill = _dereq_("./promise/polyfill").polyfill;
|
|
exports.Promise = Promise;
|
|
exports.polyfill = polyfill;
|
|
},{"./promise/polyfill":56,"./promise/promise":57}],53:[function(_dereq_,module,exports){
|
|
"use strict";
|
|
/* global toString */
|
|
|
|
var isArray = _dereq_("./utils").isArray;
|
|
var isFunction = _dereq_("./utils").isFunction;
|
|
|
|
/**
|
|
Returns a promise that is fulfilled when all the given promises have been
|
|
fulfilled, or rejected if any of them become rejected. The return promise
|
|
is fulfilled with an array that gives all the values in the order they were
|
|
passed in the `promises` array argument.
|
|
|
|
Example:
|
|
|
|
```javascript
|
|
var promise1 = RSVP.resolve(1);
|
|
var promise2 = RSVP.resolve(2);
|
|
var promise3 = RSVP.resolve(3);
|
|
var promises = [ promise1, promise2, promise3 ];
|
|
|
|
RSVP.all(promises).then(function(array){
|
|
// The array here would be [ 1, 2, 3 ];
|
|
});
|
|
```
|
|
|
|
If any of the `promises` given to `RSVP.all` are rejected, the first promise
|
|
that is rejected will be given as an argument to the returned promises's
|
|
rejection handler. For example:
|
|
|
|
Example:
|
|
|
|
```javascript
|
|
var promise1 = RSVP.resolve(1);
|
|
var promise2 = RSVP.reject(new Error("2"));
|
|
var promise3 = RSVP.reject(new Error("3"));
|
|
var promises = [ promise1, promise2, promise3 ];
|
|
|
|
RSVP.all(promises).then(function(array){
|
|
// Code here never runs because there are rejected promises!
|
|
}, function(error) {
|
|
// error.message === "2"
|
|
});
|
|
```
|
|
|
|
@method all
|
|
@for RSVP
|
|
@param {Array} promises
|
|
@param {String} label
|
|
@return {Promise} promise that is fulfilled when all `promises` have been
|
|
fulfilled, or rejected if any of them become rejected.
|
|
*/
|
|
function all(promises) {
|
|
/*jshint validthis:true */
|
|
var Promise = this;
|
|
|
|
if (!isArray(promises)) {
|
|
throw new TypeError('You must pass an array to all.');
|
|
}
|
|
|
|
return new Promise(function(resolve, reject) {
|
|
var results = [], remaining = promises.length,
|
|
promise;
|
|
|
|
if (remaining === 0) {
|
|
resolve([]);
|
|
}
|
|
|
|
function resolver(index) {
|
|
return function(value) {
|
|
resolveAll(index, value);
|
|
};
|
|
}
|
|
|
|
function resolveAll(index, value) {
|
|
results[index] = value;
|
|
if (--remaining === 0) {
|
|
resolve(results);
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < promises.length; i++) {
|
|
promise = promises[i];
|
|
|
|
if (promise && isFunction(promise.then)) {
|
|
promise.then(resolver(i), reject);
|
|
} else {
|
|
resolveAll(i, promise);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
exports.all = all;
|
|
},{"./utils":61}],54:[function(_dereq_,module,exports){
|
|
(function (process,global){
|
|
"use strict";
|
|
var browserGlobal = (typeof window !== 'undefined') ? window : {};
|
|
var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
|
|
var local = (typeof global !== 'undefined') ? global : (this === undefined? window:this);
|
|
|
|
// node
|
|
function useNextTick() {
|
|
return function() {
|
|
process.nextTick(flush);
|
|
};
|
|
}
|
|
|
|
function useMutationObserver() {
|
|
var iterations = 0;
|
|
var observer = new BrowserMutationObserver(flush);
|
|
var node = document.createTextNode('');
|
|
observer.observe(node, { characterData: true });
|
|
|
|
return function() {
|
|
node.data = (iterations = ++iterations % 2);
|
|
};
|
|
}
|
|
|
|
function useSetTimeout() {
|
|
return function() {
|
|
local.setTimeout(flush, 1);
|
|
};
|
|
}
|
|
|
|
var queue = [];
|
|
function flush() {
|
|
for (var i = 0; i < queue.length; i++) {
|
|
var tuple = queue[i];
|
|
var callback = tuple[0], arg = tuple[1];
|
|
callback(arg);
|
|
}
|
|
queue = [];
|
|
}
|
|
|
|
var scheduleFlush;
|
|
|
|
// Decide what async method to use to triggering processing of queued callbacks:
|
|
if (typeof process !== 'undefined' && {}.toString.call(process) === '[object process]') {
|
|
scheduleFlush = useNextTick();
|
|
} else if (BrowserMutationObserver) {
|
|
scheduleFlush = useMutationObserver();
|
|
} else {
|
|
scheduleFlush = useSetTimeout();
|
|
}
|
|
|
|
function asap(callback, arg) {
|
|
var length = queue.push([callback, arg]);
|
|
if (length === 1) {
|
|
// If length is 1, that means that we need to schedule an async flush.
|
|
// If additional callbacks are queued before the queue is flushed, they
|
|
// will be processed by this flush that we are scheduling.
|
|
scheduleFlush();
|
|
}
|
|
}
|
|
|
|
exports.asap = asap;
|
|
}).call(this,_dereq_("C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
|
},{"C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":144}],55:[function(_dereq_,module,exports){
|
|
"use strict";
|
|
var config = {
|
|
instrument: false
|
|
};
|
|
|
|
function configure(name, value) {
|
|
if (arguments.length === 2) {
|
|
config[name] = value;
|
|
} else {
|
|
return config[name];
|
|
}
|
|
}
|
|
|
|
exports.config = config;
|
|
exports.configure = configure;
|
|
},{}],56:[function(_dereq_,module,exports){
|
|
(function (global){
|
|
"use strict";
|
|
/*global self*/
|
|
var RSVPPromise = _dereq_("./promise").Promise;
|
|
var isFunction = _dereq_("./utils").isFunction;
|
|
|
|
function polyfill() {
|
|
var local;
|
|
|
|
if (typeof global !== 'undefined') {
|
|
local = global;
|
|
} else if (typeof window !== 'undefined' && window.document) {
|
|
local = window;
|
|
} else {
|
|
local = self;
|
|
}
|
|
|
|
var es6PromiseSupport =
|
|
"Promise" in local &&
|
|
// Some of these methods are missing from
|
|
// Firefox/Chrome experimental implementations
|
|
"resolve" in local.Promise &&
|
|
"reject" in local.Promise &&
|
|
"all" in local.Promise &&
|
|
"race" in local.Promise &&
|
|
// Older version of the spec had a resolver object
|
|
// as the arg rather than a function
|
|
(function() {
|
|
var resolve;
|
|
new local.Promise(function(r) { resolve = r; });
|
|
return isFunction(resolve);
|
|
}());
|
|
|
|
if (!es6PromiseSupport) {
|
|
local.Promise = RSVPPromise;
|
|
}
|
|
}
|
|
|
|
exports.polyfill = polyfill;
|
|
}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
|
},{"./promise":57,"./utils":61}],57:[function(_dereq_,module,exports){
|
|
"use strict";
|
|
var config = _dereq_("./config").config;
|
|
var configure = _dereq_("./config").configure;
|
|
var objectOrFunction = _dereq_("./utils").objectOrFunction;
|
|
var isFunction = _dereq_("./utils").isFunction;
|
|
var now = _dereq_("./utils").now;
|
|
var all = _dereq_("./all").all;
|
|
var race = _dereq_("./race").race;
|
|
var staticResolve = _dereq_("./resolve").resolve;
|
|
var staticReject = _dereq_("./reject").reject;
|
|
var asap = _dereq_("./asap").asap;
|
|
|
|
var counter = 0;
|
|
|
|
config.async = asap; // default async is asap;
|
|
|
|
function Promise(resolver) {
|
|
if (!isFunction(resolver)) {
|
|
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
|
|
}
|
|
|
|
if (!(this instanceof Promise)) {
|
|
throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
|
|
}
|
|
|
|
this._subscribers = [];
|
|
|
|
invokeResolver(resolver, this);
|
|
}
|
|
|
|
function invokeResolver(resolver, promise) {
|
|
function resolvePromise(value) {
|
|
resolve(promise, value);
|
|
}
|
|
|
|
function rejectPromise(reason) {
|
|
reject(promise, reason);
|
|
}
|
|
|
|
try {
|
|
resolver(resolvePromise, rejectPromise);
|
|
} catch(e) {
|
|
rejectPromise(e);
|
|
}
|
|
}
|
|
|
|
function invokeCallback(settled, promise, callback, detail) {
|
|
var hasCallback = isFunction(callback),
|
|
value, error, succeeded, failed;
|
|
|
|
if (hasCallback) {
|
|
try {
|
|
value = callback(detail);
|
|
succeeded = true;
|
|
} catch(e) {
|
|
failed = true;
|
|
error = e;
|
|
}
|
|
} else {
|
|
value = detail;
|
|
succeeded = true;
|
|
}
|
|
|
|
if (handleThenable(promise, value)) {
|
|
return;
|
|
} else if (hasCallback && succeeded) {
|
|
resolve(promise, value);
|
|
} else if (failed) {
|
|
reject(promise, error);
|
|
} else if (settled === FULFILLED) {
|
|
resolve(promise, value);
|
|
} else if (settled === REJECTED) {
|
|
reject(promise, value);
|
|
}
|
|
}
|
|
|
|
var PENDING = void 0;
|
|
var SEALED = 0;
|
|
var FULFILLED = 1;
|
|
var REJECTED = 2;
|
|
|
|
function subscribe(parent, child, onFulfillment, onRejection) {
|
|
var subscribers = parent._subscribers;
|
|
var length = subscribers.length;
|
|
|
|
subscribers[length] = child;
|
|
subscribers[length + FULFILLED] = onFulfillment;
|
|
subscribers[length + REJECTED] = onRejection;
|
|
}
|
|
|
|
function publish(promise, settled) {
|
|
var child, callback, subscribers = promise._subscribers, detail = promise._detail;
|
|
|
|
for (var i = 0; i < subscribers.length; i += 3) {
|
|
child = subscribers[i];
|
|
callback = subscribers[i + settled];
|
|
|
|
invokeCallback(settled, child, callback, detail);
|
|
}
|
|
|
|
promise._subscribers = null;
|
|
}
|
|
|
|
Promise.prototype = {
|
|
constructor: Promise,
|
|
|
|
_state: undefined,
|
|
_detail: undefined,
|
|
_subscribers: undefined,
|
|
|
|
then: function(onFulfillment, onRejection) {
|
|
var promise = this;
|
|
|
|
var thenPromise = new this.constructor(function() {});
|
|
|
|
if (this._state) {
|
|
var callbacks = arguments;
|
|
config.async(function invokePromiseCallback() {
|
|
invokeCallback(promise._state, thenPromise, callbacks[promise._state - 1], promise._detail);
|
|
});
|
|
} else {
|
|
subscribe(this, thenPromise, onFulfillment, onRejection);
|
|
}
|
|
|
|
return thenPromise;
|
|
},
|
|
|
|
'catch': function(onRejection) {
|
|
return this.then(null, onRejection);
|
|
}
|
|
};
|
|
|
|
Promise.all = all;
|
|
Promise.race = race;
|
|
Promise.resolve = staticResolve;
|
|
Promise.reject = staticReject;
|
|
|
|
function handleThenable(promise, value) {
|
|
var then = null,
|
|
resolved;
|
|
|
|
try {
|
|
if (promise === value) {
|
|
throw new TypeError("A promises callback cannot return that same promise.");
|
|
}
|
|
|
|
if (objectOrFunction(value)) {
|
|
then = value.then;
|
|
|
|
if (isFunction(then)) {
|
|
then.call(value, function(val) {
|
|
if (resolved) { return true; }
|
|
resolved = true;
|
|
|
|
if (value !== val) {
|
|
resolve(promise, val);
|
|
} else {
|
|
fulfill(promise, val);
|
|
}
|
|
}, function(val) {
|
|
if (resolved) { return true; }
|
|
resolved = true;
|
|
|
|
reject(promise, val);
|
|
});
|
|
|
|
return true;
|
|
}
|
|
}
|
|
} catch (error) {
|
|
if (resolved) { return true; }
|
|
reject(promise, error);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
function resolve(promise, value) {
|
|
if (promise === value) {
|
|
fulfill(promise, value);
|
|
} else if (!handleThenable(promise, value)) {
|
|
fulfill(promise, value);
|
|
}
|
|
}
|
|
|
|
function fulfill(promise, value) {
|
|
if (promise._state !== PENDING) { return; }
|
|
promise._state = SEALED;
|
|
promise._detail = value;
|
|
|
|
config.async(publishFulfillment, promise);
|
|
}
|
|
|
|
function reject(promise, reason) {
|
|
if (promise._state !== PENDING) { return; }
|
|
promise._state = SEALED;
|
|
promise._detail = reason;
|
|
|
|
config.async(publishRejection, promise);
|
|
}
|
|
|
|
function publishFulfillment(promise) {
|
|
publish(promise, promise._state = FULFILLED);
|
|
}
|
|
|
|
function publishRejection(promise) {
|
|
publish(promise, promise._state = REJECTED);
|
|
}
|
|
|
|
exports.Promise = Promise;
|
|
},{"./all":53,"./asap":54,"./config":55,"./race":58,"./reject":59,"./resolve":60,"./utils":61}],58:[function(_dereq_,module,exports){
|
|
"use strict";
|
|
/* global toString */
|
|
var isArray = _dereq_("./utils").isArray;
|
|
|
|
/**
|
|
`RSVP.race` allows you to watch a series of promises and act as soon as the
|
|
first promise given to the `promises` argument fulfills or rejects.
|
|
|
|
Example:
|
|
|
|
```javascript
|
|
var promise1 = new RSVP.Promise(function(resolve, reject){
|
|
setTimeout(function(){
|
|
resolve("promise 1");
|
|
}, 200);
|
|
});
|
|
|
|
var promise2 = new RSVP.Promise(function(resolve, reject){
|
|
setTimeout(function(){
|
|
resolve("promise 2");
|
|
}, 100);
|
|
});
|
|
|
|
RSVP.race([promise1, promise2]).then(function(result){
|
|
// result === "promise 2" because it was resolved before promise1
|
|
// was resolved.
|
|
});
|
|
```
|
|
|
|
`RSVP.race` is deterministic in that only the state of the first completed
|
|
promise matters. For example, even if other promises given to the `promises`
|
|
array argument are resolved, but the first completed promise has become
|
|
rejected before the other promises became fulfilled, the returned promise
|
|
will become rejected:
|
|
|
|
```javascript
|
|
var promise1 = new RSVP.Promise(function(resolve, reject){
|
|
setTimeout(function(){
|
|
resolve("promise 1");
|
|
}, 200);
|
|
});
|
|
|
|
var promise2 = new RSVP.Promise(function(resolve, reject){
|
|
setTimeout(function(){
|
|
reject(new Error("promise 2"));
|
|
}, 100);
|
|
});
|
|
|
|
RSVP.race([promise1, promise2]).then(function(result){
|
|
// Code here never runs because there are rejected promises!
|
|
}, function(reason){
|
|
// reason.message === "promise2" because promise 2 became rejected before
|
|
// promise 1 became fulfilled
|
|
});
|
|
```
|
|
|
|
@method race
|
|
@for RSVP
|
|
@param {Array} promises array of promises to observe
|
|
@param {String} label optional string for describing the promise returned.
|
|
Useful for tooling.
|
|
@return {Promise} a promise that becomes fulfilled with the value the first
|
|
completed promises is resolved with if the first completed promise was
|
|
fulfilled, or rejected with the reason that the first completed promise
|
|
was rejected with.
|
|
*/
|
|
function race(promises) {
|
|
/*jshint validthis:true */
|
|
var Promise = this;
|
|
|
|
if (!isArray(promises)) {
|
|
throw new TypeError('You must pass an array to race.');
|
|
}
|
|
return new Promise(function(resolve, reject) {
|
|
var results = [], promise;
|
|
|
|
for (var i = 0; i < promises.length; i++) {
|
|
promise = promises[i];
|
|
|
|
if (promise && typeof promise.then === 'function') {
|
|
promise.then(resolve, reject);
|
|
} else {
|
|
resolve(promise);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
exports.race = race;
|
|
},{"./utils":61}],59:[function(_dereq_,module,exports){
|
|
"use strict";
|
|
/**
|
|
`RSVP.reject` returns a promise that will become rejected with the passed
|
|
`reason`. `RSVP.reject` is essentially shorthand for the following:
|
|
|
|
```javascript
|
|
var promise = new RSVP.Promise(function(resolve, reject){
|
|
reject(new Error('WHOOPS'));
|
|
});
|
|
|
|
promise.then(function(value){
|
|
// Code here doesn't run because the promise is rejected!
|
|
}, function(reason){
|
|
// reason.message === 'WHOOPS'
|
|
});
|
|
```
|
|
|
|
Instead of writing the above, your code now simply becomes the following:
|
|
|
|
```javascript
|
|
var promise = RSVP.reject(new Error('WHOOPS'));
|
|
|
|
promise.then(function(value){
|
|
// Code here doesn't run because the promise is rejected!
|
|
}, function(reason){
|
|
// reason.message === 'WHOOPS'
|
|
});
|
|
```
|
|
|
|
@method reject
|
|
@for RSVP
|
|
@param {Any} reason value that the returned promise will be rejected with.
|
|
@param {String} label optional string for identifying the returned promise.
|
|
Useful for tooling.
|
|
@return {Promise} a promise that will become rejected with the given
|
|
`reason`.
|
|
*/
|
|
function reject(reason) {
|
|
/*jshint validthis:true */
|
|
var Promise = this;
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
reject(reason);
|
|
});
|
|
}
|
|
|
|
exports.reject = reject;
|
|
},{}],60:[function(_dereq_,module,exports){
|
|
"use strict";
|
|
function resolve(value) {
|
|
/*jshint validthis:true */
|
|
if (value && typeof value === 'object' && value.constructor === this) {
|
|
return value;
|
|
}
|
|
|
|
var Promise = this;
|
|
|
|
return new Promise(function(resolve) {
|
|
resolve(value);
|
|
});
|
|
}
|
|
|
|
exports.resolve = resolve;
|
|
},{}],61:[function(_dereq_,module,exports){
|
|
"use strict";
|
|
function objectOrFunction(x) {
|
|
return isFunction(x) || (typeof x === "object" && x !== null);
|
|
}
|
|
|
|
function isFunction(x) {
|
|
return typeof x === "function";
|
|
}
|
|
|
|
function isArray(x) {
|
|
return Object.prototype.toString.call(x) === "[object Array]";
|
|
}
|
|
|
|
// Date.now is not available in browsers < IE9
|
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now#Compatibility
|
|
var now = Date.now || function() { return new Date().getTime(); };
|
|
|
|
|
|
exports.objectOrFunction = objectOrFunction;
|
|
exports.isFunction = isFunction;
|
|
exports.isArray = isArray;
|
|
exports.now = now;
|
|
},{}],62:[function(_dereq_,module,exports){
|
|
module.exports = _dereq_('./lib/agent');
|
|
},{"./lib/agent":64}],63:[function(_dereq_,module,exports){
|
|
(function (process){
|
|
// 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.
|
|
|
|
// copy from https://github.com/joyent/node/blob/master/lib/_http_agent.js
|
|
|
|
var net = _dereq_('net');
|
|
var url = _dereq_('url');
|
|
var util = _dereq_('util');
|
|
var EventEmitter = _dereq_('events').EventEmitter;
|
|
// var ClientRequest = require('_http_client').ClientRequest;
|
|
// var debug = util.debuglog('http');
|
|
var ClientRequest = _dereq_('http').ClientRequest;
|
|
var debug;
|
|
if (process.env.NODE_DEBUG && /agentkeepalive/.test(process.env.NODE_DEBUG)) {
|
|
debug = function (x) {
|
|
console.error.apply(console, arguments);
|
|
};
|
|
} else {
|
|
debug = function () { };
|
|
}
|
|
|
|
// New Agent code.
|
|
|
|
// The largest departure from the previous implementation is that
|
|
// an Agent instance holds connections for a variable number of host:ports.
|
|
// Surprisingly, this is still API compatible as far as third parties are
|
|
// concerned. The only code that really notices the difference is the
|
|
// request object.
|
|
|
|
// Another departure is that all code related to HTTP parsing is in
|
|
// ClientRequest.onSocket(). The Agent is now *strictly*
|
|
// concerned with managing a connection pool.
|
|
|
|
function Agent(options) {
|
|
if (!(this instanceof Agent))
|
|
return new Agent(options);
|
|
|
|
EventEmitter.call(this);
|
|
|
|
var self = this;
|
|
|
|
self.defaultPort = 80;
|
|
self.protocol = 'http:';
|
|
|
|
self.options = util._extend({}, options);
|
|
|
|
// don't confuse net and make it think that we're connecting to a pipe
|
|
self.options.path = null;
|
|
self.requests = {};
|
|
self.sockets = {};
|
|
self.freeSockets = {};
|
|
self.keepAliveMsecs = self.options.keepAliveMsecs || 1000;
|
|
self.keepAlive = self.options.keepAlive || false;
|
|
self.maxSockets = self.options.maxSockets || Agent.defaultMaxSockets;
|
|
self.maxFreeSockets = self.options.maxFreeSockets || 256;
|
|
|
|
self.on('free', function(socket, options) {
|
|
var name = self.getName(options);
|
|
debug('agent.on(free)', name);
|
|
|
|
if (!socket.destroyed &&
|
|
self.requests[name] && self.requests[name].length) {
|
|
self.requests[name].shift().onSocket(socket);
|
|
if (self.requests[name].length === 0) {
|
|
// don't leak
|
|
delete self.requests[name];
|
|
}
|
|
} else {
|
|
// If there are no pending requests, then put it in
|
|
// the freeSockets pool, but only if we're allowed to do so.
|
|
var req = socket._httpMessage;
|
|
if (req &&
|
|
req.shouldKeepAlive &&
|
|
!socket.destroyed &&
|
|
self.options.keepAlive) {
|
|
var freeSockets = self.freeSockets[name];
|
|
var freeLen = freeSockets ? freeSockets.length : 0;
|
|
var count = freeLen;
|
|
if (self.sockets[name])
|
|
count += self.sockets[name].length;
|
|
|
|
if (count >= self.maxSockets || freeLen >= self.maxFreeSockets) {
|
|
self.removeSocket(socket, options);
|
|
socket.destroy();
|
|
} else {
|
|
freeSockets = freeSockets || [];
|
|
self.freeSockets[name] = freeSockets;
|
|
socket.setKeepAlive(true, self.keepAliveMsecs);
|
|
socket.unref && socket.unref();
|
|
socket._httpMessage = null;
|
|
self.removeSocket(socket, options);
|
|
freeSockets.push(socket);
|
|
}
|
|
} else {
|
|
self.removeSocket(socket, options);
|
|
socket.destroy();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
util.inherits(Agent, EventEmitter);
|
|
exports.Agent = Agent;
|
|
|
|
Agent.defaultMaxSockets = Infinity;
|
|
|
|
Agent.prototype.createConnection = net.createConnection;
|
|
|
|
// Get the key for a given set of request options
|
|
Agent.prototype.getName = function(options) {
|
|
var name = '';
|
|
|
|
if (options.host)
|
|
name += options.host;
|
|
else
|
|
name += 'localhost';
|
|
|
|
name += ':';
|
|
if (options.port)
|
|
name += options.port;
|
|
name += ':';
|
|
if (options.localAddress)
|
|
name += options.localAddress;
|
|
name += ':';
|
|
return name;
|
|
};
|
|
|
|
Agent.prototype.addRequest = function(req, options) {
|
|
// Legacy API: addRequest(req, host, port, path)
|
|
if (typeof options === 'string') {
|
|
options = {
|
|
host: options,
|
|
port: arguments[2],
|
|
path: arguments[3]
|
|
};
|
|
}
|
|
|
|
var name = this.getName(options);
|
|
if (!this.sockets[name]) {
|
|
this.sockets[name] = [];
|
|
}
|
|
|
|
var freeLen = this.freeSockets[name] ? this.freeSockets[name].length : 0;
|
|
var sockLen = freeLen + this.sockets[name].length;
|
|
|
|
if (freeLen) {
|
|
// we have a free socket, so use that.
|
|
var socket = this.freeSockets[name].shift();
|
|
debug('have free socket');
|
|
|
|
// don't leak
|
|
if (!this.freeSockets[name].length)
|
|
delete this.freeSockets[name];
|
|
|
|
socket.ref && socket.ref();
|
|
req.onSocket(socket);
|
|
this.sockets[name].push(socket);
|
|
} else if (sockLen < this.maxSockets) {
|
|
debug('call onSocket', sockLen, freeLen);
|
|
// If we are under maxSockets create a new one.
|
|
req.onSocket(this.createSocket(req, options));
|
|
} else {
|
|
debug('wait for socket');
|
|
// We are over limit so we'll add it to the queue.
|
|
if (!this.requests[name]) {
|
|
this.requests[name] = [];
|
|
}
|
|
this.requests[name].push(req);
|
|
}
|
|
};
|
|
|
|
Agent.prototype.createSocket = function(req, options) {
|
|
var self = this;
|
|
options = util._extend({}, options);
|
|
options = util._extend(options, self.options);
|
|
|
|
options.servername = options.host;
|
|
if (req) {
|
|
var hostHeader = req.getHeader('host');
|
|
if (hostHeader) {
|
|
options.servername = hostHeader.replace(/:.*$/, '');
|
|
}
|
|
}
|
|
|
|
var name = self.getName(options);
|
|
|
|
debug('createConnection', name, options);
|
|
var s = self.createConnection(options);
|
|
if (!self.sockets[name]) {
|
|
self.sockets[name] = [];
|
|
}
|
|
this.sockets[name].push(s);
|
|
debug('sockets', name, this.sockets[name].length);
|
|
|
|
function onFree() {
|
|
self.emit('free', s, options);
|
|
}
|
|
s.on('free', onFree);
|
|
|
|
function onClose(err) {
|
|
debug('CLIENT socket onClose');
|
|
// This is the only place where sockets get removed from the Agent.
|
|
// If you want to remove a socket from the pool, just close it.
|
|
// All socket errors end in a close event anyway.
|
|
self.removeSocket(s, options);
|
|
}
|
|
s.on('close', onClose);
|
|
|
|
function onRemove() {
|
|
// We need this function for cases like HTTP 'upgrade'
|
|
// (defined by WebSockets) where we need to remove a socket from the
|
|
// pool because it'll be locked up indefinitely
|
|
debug('CLIENT socket onRemove');
|
|
self.removeSocket(s, options, 'agentRemove');
|
|
s.removeListener('close', onClose);
|
|
s.removeListener('free', onFree);
|
|
s.removeListener('agentRemove', onRemove);
|
|
}
|
|
s.on('agentRemove', onRemove);
|
|
return s;
|
|
};
|
|
|
|
Agent.prototype.removeSocket = function(s, options) {
|
|
var name = this.getName(options);
|
|
debug('removeSocket', name, 'destroyed:', s.destroyed);
|
|
var sets = [this.sockets];
|
|
if (s.destroyed) {
|
|
// If the socket was destroyed, we need to remove it from the free buffers.
|
|
sets.push(this.freeSockets);
|
|
}
|
|
sets.forEach(function(sockets) {
|
|
if (sockets[name]) {
|
|
var index = sockets[name].indexOf(s);
|
|
if (index !== -1) {
|
|
sockets[name].splice(index, 1);
|
|
if (sockets[name].length === 0) {
|
|
// don't leak
|
|
delete sockets[name];
|
|
}
|
|
}
|
|
}
|
|
});
|
|
if (this.requests[name] && this.requests[name].length) {
|
|
debug('removeSocket, have a request, make a socket');
|
|
var req = this.requests[name][0];
|
|
// If we have pending requests and a socket gets closed make a new one
|
|
this.createSocket(req, options).emit('free');
|
|
}
|
|
};
|
|
|
|
Agent.prototype.destroy = function() {
|
|
var sets = [this.freeSockets, this.sockets];
|
|
sets.forEach(function(set) {
|
|
Object.keys(set).forEach(function(name) {
|
|
set[name].forEach(function(socket) {
|
|
socket.destroy();
|
|
});
|
|
});
|
|
});
|
|
};
|
|
|
|
Agent.prototype.request = function(options, cb) {
|
|
// if (util.isString(options)) {
|
|
// options = url.parse(options);
|
|
// }
|
|
if (typeof options === 'string') {
|
|
options = url.parse(options);
|
|
}
|
|
// don't try to do dns lookups of foo.com:8080, just foo.com
|
|
if (options.hostname) {
|
|
options.host = options.hostname;
|
|
}
|
|
|
|
if (options && options.path && / /.test(options.path)) {
|
|
// The actual regex is more like /[^A-Za-z0-9\-._~!$&'()*+,;=/:@]/
|
|
// with an additional rule for ignoring percentage-escaped characters
|
|
// but that's a) hard to capture in a regular expression that performs
|
|
// well, and b) possibly too restrictive for real-world usage. That's
|
|
// why it only scans for spaces because those are guaranteed to create
|
|
// an invalid request.
|
|
throw new TypeError('Request path contains unescaped characters.');
|
|
} else if (options.protocol && options.protocol !== this.protocol) {
|
|
throw new Error('Protocol:' + options.protocol + ' not supported.');
|
|
}
|
|
|
|
options = util._extend({
|
|
agent: this,
|
|
keepAlive: this.keepAlive
|
|
}, options);
|
|
|
|
// if it's false, then make a new one, just like this one.
|
|
if (options.agent === false)
|
|
options.agent = new this.constructor();
|
|
|
|
debug('agent.request', options);
|
|
return new ClientRequest(options, cb);
|
|
};
|
|
|
|
Agent.prototype.get = function(options, cb) {
|
|
var req = this.request(options, cb);
|
|
req.end();
|
|
return req;
|
|
};
|
|
|
|
exports.globalAgent = new Agent();
|
|
|
|
}).call(this,_dereq_("C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"))
|
|
},{"C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":144,"events":137,"http":138,"net":127,"url":157,"util":159}],64:[function(_dereq_,module,exports){
|
|
(function (process){
|
|
/**!
|
|
* agentkeepalive - lib/agent.js
|
|
*
|
|
* refer:
|
|
* * @atimb "Real keep-alive HTTP agent": https://gist.github.com/2963672
|
|
* * https://github.com/joyent/node/blob/master/lib/http.js
|
|
* * https://github.com/joyent/node/blob/master/lib/_http_agent.js
|
|
*
|
|
* Copyright(c) 2012 - 2013 fengmk2 <fengmk2@gmail.com>
|
|
* MIT Licensed
|
|
*/
|
|
|
|
"use strict";
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var http = _dereq_('http');
|
|
var https = _dereq_('https');
|
|
var util = _dereq_('util');
|
|
|
|
var debug;
|
|
if (process.env.NODE_DEBUG && /agentkeepalive/.test(process.env.NODE_DEBUG)) {
|
|
debug = function (x) {
|
|
console.error.apply(console, arguments);
|
|
};
|
|
} else {
|
|
debug = function () { };
|
|
}
|
|
|
|
var OriginalAgent = http.Agent;
|
|
|
|
if (process.version.indexOf('v0.8.') === 0 || process.version.indexOf('v0.10.') === 0) {
|
|
OriginalAgent = _dereq_('./_http_agent').Agent;
|
|
debug('%s use _http_agent', process.version);
|
|
}
|
|
|
|
function Agent(options) {
|
|
options = options || {};
|
|
options.keepAlive = options.keepAlive !== false;
|
|
options.keepAliveMsecs = options.keepAliveMsecs || options.maxKeepAliveTime;
|
|
OriginalAgent.call(this, options);
|
|
|
|
var self = this;
|
|
// max requests per keepalive socket, default is 0, no limit.
|
|
self.maxKeepAliveRequests = parseInt(options.maxKeepAliveRequests, 10) || 0;
|
|
// max keep alive time, default 60 seconds.
|
|
// if set `keepAliveMsecs = 0`, will disable keepalive feature.
|
|
self.createSocketCount = 0;
|
|
self.timeoutSocketCount = 0;
|
|
self.requestFinishedCount = 0;
|
|
|
|
// override the `free` event listener
|
|
self.removeAllListeners('free');
|
|
self.on('free', function (socket, options) {
|
|
self.requestFinishedCount++;
|
|
socket._requestCount++;
|
|
|
|
var name = self.getName(options);
|
|
debug('agent.on(free)', name);
|
|
|
|
if (!socket.destroyed &&
|
|
self.requests[name] && self.requests[name].length) {
|
|
self.requests[name].shift().onSocket(socket);
|
|
if (self.requests[name].length === 0) {
|
|
// don't leak
|
|
delete self.requests[name];
|
|
}
|
|
} else {
|
|
// If there are no pending requests, then put it in
|
|
// the freeSockets pool, but only if we're allowed to do so.
|
|
var req = socket._httpMessage;
|
|
if (req &&
|
|
req.shouldKeepAlive &&
|
|
!socket.destroyed &&
|
|
self.options.keepAlive) {
|
|
var freeSockets = self.freeSockets[name];
|
|
var freeLen = freeSockets ? freeSockets.length : 0;
|
|
var count = freeLen;
|
|
if (self.sockets[name])
|
|
count += self.sockets[name].length;
|
|
|
|
if (count >= self.maxSockets || freeLen >= self.maxFreeSockets) {
|
|
self.removeSocket(socket, options);
|
|
socket.destroy();
|
|
} else {
|
|
freeSockets = freeSockets || [];
|
|
self.freeSockets[name] = freeSockets;
|
|
socket.setKeepAlive(true, self.keepAliveMsecs);
|
|
socket.unref && socket.unref();
|
|
socket._httpMessage = null;
|
|
self.removeSocket(socket, options);
|
|
freeSockets.push(socket);
|
|
|
|
// Avoid duplicitive timeout events by removing timeout listeners set on
|
|
// socket by previous requests. node does not do this normally because it
|
|
// assumes sockets are too short-lived for it to matter. It becomes a
|
|
// problem when sockets are being reused. Steps are being taken to fix
|
|
// this issue upstream in node v0.10.0.
|
|
//
|
|
// See https://github.com/joyent/node/commit/451ff1540ab536237e8d751d241d7fc3391a4087
|
|
if (self.keepAliveMsecs && socket._events && Array.isArray(socket._events.timeout)) {
|
|
socket.removeAllListeners('timeout');
|
|
// Restore the socket's setTimeout() that was remove as collateral
|
|
// damage.
|
|
socket.setTimeout(self.keepAliveMsecs, socket._maxKeepAliveTimeout);
|
|
}
|
|
}
|
|
} else {
|
|
self.removeSocket(socket, options);
|
|
socket.destroy();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
util.inherits(Agent, OriginalAgent);
|
|
module.exports = Agent;
|
|
|
|
Agent.prototype.createSocket = function (req, options) {
|
|
var self = this;
|
|
var socket = OriginalAgent.prototype.createSocket.call(this, req, options);
|
|
socket._requestCount = 0;
|
|
if (self.keepAliveMsecs) {
|
|
socket._maxKeepAliveTimeout = function () {
|
|
debug('maxKeepAliveTimeout, socket destroy()');
|
|
socket.destroy();
|
|
self.timeoutSocketCount++;
|
|
};
|
|
socket.setTimeout(self.keepAliveMsecs, socket._maxKeepAliveTimeout);
|
|
// Disable Nagle's algorithm: http://blog.caustik.com/2012/04/08/scaling-node-js-to-100k-concurrent-connections/
|
|
socket.setNoDelay(true);
|
|
}
|
|
this.createSocketCount++;
|
|
return socket;
|
|
};
|
|
|
|
Agent.prototype.removeSocket = function (s, options) {
|
|
OriginalAgent.prototype.removeSocket.call(this, s, options);
|
|
var name = this.getName(options);
|
|
debug('removeSocket', name, 'destroyed:', s.destroyed);
|
|
|
|
if (s.destroyed && this.freeSockets[name]) {
|
|
var index = this.freeSockets[name].indexOf(s);
|
|
if (index !== -1) {
|
|
this.freeSockets[name].splice(index, 1);
|
|
if (this.freeSockets[name].length === 0) {
|
|
// don't leak
|
|
delete this.freeSockets[name];
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
function HttpsAgent(options) {
|
|
Agent.call(this, options);
|
|
this.defaultPort = 443;
|
|
this.protocol = 'https:';
|
|
}
|
|
util.inherits(HttpsAgent, Agent);
|
|
HttpsAgent.prototype.createConnection = https.globalAgent.createConnection;
|
|
|
|
HttpsAgent.prototype.getName = function(options) {
|
|
var name = Agent.prototype.getName.call(this, options);
|
|
|
|
name += ':';
|
|
if (options.ca)
|
|
name += options.ca;
|
|
|
|
name += ':';
|
|
if (options.cert)
|
|
name += options.cert;
|
|
|
|
name += ':';
|
|
if (options.ciphers)
|
|
name += options.ciphers;
|
|
|
|
name += ':';
|
|
if (options.key)
|
|
name += options.key;
|
|
|
|
name += ':';
|
|
if (options.pfx)
|
|
name += options.pfx;
|
|
|
|
name += ':';
|
|
if (options.rejectUnauthorized !== undefined)
|
|
name += options.rejectUnauthorized;
|
|
|
|
return name;
|
|
};
|
|
|
|
Agent.HttpsAgent = HttpsAgent;
|
|
|
|
}).call(this,_dereq_("C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"))
|
|
},{"./_http_agent":63,"C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":144,"http":138,"https":142,"util":159}],65:[function(_dereq_,module,exports){
|
|
(function (Buffer){
|
|
// Version: 3.6.8
|
|
var NOW = 1
|
|
, READY = false
|
|
, READY_BUFFER = []
|
|
, PRESENCE_SUFFIX = '-pnpres'
|
|
, DEF_WINDOWING = 10 // MILLISECONDS.
|
|
, DEF_TIMEOUT = 10000 // MILLISECONDS.
|
|
, DEF_SUB_TIMEOUT = 310 // SECONDS.
|
|
, DEF_KEEPALIVE = 60 // SECONDS (FOR TIMESYNC).
|
|
, SECOND = 1000 // A THOUSAND MILLISECONDS.
|
|
, URLBIT = '/'
|
|
, PARAMSBIT = '&'
|
|
, PRESENCE_HB_THRESHOLD = 5
|
|
, PRESENCE_HB_DEFAULT = 30
|
|
, SDK_VER = '3.6.8'
|
|
, REPL = /{([\w\-]+)}/g;
|
|
|
|
/**
|
|
* UTILITIES
|
|
*/
|
|
function unique() { return'x'+ ++NOW+''+(+new Date) }
|
|
function rnow() { return+new Date }
|
|
|
|
/**
|
|
* NEXTORIGIN
|
|
* ==========
|
|
* var next_origin = nextorigin();
|
|
*/
|
|
var nextorigin = (function() {
|
|
var max = 20
|
|
, ori = Math.floor(Math.random() * max);
|
|
return function( origin, failover ) {
|
|
return origin.indexOf('pubsub.') > 0
|
|
&& origin.replace(
|
|
'pubsub', 'ps' + (
|
|
failover ? uuid().split('-')[0] :
|
|
(++ori < max? ori : ori=1)
|
|
) ) || origin;
|
|
}
|
|
})();
|
|
|
|
|
|
/**
|
|
* Build Url
|
|
* =======
|
|
*
|
|
*/
|
|
function build_url( url_components, url_params ) {
|
|
var url = url_components.join(URLBIT)
|
|
, params = [];
|
|
|
|
if (!url_params) return url;
|
|
|
|
each( url_params, function( key, value ) {
|
|
var value_str = (typeof value == 'object')?JSON['stringify'](value):value;
|
|
(typeof value != 'undefined' &&
|
|
value != null && encode(value_str).length > 0
|
|
) && params.push(key + "=" + encode(value_str));
|
|
} );
|
|
|
|
url += "?" + params.join(PARAMSBIT);
|
|
return url;
|
|
}
|
|
|
|
/**
|
|
* UPDATER
|
|
* =======
|
|
* var timestamp = unique();
|
|
*/
|
|
function updater( fun, rate ) {
|
|
var timeout
|
|
, last = 0
|
|
, runnit = function() {
|
|
if (last + rate > rnow()) {
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout( runnit, rate );
|
|
}
|
|
else {
|
|
last = rnow();
|
|
fun();
|
|
}
|
|
};
|
|
|
|
return runnit;
|
|
}
|
|
|
|
/**
|
|
* GREP
|
|
* ====
|
|
* var list = grep( [1,2,3], function(item) { return item % 2 } )
|
|
*/
|
|
function grep( list, fun ) {
|
|
var fin = [];
|
|
each( list || [], function(l) { fun(l) && fin.push(l) } );
|
|
return fin
|
|
}
|
|
|
|
/**
|
|
* SUPPLANT
|
|
* ========
|
|
* var text = supplant( 'Hello {name}!', { name : 'John' } )
|
|
*/
|
|
function supplant( str, values ) {
|
|
return str.replace( REPL, function( _, match ) {
|
|
return values[match] || _
|
|
} );
|
|
}
|
|
|
|
/**
|
|
* timeout
|
|
* =======
|
|
* timeout( function(){}, 100 );
|
|
*/
|
|
function timeout( fun, wait ) {
|
|
return setTimeout( fun, wait );
|
|
}
|
|
|
|
/**
|
|
* uuid
|
|
* ====
|
|
* var my_uuid = uuid();
|
|
*/
|
|
function uuid(callback) {
|
|
var u = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,
|
|
function(c) {
|
|
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
|
|
return v.toString(16);
|
|
});
|
|
if (callback) callback(u);
|
|
return u;
|
|
}
|
|
|
|
function isArray(arg) {
|
|
return !!arg && (Array.isArray && Array.isArray(arg) || typeof(arg.length) === "number")
|
|
}
|
|
|
|
/**
|
|
* EACH
|
|
* ====
|
|
* each( [1,2,3], function(item) { } )
|
|
*/
|
|
function each( o, f) {
|
|
if ( !o || !f ) return;
|
|
|
|
if ( isArray(o) )
|
|
for ( var i = 0, l = o.length; i < l; )
|
|
f.call( o[i], o[i], i++ );
|
|
else
|
|
for ( var i in o )
|
|
o.hasOwnProperty &&
|
|
o.hasOwnProperty(i) &&
|
|
f.call( o[i], i, o[i] );
|
|
}
|
|
|
|
/**
|
|
* MAP
|
|
* ===
|
|
* var list = map( [1,2,3], function(item) { return item + 1 } )
|
|
*/
|
|
function map( list, fun ) {
|
|
var fin = [];
|
|
each( list || [], function( k, v ) { fin.push(fun( k, v )) } );
|
|
return fin;
|
|
}
|
|
|
|
/**
|
|
* ENCODE
|
|
* ======
|
|
* var encoded_data = encode('path');
|
|
*/
|
|
function encode(path) { return encodeURIComponent(path) }
|
|
|
|
/**
|
|
* Generate Subscription Channel List
|
|
* ==================================
|
|
* generate_channel_list(channels_object);
|
|
*/
|
|
function generate_channel_list(channels, nopresence) {
|
|
var list = [];
|
|
each( channels, function( channel, status ) {
|
|
if (nopresence) {
|
|
if(channel.search('-pnpres') < 0) {
|
|
if (status.subscribed) list.push(channel);
|
|
}
|
|
} else {
|
|
if (status.subscribed) list.push(channel);
|
|
}
|
|
});
|
|
return list.sort();
|
|
}
|
|
|
|
|
|
// PUBNUB READY TO CONNECT
|
|
function ready() { timeout( function() {
|
|
if (READY) return;
|
|
READY = 1;
|
|
each( READY_BUFFER, function(connect) { connect() } );
|
|
}, SECOND ); }
|
|
|
|
function PNmessage(args) {
|
|
msg = args || {'apns' : {}},
|
|
msg['getPubnubMessage'] = function() {
|
|
var m = {};
|
|
|
|
if (Object.keys(msg['apns']).length) {
|
|
m['pn_apns'] = {
|
|
'aps' : {
|
|
'alert' : msg['apns']['alert'] ,
|
|
'badge' : msg['apns']['badge']
|
|
}
|
|
}
|
|
for (var k in msg['apns']) {
|
|
m['pn_apns'][k] = msg['apns'][k];
|
|
}
|
|
var exclude1 = ['badge','alert'];
|
|
for (var k in exclude1) {
|
|
//console.log(exclude[k]);
|
|
delete m['pn_apns'][exclude1[k]];
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (msg['gcm']) {
|
|
m['pn_gcm'] = {
|
|
'data' : msg['gcm']
|
|
}
|
|
}
|
|
|
|
for (var k in msg) {
|
|
m[k] = msg[k];
|
|
}
|
|
var exclude = ['apns','gcm','publish', 'channel','callback','error'];
|
|
for (var k in exclude) {
|
|
delete m[exclude[k]];
|
|
}
|
|
|
|
return m;
|
|
};
|
|
msg['publish'] = function() {
|
|
|
|
var m = msg.getPubnubMessage();
|
|
|
|
if (msg['pubnub'] && msg['channel']) {
|
|
msg['pubnub'].publish({
|
|
'message' : m,
|
|
'channel' : msg['channel'],
|
|
'callback' : msg['callback'],
|
|
'error' : msg['error']
|
|
})
|
|
}
|
|
};
|
|
return msg;
|
|
}
|
|
|
|
function PN_API(setup) {
|
|
var SUB_WINDOWING = +setup['windowing'] || DEF_WINDOWING
|
|
, SUB_TIMEOUT = (+setup['timeout'] || DEF_SUB_TIMEOUT) * SECOND
|
|
, KEEPALIVE = (+setup['keepalive'] || DEF_KEEPALIVE) * SECOND
|
|
, NOLEAVE = setup['noleave'] || 0
|
|
, PUBLISH_KEY = setup['publish_key'] || 'demo'
|
|
, SUBSCRIBE_KEY = setup['subscribe_key'] || 'demo'
|
|
, AUTH_KEY = setup['auth_key'] || ''
|
|
, SECRET_KEY = setup['secret_key'] || ''
|
|
, hmac_SHA256 = setup['hmac_SHA256']
|
|
, SSL = setup['ssl'] ? 's' : ''
|
|
, ORIGIN = 'http'+SSL+'://'+(setup['origin']||'pubsub.pubnub.com')
|
|
, STD_ORIGIN = nextorigin(ORIGIN)
|
|
, SUB_ORIGIN = nextorigin(ORIGIN)
|
|
, CONNECT = function(){}
|
|
, PUB_QUEUE = []
|
|
, TIME_DRIFT = 0
|
|
, SUB_CALLBACK = 0
|
|
, SUB_CHANNEL = 0
|
|
, SUB_RECEIVER = 0
|
|
, SUB_RESTORE = setup['restore'] || 0
|
|
, SUB_BUFF_WAIT = 0
|
|
, TIMETOKEN = 0
|
|
, RESUMED = false
|
|
, CHANNELS = {}
|
|
, STATE = {}
|
|
, PRESENCE_HB_TIMEOUT = null
|
|
, PRESENCE_HB = validate_presence_heartbeat(setup['heartbeat'] || setup['pnexpires'] || 0, setup['error'])
|
|
, PRESENCE_HB_INTERVAL = setup['heartbeat_interval'] || PRESENCE_HB - 3
|
|
, PRESENCE_HB_RUNNING = false
|
|
, NO_WAIT_FOR_PENDING = setup['no_wait_for_pending']
|
|
, COMPATIBLE_35 = setup['compatible_3.5'] || false
|
|
, xdr = setup['xdr']
|
|
, params = setup['params'] || {}
|
|
, error = setup['error'] || function() {}
|
|
, _is_online = setup['_is_online'] || function() { return 1 }
|
|
, jsonp_cb = setup['jsonp_cb'] || function() { return 0 }
|
|
, db = setup['db'] || {'get': function(){}, 'set': function(){}}
|
|
, CIPHER_KEY = setup['cipher_key']
|
|
, UUID = setup['uuid'] || ( db && db['get'](SUBSCRIBE_KEY+'uuid') || '');
|
|
|
|
var crypto_obj = setup['crypto_obj'] ||
|
|
{
|
|
'encrypt' : function(a,key){ return a},
|
|
'decrypt' : function(b,key){return b}
|
|
};
|
|
|
|
function _get_url_params(data) {
|
|
if (!data) data = {};
|
|
each( params , function( key, value ) {
|
|
if (!(key in data)) data[key] = value;
|
|
});
|
|
return data;
|
|
}
|
|
|
|
function _object_to_key_list(o) {
|
|
var l = []
|
|
each( o , function( key, value ) {
|
|
l.push(key);
|
|
});
|
|
return l;
|
|
}
|
|
function _object_to_key_list_sorted(o) {
|
|
return _object_to_key_list(o).sort();
|
|
}
|
|
|
|
function _get_pam_sign_input_from_params(params) {
|
|
var si = "";
|
|
var l = _object_to_key_list_sorted(params);
|
|
|
|
for (var i in l) {
|
|
var k = l[i]
|
|
si += k + "=" + encode(params[k]) ;
|
|
if (i != l.length - 1) si += "&"
|
|
}
|
|
return si;
|
|
}
|
|
|
|
function validate_presence_heartbeat(heartbeat, cur_heartbeat, error) {
|
|
var err = false;
|
|
|
|
if (typeof heartbeat === 'number') {
|
|
if (heartbeat > PRESENCE_HB_THRESHOLD || heartbeat == 0)
|
|
err = false;
|
|
else
|
|
err = true;
|
|
} else if(typeof heartbeat === 'boolean'){
|
|
if (!heartbeat) {
|
|
return 0;
|
|
} else {
|
|
return PRESENCE_HB_DEFAULT;
|
|
}
|
|
} else {
|
|
err = true;
|
|
}
|
|
|
|
if (err) {
|
|
error && error("Presence Heartbeat value invalid. Valid range ( x > " + PRESENCE_HB_THRESHOLD + " or x = 0). Current Value : " + (cur_heartbeat || PRESENCE_HB_THRESHOLD));
|
|
return cur_heartbeat || PRESENCE_HB_THRESHOLD;
|
|
} else return heartbeat;
|
|
}
|
|
|
|
function encrypt(input, key) {
|
|
return crypto_obj['encrypt'](input, key || CIPHER_KEY) || input;
|
|
}
|
|
function decrypt(input, key) {
|
|
return crypto_obj['decrypt'](input, key || CIPHER_KEY) ||
|
|
crypto_obj['decrypt'](input, CIPHER_KEY) ||
|
|
input;
|
|
}
|
|
|
|
function error_common(message, callback) {
|
|
callback && callback({ 'error' : message || "error occurred"});
|
|
error && error(message);
|
|
}
|
|
function _presence_heartbeat() {
|
|
|
|
clearTimeout(PRESENCE_HB_TIMEOUT);
|
|
|
|
if (!PRESENCE_HB_INTERVAL || PRESENCE_HB_INTERVAL >= 500 || PRESENCE_HB_INTERVAL < 1 || !generate_channel_list(CHANNELS,true).length){
|
|
PRESENCE_HB_RUNNING = false;
|
|
return;
|
|
}
|
|
|
|
PRESENCE_HB_RUNNING = true;
|
|
SELF['presence_heartbeat']({
|
|
'callback' : function(r) {
|
|
PRESENCE_HB_TIMEOUT = timeout( _presence_heartbeat, (PRESENCE_HB_INTERVAL) * SECOND );
|
|
},
|
|
'error' : function(e) {
|
|
error && error("Presence Heartbeat unable to reach Pubnub servers." + JSON.stringify(e));
|
|
PRESENCE_HB_TIMEOUT = timeout( _presence_heartbeat, (PRESENCE_HB_INTERVAL) * SECOND );
|
|
}
|
|
});
|
|
}
|
|
|
|
function start_presence_heartbeat() {
|
|
!PRESENCE_HB_RUNNING && _presence_heartbeat();
|
|
}
|
|
|
|
function publish(next) {
|
|
|
|
if (NO_WAIT_FOR_PENDING) {
|
|
if (!PUB_QUEUE.length) return;
|
|
} else {
|
|
if (next) PUB_QUEUE.sending = 0;
|
|
if ( PUB_QUEUE.sending || !PUB_QUEUE.length ) return;
|
|
PUB_QUEUE.sending = 1;
|
|
}
|
|
|
|
xdr(PUB_QUEUE.shift());
|
|
}
|
|
|
|
function each_channel(callback) {
|
|
var count = 0;
|
|
|
|
each( generate_channel_list(CHANNELS), function(channel) {
|
|
var chan = CHANNELS[channel];
|
|
|
|
if (!chan) return;
|
|
|
|
count++;
|
|
(callback||function(){})(chan);
|
|
} );
|
|
|
|
return count;
|
|
}
|
|
function _invoke_callback(response, callback, err) {
|
|
if (typeof response == 'object') {
|
|
if (response['error'] && response['message'] && response['payload']) {
|
|
err({'message' : response['message'], 'payload' : response['payload']});
|
|
return;
|
|
}
|
|
if (response['payload']) {
|
|
callback(response['payload']);
|
|
return;
|
|
}
|
|
}
|
|
callback(response);
|
|
}
|
|
|
|
function _invoke_error(response,err) {
|
|
if (typeof response == 'object' && response['error'] &&
|
|
response['message'] && response['payload']) {
|
|
err({'message' : response['message'], 'payload' : response['payload']});
|
|
} else err(response);
|
|
}
|
|
|
|
// Announce Leave Event
|
|
var SELF = {
|
|
'LEAVE' : function( channel, blocking, callback, error ) {
|
|
|
|
var data = { 'uuid' : UUID, 'auth' : AUTH_KEY }
|
|
, origin = nextorigin(ORIGIN)
|
|
, callback = callback || function(){}
|
|
, err = error || function(){}
|
|
, jsonp = jsonp_cb();
|
|
|
|
// Prevent Leaving a Presence Channel
|
|
if (channel.indexOf(PRESENCE_SUFFIX) > 0) return true;
|
|
|
|
if (COMPATIBLE_35) {
|
|
if (!SSL) return false;
|
|
if (jsonp == '0') return false;
|
|
}
|
|
|
|
if (NOLEAVE) return false;
|
|
|
|
if (jsonp != '0') data['callback'] = jsonp;
|
|
|
|
xdr({
|
|
blocking : blocking || SSL,
|
|
timeout : 2000,
|
|
callback : jsonp,
|
|
data : _get_url_params(data),
|
|
success : function(response) {
|
|
_invoke_callback(response, callback, err);
|
|
},
|
|
fail : function(response) {
|
|
_invoke_error(response, err);
|
|
},
|
|
url : [
|
|
origin, 'v2', 'presence', 'sub_key',
|
|
SUBSCRIBE_KEY, 'channel', encode(channel), 'leave'
|
|
]
|
|
});
|
|
return true;
|
|
},
|
|
'set_resumed' : function(resumed) {
|
|
RESUMED = resumed;
|
|
},
|
|
'get_cipher_key' : function() {
|
|
return CIPHER_KEY;
|
|
},
|
|
'set_cipher_key' : function(key) {
|
|
CIPHER_KEY = key;
|
|
},
|
|
'raw_encrypt' : function(input, key) {
|
|
return encrypt(input, key);
|
|
},
|
|
'raw_decrypt' : function(input, key) {
|
|
return decrypt(input, key);
|
|
},
|
|
'get_heartbeat' : function() {
|
|
return PRESENCE_HB;
|
|
},
|
|
'set_heartbeat' : function(heartbeat) {
|
|
PRESENCE_HB = validate_presence_heartbeat(heartbeat, PRESENCE_HB_INTERVAL, error);
|
|
PRESENCE_HB_INTERVAL = (PRESENCE_HB - 3 >= 1)?PRESENCE_HB - 3:1;
|
|
CONNECT();
|
|
_presence_heartbeat();
|
|
},
|
|
'get_heartbeat_interval' : function() {
|
|
return PRESENCE_HB_INTERVAL;
|
|
},
|
|
'set_heartbeat_interval' : function(heartbeat_interval) {
|
|
PRESENCE_HB_INTERVAL = heartbeat_interval;
|
|
_presence_heartbeat();
|
|
},
|
|
'get_version' : function() {
|
|
return SDK_VER;
|
|
},
|
|
'getGcmMessageObject' : function(obj) {
|
|
return {
|
|
'data' : obj
|
|
}
|
|
},
|
|
'getApnsMessageObject' : function(obj) {
|
|
var x = {
|
|
'aps' : { 'badge' : 1, 'alert' : ''}
|
|
}
|
|
for (k in obj) {
|
|
k[x] = obj[k];
|
|
}
|
|
return x;
|
|
},
|
|
'newPnMessage' : function() {
|
|
var x = {};
|
|
if (gcm) x['pn_gcm'] = gcm;
|
|
if (apns) x['pn_apns'] = apns;
|
|
for ( k in n ) {
|
|
x[k] = n[k];
|
|
}
|
|
return x;
|
|
},
|
|
|
|
'_add_param' : function(key,val) {
|
|
params[key] = val;
|
|
},
|
|
|
|
/*
|
|
PUBNUB.history({
|
|
channel : 'my_chat_channel',
|
|
limit : 100,
|
|
callback : function(history) { }
|
|
});
|
|
*/
|
|
'history' : function( args, callback ) {
|
|
var callback = args['callback'] || callback
|
|
, count = args['count'] || args['limit'] || 100
|
|
, reverse = args['reverse'] || "false"
|
|
, err = args['error'] || function(){}
|
|
, auth_key = args['auth_key'] || AUTH_KEY
|
|
, cipher_key = args['cipher_key']
|
|
, channel = args['channel']
|
|
, start = args['start']
|
|
, end = args['end']
|
|
, include_token = args['include_token']
|
|
, params = {}
|
|
, jsonp = jsonp_cb();
|
|
|
|
// Make sure we have a Channel
|
|
if (!channel) return error('Missing Channel');
|
|
if (!callback) return error('Missing Callback');
|
|
if (!SUBSCRIBE_KEY) return error('Missing Subscribe Key');
|
|
|
|
params['stringtoken'] = 'true';
|
|
params['count'] = count;
|
|
params['reverse'] = reverse;
|
|
params['auth'] = auth_key;
|
|
|
|
if (jsonp) params['callback'] = jsonp;
|
|
if (start) params['start'] = start;
|
|
if (end) params['end'] = end;
|
|
if (include_token) params['include_token'] = 'true';
|
|
|
|
// Send Message
|
|
xdr({
|
|
callback : jsonp,
|
|
data : _get_url_params(params),
|
|
success : function(response) {
|
|
if (typeof response == 'object' && response['error']) {
|
|
err({'message' : response['message'], 'payload' : response['payload']});
|
|
return;
|
|
}
|
|
var messages = response[0];
|
|
var decrypted_messages = [];
|
|
for (var a = 0; a < messages.length; a++) {
|
|
var new_message = decrypt(messages[a],cipher_key);
|
|
try {
|
|
decrypted_messages['push'](JSON['parse'](new_message));
|
|
} catch (e) {
|
|
decrypted_messages['push']((new_message));
|
|
}
|
|
}
|
|
callback([decrypted_messages, response[1], response[2]]);
|
|
},
|
|
fail : function(response) {
|
|
_invoke_error(response, err);
|
|
},
|
|
url : [
|
|
STD_ORIGIN, 'v2', 'history', 'sub-key',
|
|
SUBSCRIBE_KEY, 'channel', encode(channel)
|
|
]
|
|
});
|
|
},
|
|
|
|
/*
|
|
PUBNUB.replay({
|
|
source : 'my_channel',
|
|
destination : 'new_channel'
|
|
});
|
|
*/
|
|
'replay' : function(args, callback) {
|
|
var callback = callback || args['callback'] || function(){}
|
|
, auth_key = args['auth_key'] || AUTH_KEY
|
|
, source = args['source']
|
|
, destination = args['destination']
|
|
, stop = args['stop']
|
|
, start = args['start']
|
|
, end = args['end']
|
|
, reverse = args['reverse']
|
|
, limit = args['limit']
|
|
, jsonp = jsonp_cb()
|
|
, data = {}
|
|
, url;
|
|
|
|
// Check User Input
|
|
if (!source) return error('Missing Source Channel');
|
|
if (!destination) return error('Missing Destination Channel');
|
|
if (!PUBLISH_KEY) return error('Missing Publish Key');
|
|
if (!SUBSCRIBE_KEY) return error('Missing Subscribe Key');
|
|
|
|
// Setup URL Params
|
|
if (jsonp != '0') data['callback'] = jsonp;
|
|
if (stop) data['stop'] = 'all';
|
|
if (reverse) data['reverse'] = 'true';
|
|
if (start) data['start'] = start;
|
|
if (end) data['end'] = end;
|
|
if (limit) data['count'] = limit;
|
|
|
|
data['auth'] = auth_key;
|
|
|
|
// Compose URL Parts
|
|
url = [
|
|
STD_ORIGIN, 'v1', 'replay',
|
|
PUBLISH_KEY, SUBSCRIBE_KEY,
|
|
source, destination
|
|
];
|
|
|
|
// Start (or Stop) Replay!
|
|
xdr({
|
|
callback : jsonp,
|
|
success : function(response) {
|
|
_invoke_callback(response, callback, err);
|
|
},
|
|
fail : function() { callback([ 0, 'Disconnected' ]) },
|
|
url : url,
|
|
data : _get_url_params(data)
|
|
});
|
|
},
|
|
|
|
/*
|
|
PUBNUB.auth('AJFLKAJSDKLA');
|
|
*/
|
|
'auth' : function(auth) {
|
|
AUTH_KEY = auth;
|
|
CONNECT();
|
|
},
|
|
|
|
/*
|
|
PUBNUB.time(function(time){ });
|
|
*/
|
|
'time' : function(callback) {
|
|
var jsonp = jsonp_cb();
|
|
xdr({
|
|
callback : jsonp,
|
|
data : _get_url_params({ 'uuid' : UUID, 'auth' : AUTH_KEY }),
|
|
timeout : SECOND * 5,
|
|
url : [STD_ORIGIN, 'time', jsonp],
|
|
success : function(response) { callback(response[0]) },
|
|
fail : function() { callback(0) }
|
|
});
|
|
},
|
|
|
|
/*
|
|
PUBNUB.publish({
|
|
channel : 'my_chat_channel',
|
|
message : 'hello!'
|
|
});
|
|
*/
|
|
'publish' : function( args, callback ) {
|
|
var msg = args['message'];
|
|
if (!msg) return error('Missing Message');
|
|
|
|
var callback = callback || args['callback'] || msg['callback'] || function(){}
|
|
, channel = args['channel'] || msg['channel']
|
|
, auth_key = args['auth_key'] || AUTH_KEY
|
|
, cipher_key = args['cipher_key']
|
|
, err = args['error'] || msg['error'] || function() {}
|
|
, post = args['post'] || false
|
|
, store = ('store_in_history' in args) ? args['store_in_history']: true
|
|
, jsonp = jsonp_cb()
|
|
, add_msg = 'push'
|
|
, url;
|
|
|
|
if (args['prepend']) add_msg = 'unshift'
|
|
|
|
if (!channel) return error('Missing Channel');
|
|
if (!PUBLISH_KEY) return error('Missing Publish Key');
|
|
if (!SUBSCRIBE_KEY) return error('Missing Subscribe Key');
|
|
|
|
if (msg['getPubnubMessage']) {
|
|
msg = msg['getPubnubMessage']();
|
|
}
|
|
|
|
// If trying to send Object
|
|
msg = JSON['stringify'](encrypt(msg, cipher_key));
|
|
|
|
// Create URL
|
|
url = [
|
|
STD_ORIGIN, 'publish',
|
|
PUBLISH_KEY, SUBSCRIBE_KEY,
|
|
0, encode(channel),
|
|
jsonp, encode(msg)
|
|
];
|
|
|
|
params = { 'uuid' : UUID, 'auth' : auth_key }
|
|
|
|
if (!store) params['store'] ="0"
|
|
|
|
// Queue Message Send
|
|
PUB_QUEUE[add_msg]({
|
|
callback : jsonp,
|
|
timeout : SECOND * 5,
|
|
url : url,
|
|
data : _get_url_params(params),
|
|
fail : function(response){
|
|
_invoke_error(response, err);
|
|
publish(1);
|
|
},
|
|
success : function(response) {
|
|
_invoke_callback(response, callback, err);
|
|
publish(1);
|
|
},
|
|
mode : (post)?'POST':'GET'
|
|
});
|
|
|
|
// Send Message
|
|
publish();
|
|
},
|
|
|
|
/*
|
|
PUBNUB.unsubscribe({ channel : 'my_chat' });
|
|
*/
|
|
'unsubscribe' : function(args, callback) {
|
|
var channel = args['channel']
|
|
, callback = callback || args['callback'] || function(){}
|
|
, err = args['error'] || function(){};
|
|
|
|
TIMETOKEN = 0;
|
|
//SUB_RESTORE = 1; REVISIT !!!!
|
|
|
|
// Prepare Channel(s)
|
|
channel = map( (
|
|
channel.join ? channel.join(',') : ''+channel
|
|
).split(','), function(channel) {
|
|
if (!CHANNELS[channel]) return;
|
|
return channel + ',' + channel + PRESENCE_SUFFIX;
|
|
} ).join(',');
|
|
|
|
// Iterate over Channels
|
|
each( channel.split(','), function(channel) {
|
|
var CB_CALLED = true;
|
|
if (!channel) return;
|
|
if (READY) {
|
|
CB_CALLED = SELF['LEAVE']( channel, 0 , callback, err);
|
|
}
|
|
if (!CB_CALLED) callback({action : "leave"});
|
|
CHANNELS[channel] = 0;
|
|
if (channel in STATE) delete STATE[channel];
|
|
} );
|
|
|
|
// Reset Connection if Count Less
|
|
CONNECT();
|
|
},
|
|
|
|
/*
|
|
PUBNUB.subscribe({
|
|
channel : 'my_chat'
|
|
callback : function(message) { }
|
|
});
|
|
*/
|
|
'subscribe' : function( args, callback ) {
|
|
var channel = args['channel']
|
|
, callback = callback || args['callback']
|
|
, callback = callback || args['message']
|
|
, auth_key = args['auth_key'] || AUTH_KEY
|
|
, connect = args['connect'] || function(){}
|
|
, reconnect = args['reconnect'] || function(){}
|
|
, disconnect = args['disconnect'] || function(){}
|
|
, errcb = args['error'] || function(){}
|
|
, idlecb = args['idle'] || function(){}
|
|
, presence = args['presence'] || 0
|
|
, noheresync = args['noheresync'] || 0
|
|
, backfill = args['backfill'] || 0
|
|
, timetoken = args['timetoken'] || 0
|
|
, sub_timeout = args['timeout'] || SUB_TIMEOUT
|
|
, windowing = args['windowing'] || SUB_WINDOWING
|
|
, state = args['state']
|
|
, heartbeat = args['heartbeat'] || args['pnexpires']
|
|
, restore = args['restore'] || SUB_RESTORE;
|
|
|
|
// Restore Enabled?
|
|
SUB_RESTORE = restore;
|
|
|
|
// Always Reset the TT
|
|
TIMETOKEN = timetoken;
|
|
|
|
// Make sure we have a Channel
|
|
if (!channel) return error('Missing Channel');
|
|
if (!callback) return error('Missing Callback');
|
|
if (!SUBSCRIBE_KEY) return error('Missing Subscribe Key');
|
|
|
|
if (heartbeat || heartbeat === 0) {
|
|
SELF['set_heartbeat'](heartbeat);
|
|
}
|
|
|
|
// Setup Channel(s)
|
|
each( (channel.join ? channel.join(',') : ''+channel).split(','),
|
|
function(channel) {
|
|
var settings = CHANNELS[channel] || {};
|
|
|
|
// Store Channel State
|
|
CHANNELS[SUB_CHANNEL = channel] = {
|
|
name : channel,
|
|
connected : settings.connected,
|
|
disconnected : settings.disconnected,
|
|
subscribed : 1,
|
|
callback : SUB_CALLBACK = callback,
|
|
'cipher_key' : args['cipher_key'],
|
|
connect : connect,
|
|
disconnect : disconnect,
|
|
reconnect : reconnect
|
|
};
|
|
if (state) {
|
|
if (channel in state) {
|
|
STATE[channel] = state[channel];
|
|
} else {
|
|
STATE[channel] = state;
|
|
}
|
|
}
|
|
|
|
// Presence Enabled?
|
|
if (!presence) return;
|
|
|
|
// Subscribe Presence Channel
|
|
SELF['subscribe']({
|
|
'channel' : channel + PRESENCE_SUFFIX,
|
|
'callback' : presence,
|
|
'restore' : restore
|
|
});
|
|
|
|
// Presence Subscribed?
|
|
if (settings.subscribed) return;
|
|
|
|
// See Who's Here Now?
|
|
if (noheresync) return;
|
|
SELF['here_now']({
|
|
'channel' : channel,
|
|
'callback' : function(here) {
|
|
each( 'uuids' in here ? here['uuids'] : [],
|
|
function(uid) { presence( {
|
|
'action' : 'join',
|
|
'uuid' : uid,
|
|
'timestamp' : Math.floor(rnow() / 1000),
|
|
'occupancy' : here['occupancy'] || 1
|
|
}, here, channel ); } );
|
|
}
|
|
});
|
|
} );
|
|
|
|
// Test Network Connection
|
|
function _test_connection(success) {
|
|
if (success) {
|
|
// Begin Next Socket Connection
|
|
timeout( CONNECT, SECOND );
|
|
}
|
|
else {
|
|
// New Origin on Failed Connection
|
|
STD_ORIGIN = nextorigin( ORIGIN, 1 );
|
|
SUB_ORIGIN = nextorigin( ORIGIN, 1 );
|
|
|
|
// Re-test Connection
|
|
timeout( function() {
|
|
SELF['time'](_test_connection);
|
|
}, SECOND );
|
|
}
|
|
|
|
// Disconnect & Reconnect
|
|
each_channel(function(channel){
|
|
// Reconnect
|
|
if (success && channel.disconnected) {
|
|
channel.disconnected = 0;
|
|
return channel.reconnect(channel.name);
|
|
}
|
|
|
|
// Disconnect
|
|
if (!success && !channel.disconnected) {
|
|
channel.disconnected = 1;
|
|
channel.disconnect(channel.name);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Evented Subscribe
|
|
function _connect() {
|
|
var jsonp = jsonp_cb()
|
|
, channels = generate_channel_list(CHANNELS).join(',');
|
|
|
|
// Stop Connection
|
|
if (!channels) return;
|
|
|
|
// Connect to PubNub Subscribe Servers
|
|
_reset_offline();
|
|
|
|
var data = _get_url_params({ 'uuid' : UUID, 'auth' : auth_key });
|
|
|
|
var st = JSON.stringify(STATE);
|
|
if (st.length > 2) data['state'] = JSON.stringify(STATE);
|
|
|
|
if (PRESENCE_HB) data['heartbeat'] = PRESENCE_HB;
|
|
|
|
start_presence_heartbeat();
|
|
SUB_RECEIVER = xdr({
|
|
timeout : sub_timeout,
|
|
callback : jsonp,
|
|
fail : function(response) {
|
|
_invoke_error(response, errcb);
|
|
//SUB_RECEIVER = null;
|
|
SELF['time'](_test_connection);
|
|
},
|
|
data : _get_url_params(data),
|
|
url : [
|
|
SUB_ORIGIN, 'subscribe',
|
|
SUBSCRIBE_KEY, encode(channels),
|
|
jsonp, TIMETOKEN
|
|
],
|
|
success : function(messages) {
|
|
|
|
//SUB_RECEIVER = null;
|
|
// Check for Errors
|
|
if (!messages || (
|
|
typeof messages == 'object' &&
|
|
'error' in messages &&
|
|
messages['error']
|
|
)) {
|
|
errcb(messages['error']);
|
|
return timeout( CONNECT, SECOND );
|
|
}
|
|
|
|
// User Idle Callback
|
|
idlecb(messages[1]);
|
|
|
|
// Restore Previous Connection Point if Needed
|
|
TIMETOKEN = !TIMETOKEN &&
|
|
SUB_RESTORE &&
|
|
db['get'](SUBSCRIBE_KEY) || messages[1];
|
|
|
|
// Connect
|
|
each_channel(function(channel){
|
|
if (channel.connected) return;
|
|
channel.connected = 1;
|
|
channel.connect(channel.name);
|
|
});
|
|
|
|
if (RESUMED && !SUB_RESTORE) {
|
|
TIMETOKEN = 0;
|
|
RESUMED = false;
|
|
// Update Saved Timetoken
|
|
db['set']( SUBSCRIBE_KEY, 0 );
|
|
timeout( _connect, windowing );
|
|
return;
|
|
}
|
|
|
|
// Invoke Memory Catchup and Receive Up to 100
|
|
// Previous Messages from the Queue.
|
|
if (backfill) {
|
|
TIMETOKEN = 10000;
|
|
backfill = 0;
|
|
}
|
|
|
|
// Update Saved Timetoken
|
|
db['set']( SUBSCRIBE_KEY, messages[1] );
|
|
|
|
// Route Channel <---> Callback for Message
|
|
var next_callback = (function() {
|
|
var channels = (messages.length>2?messages[2]:map(
|
|
generate_channel_list(CHANNELS), function(chan) { return map(
|
|
Array(messages[0].length)
|
|
.join(',').split(','),
|
|
function() { return chan; }
|
|
) }).join(','));
|
|
var list = channels.split(',');
|
|
|
|
return function() {
|
|
var channel = list.shift()||SUB_CHANNEL;
|
|
return [
|
|
(CHANNELS[channel]||{})
|
|
.callback||SUB_CALLBACK,
|
|
channel.split(PRESENCE_SUFFIX)[0]
|
|
];
|
|
};
|
|
})();
|
|
|
|
var latency = detect_latency(+messages[1]);
|
|
each( messages[0], function(msg) {
|
|
var next = next_callback();
|
|
var decrypted_msg = decrypt(msg,
|
|
(CHANNELS[next[1]])?CHANNELS[next[1]]['cipher_key']:null);
|
|
next[0]( decrypted_msg, messages, next[1], latency);
|
|
});
|
|
|
|
timeout( _connect, windowing );
|
|
}
|
|
});
|
|
}
|
|
|
|
CONNECT = function() {
|
|
_reset_offline();
|
|
timeout( _connect, windowing );
|
|
};
|
|
|
|
// Reduce Status Flicker
|
|
if (!READY) return READY_BUFFER.push(CONNECT);
|
|
|
|
// Connect Now
|
|
CONNECT();
|
|
},
|
|
|
|
/*
|
|
PUBNUB.here_now({ channel : 'my_chat', callback : fun });
|
|
*/
|
|
'here_now' : function( args, callback ) {
|
|
var callback = args['callback'] || callback
|
|
, err = args['error'] || function(){}
|
|
, auth_key = args['auth_key'] || AUTH_KEY
|
|
, channel = args['channel']
|
|
, jsonp = jsonp_cb()
|
|
, uuids = ('uuids' in args) ? args['uuids'] : true
|
|
, state = args['state']
|
|
, data = { 'uuid' : UUID, 'auth' : auth_key };
|
|
|
|
if (!uuids) data['disable_uuids'] = 1;
|
|
if (state) data['state'] = 1;
|
|
|
|
// Make sure we have a Channel
|
|
if (!callback) return error('Missing Callback');
|
|
if (!SUBSCRIBE_KEY) return error('Missing Subscribe Key');
|
|
|
|
var url = [
|
|
STD_ORIGIN, 'v2', 'presence',
|
|
'sub_key', SUBSCRIBE_KEY
|
|
];
|
|
|
|
channel && url.push('channel') && url.push(encode(channel));
|
|
|
|
if (jsonp != '0') { data['callback'] = jsonp; }
|
|
|
|
xdr({
|
|
callback : jsonp,
|
|
data : _get_url_params(data),
|
|
success : function(response) {
|
|
_invoke_callback(response, callback, err);
|
|
},
|
|
fail : function(response) {
|
|
_invoke_error(response, err);
|
|
},
|
|
url : url
|
|
});
|
|
},
|
|
|
|
/*
|
|
PUBNUB.current_channels_by_uuid({ channel : 'my_chat', callback : fun });
|
|
*/
|
|
'where_now' : function( args, callback ) {
|
|
var callback = args['callback'] || callback
|
|
, err = args['error'] || function(){}
|
|
, auth_key = args['auth_key'] || AUTH_KEY
|
|
, jsonp = jsonp_cb()
|
|
, uuid = args['uuid'] || UUID
|
|
, data = { 'auth' : auth_key };
|
|
|
|
// Make sure we have a Channel
|
|
if (!callback) return error('Missing Callback');
|
|
if (!SUBSCRIBE_KEY) return error('Missing Subscribe Key');
|
|
|
|
if (jsonp != '0') { data['callback'] = jsonp; }
|
|
|
|
xdr({
|
|
callback : jsonp,
|
|
data : _get_url_params(data),
|
|
success : function(response) {
|
|
_invoke_callback(response, callback, err);
|
|
},
|
|
fail : function(response) {
|
|
_invoke_error(response, err);
|
|
},
|
|
url : [
|
|
STD_ORIGIN, 'v2', 'presence',
|
|
'sub_key', SUBSCRIBE_KEY,
|
|
'uuid', encode(uuid)
|
|
]
|
|
});
|
|
},
|
|
|
|
'state' : function(args, callback) {
|
|
var callback = args['callback'] || callback || function(r) {}
|
|
, err = args['error'] || function(){}
|
|
, auth_key = args['auth_key'] || AUTH_KEY
|
|
, jsonp = jsonp_cb()
|
|
, state = args['state']
|
|
, uuid = args['uuid'] || UUID
|
|
, channel = args['channel']
|
|
, url
|
|
, data = _get_url_params({ 'auth' : auth_key });
|
|
|
|
// Make sure we have a Channel
|
|
if (!SUBSCRIBE_KEY) return error('Missing Subscribe Key');
|
|
if (!uuid) return error('Missing UUID');
|
|
if (!channel) return error('Missing Channel');
|
|
|
|
if (jsonp != '0') { data['callback'] = jsonp; }
|
|
|
|
if (CHANNELS[channel] && CHANNELS[channel].subscribed && state) STATE[channel] = state;
|
|
|
|
data['state'] = JSON.stringify(state);
|
|
|
|
if (state) {
|
|
url = [
|
|
STD_ORIGIN, 'v2', 'presence',
|
|
'sub-key', SUBSCRIBE_KEY,
|
|
'channel', encode(channel),
|
|
'uuid', uuid, 'data'
|
|
]
|
|
} else {
|
|
url = [
|
|
STD_ORIGIN, 'v2', 'presence',
|
|
'sub-key', SUBSCRIBE_KEY,
|
|
'channel', encode(channel),
|
|
'uuid', encode(uuid)
|
|
]
|
|
}
|
|
|
|
xdr({
|
|
callback : jsonp,
|
|
data : _get_url_params(data),
|
|
success : function(response) {
|
|
_invoke_callback(response, callback, err);
|
|
},
|
|
fail : function(response) {
|
|
_invoke_error(response, err);
|
|
},
|
|
url : url
|
|
|
|
});
|
|
|
|
},
|
|
|
|
/*
|
|
PUBNUB.grant({
|
|
channel : 'my_chat',
|
|
callback : fun,
|
|
error : fun,
|
|
ttl : 24 * 60, // Minutes
|
|
read : true,
|
|
write : true,
|
|
auth_key : '3y8uiajdklytowsj'
|
|
});
|
|
*/
|
|
'grant' : function( args, callback ) {
|
|
var callback = args['callback'] || callback
|
|
, err = args['error'] || function(){}
|
|
, channel = args['channel']
|
|
, jsonp = jsonp_cb()
|
|
, ttl = args['ttl']
|
|
, r = (args['read'] )?"1":"0"
|
|
, w = (args['write'])?"1":"0"
|
|
, auth_key = args['auth_key'];
|
|
|
|
if (!callback) return error('Missing Callback');
|
|
if (!SUBSCRIBE_KEY) return error('Missing Subscribe Key');
|
|
if (!PUBLISH_KEY) return error('Missing Publish Key');
|
|
if (!SECRET_KEY) return error('Missing Secret Key');
|
|
|
|
var timestamp = Math.floor(new Date().getTime() / 1000)
|
|
, sign_input = SUBSCRIBE_KEY + "\n" + PUBLISH_KEY + "\n"
|
|
+ "grant" + "\n";
|
|
|
|
var data = {
|
|
'w' : w,
|
|
'r' : r,
|
|
'timestamp' : timestamp
|
|
};
|
|
if (channel != 'undefined' && channel != null && channel.length > 0) data['channel'] = channel;
|
|
if (jsonp != '0') { data['callback'] = jsonp; }
|
|
if (ttl || ttl === 0) data['ttl'] = ttl;
|
|
|
|
if (auth_key) data['auth'] = auth_key;
|
|
|
|
data = _get_url_params(data)
|
|
|
|
if (!auth_key) delete data['auth'];
|
|
|
|
sign_input += _get_pam_sign_input_from_params(data);
|
|
|
|
var signature = hmac_SHA256( sign_input, SECRET_KEY );
|
|
|
|
signature = signature.replace( /\+/g, "-" );
|
|
signature = signature.replace( /\//g, "_" );
|
|
|
|
data['signature'] = signature;
|
|
|
|
xdr({
|
|
callback : jsonp,
|
|
data : data,
|
|
success : function(response) {
|
|
_invoke_callback(response, callback, err);
|
|
},
|
|
fail : function(response) {
|
|
_invoke_error(response, err);
|
|
},
|
|
url : [
|
|
STD_ORIGIN, 'v1', 'auth', 'grant' ,
|
|
'sub-key', SUBSCRIBE_KEY
|
|
]
|
|
});
|
|
},
|
|
|
|
/*
|
|
PUBNUB.audit({
|
|
channel : 'my_chat',
|
|
callback : fun,
|
|
error : fun,
|
|
read : true,
|
|
write : true,
|
|
auth_key : '3y8uiajdklytowsj'
|
|
});
|
|
*/
|
|
'audit' : function( args, callback ) {
|
|
var callback = args['callback'] || callback
|
|
, err = args['error'] || function(){}
|
|
, channel = args['channel']
|
|
, auth_key = args['auth_key']
|
|
, jsonp = jsonp_cb();
|
|
|
|
// Make sure we have a Channel
|
|
if (!callback) return error('Missing Callback');
|
|
if (!SUBSCRIBE_KEY) return error('Missing Subscribe Key');
|
|
if (!PUBLISH_KEY) return error('Missing Publish Key');
|
|
if (!SECRET_KEY) return error('Missing Secret Key');
|
|
|
|
var timestamp = Math.floor(new Date().getTime() / 1000)
|
|
, sign_input = SUBSCRIBE_KEY + "\n"
|
|
+ PUBLISH_KEY + "\n"
|
|
+ "audit" + "\n";
|
|
|
|
var data = {'timestamp' : timestamp };
|
|
if (jsonp != '0') { data['callback'] = jsonp; }
|
|
if (channel != 'undefined' && channel != null && channel.length > 0) data['channel'] = channel;
|
|
if (auth_key) data['auth'] = auth_key;
|
|
|
|
data = _get_url_params(data)
|
|
|
|
if (!auth_key) delete data['auth'];
|
|
|
|
sign_input += _get_pam_sign_input_from_params(data);
|
|
|
|
var signature = hmac_SHA256( sign_input, SECRET_KEY );
|
|
|
|
signature = signature.replace( /\+/g, "-" );
|
|
signature = signature.replace( /\//g, "_" );
|
|
|
|
data['signature'] = signature;
|
|
xdr({
|
|
callback : jsonp,
|
|
data : data,
|
|
success : function(response) {
|
|
_invoke_callback(response, callback, err);
|
|
},
|
|
fail : function(response) {
|
|
_invoke_error(response, err);
|
|
},
|
|
url : [
|
|
STD_ORIGIN, 'v1', 'auth', 'audit' ,
|
|
'sub-key', SUBSCRIBE_KEY
|
|
]
|
|
});
|
|
},
|
|
|
|
/*
|
|
PUBNUB.revoke({
|
|
channel : 'my_chat',
|
|
callback : fun,
|
|
error : fun,
|
|
auth_key : '3y8uiajdklytowsj'
|
|
});
|
|
*/
|
|
'revoke' : function( args, callback ) {
|
|
args['read'] = false;
|
|
args['write'] = false;
|
|
SELF['grant']( args, callback );
|
|
},
|
|
'set_uuid' : function(uuid) {
|
|
UUID = uuid;
|
|
CONNECT();
|
|
},
|
|
'get_uuid' : function() {
|
|
return UUID;
|
|
},
|
|
'presence_heartbeat' : function(args) {
|
|
var callback = args['callback'] || function() {}
|
|
var err = args['error'] || function() {}
|
|
var jsonp = jsonp_cb();
|
|
var data = { 'uuid' : UUID, 'auth' : AUTH_KEY };
|
|
|
|
var st = JSON['stringify'](STATE);
|
|
if (st.length > 2) data['state'] = JSON['stringify'](STATE);
|
|
|
|
if (PRESENCE_HB > 0 && PRESENCE_HB < 320) data['heartbeat'] = PRESENCE_HB;
|
|
|
|
if (jsonp != '0') { data['callback'] = jsonp; }
|
|
|
|
xdr({
|
|
callback : jsonp,
|
|
data : _get_url_params(data),
|
|
timeout : SECOND * 5,
|
|
url : [
|
|
STD_ORIGIN, 'v2', 'presence',
|
|
'sub-key', SUBSCRIBE_KEY,
|
|
'channel' , encode(generate_channel_list(CHANNELS, true)['join'](',')),
|
|
'heartbeat'
|
|
],
|
|
success : function(response) {
|
|
_invoke_callback(response, callback, err);
|
|
},
|
|
fail : function(response) { _invoke_error(response, err); }
|
|
});
|
|
},
|
|
|
|
// Expose PUBNUB Functions
|
|
'xdr' : xdr,
|
|
'ready' : ready,
|
|
'db' : db,
|
|
'uuid' : uuid,
|
|
'map' : map,
|
|
'each' : each,
|
|
'each-channel' : each_channel,
|
|
'grep' : grep,
|
|
'offline' : function(){_reset_offline(1, { "message":"Offline. Please check your network settings." })},
|
|
'supplant' : supplant,
|
|
'now' : rnow,
|
|
'unique' : unique,
|
|
'updater' : updater
|
|
};
|
|
|
|
function _poll_online() {
|
|
_is_online() || _reset_offline( 1, {
|
|
"error" : "Offline. Please check your network settings. "
|
|
});
|
|
timeout( _poll_online, SECOND );
|
|
}
|
|
|
|
function _poll_online2() {
|
|
SELF['time'](function(success){
|
|
detect_time_detla( function(){}, success );
|
|
success || _reset_offline( 1, {
|
|
"error" : "Heartbeat failed to connect to Pubnub Servers." +
|
|
"Please check your network settings."
|
|
});
|
|
timeout( _poll_online2, KEEPALIVE );
|
|
});
|
|
}
|
|
|
|
function _reset_offline(err, msg) {
|
|
SUB_RECEIVER && SUB_RECEIVER(err, msg);
|
|
SUB_RECEIVER = null;
|
|
}
|
|
|
|
if (!UUID) UUID = SELF['uuid']();
|
|
db['set']( SUBSCRIBE_KEY + 'uuid', UUID );
|
|
|
|
timeout( _poll_online, SECOND );
|
|
timeout( _poll_online2, KEEPALIVE );
|
|
PRESENCE_HB_TIMEOUT = timeout( start_presence_heartbeat, ( PRESENCE_HB_INTERVAL - 3 ) * SECOND ) ;
|
|
|
|
// Detect Age of Message
|
|
function detect_latency(tt) {
|
|
var adjusted_time = rnow() - TIME_DRIFT;
|
|
return adjusted_time - tt / 10000;
|
|
}
|
|
|
|
detect_time_detla();
|
|
function detect_time_detla( cb, time ) {
|
|
var stime = rnow();
|
|
|
|
time && calculate(time) || SELF['time'](calculate);
|
|
|
|
function calculate(time) {
|
|
if (!time) return;
|
|
var ptime = time / 10000
|
|
, latency = (rnow() - stime) / 2;
|
|
TIME_DRIFT = rnow() - (ptime + latency);
|
|
cb && cb(TIME_DRIFT);
|
|
}
|
|
}
|
|
|
|
return SELF;
|
|
}
|
|
/* ---------------------------------------------------------------------------
|
|
WAIT! - This file depends on instructions from the PUBNUB Cloud.
|
|
http://www.pubnub.com/account
|
|
--------------------------------------------------------------------------- */
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
PubNub Real-time Cloud-Hosted Push API and Push Notification Client Frameworks
|
|
Copyright (c) 2011 TopMambo Inc.
|
|
http://www.pubnub.com/
|
|
http://www.pubnub.com/terms
|
|
--------------------------------------------------------------------------- */
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
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.
|
|
--------------------------------------------------------------------------- */
|
|
/**
|
|
* UTIL LOCALS
|
|
*/
|
|
var NOW = 1
|
|
, http = _dereq_('http')
|
|
, https = _dereq_('https')
|
|
, keepAliveAgent = new (keepAliveIsEmbedded() ? http.Agent : _dereq_('agentkeepalive'))({
|
|
keepAlive: true,
|
|
keepAliveMsecs: 300000,
|
|
maxSockets: 5
|
|
})
|
|
, XHRTME = 310000
|
|
, DEF_TIMEOUT = 10000
|
|
, SECOND = 1000
|
|
, PNSDK = 'PubNub-JS-' + 'Nodejs' + '/' + '3.6.8'
|
|
, crypto = _dereq_('crypto')
|
|
, proxy = null
|
|
, XORIGN = 1;
|
|
|
|
|
|
function get_hmac_SHA256(data, key) {
|
|
return crypto.createHmac('sha256',
|
|
new Buffer(key, 'utf8')).update(data).digest('base64');
|
|
}
|
|
|
|
|
|
/**
|
|
* ERROR
|
|
* ===
|
|
* error('message');
|
|
*/
|
|
function error(message) { console['error'](message) }
|
|
|
|
/**
|
|
* Request
|
|
* =======
|
|
* xdr({
|
|
* url : ['http://www.blah.com/url'],
|
|
* success : function(response) {},
|
|
* fail : function() {}
|
|
* });
|
|
*/
|
|
function xdr( setup ) {
|
|
var request
|
|
, response
|
|
, success = setup.success || function(){}
|
|
, fail = setup.fail || function(){}
|
|
, origin = setup.origin || 'pubsub.pubnub.com'
|
|
, ssl = setup.ssl
|
|
, failed = 0
|
|
, complete = 0
|
|
, loaded = 0
|
|
, mode = setup['mode'] || 'GET'
|
|
, data = setup['data'] || {}
|
|
, xhrtme = setup.timeout || DEF_TIMEOUT
|
|
, body = ''
|
|
, finished = function() {
|
|
if (loaded) return;
|
|
loaded = 1;
|
|
|
|
clearTimeout(timer);
|
|
try { response = JSON['parse'](body); }
|
|
catch (r) { return done(1); }
|
|
success(response);
|
|
}
|
|
, done = function(failed, response) {
|
|
if (complete) return;
|
|
complete = 1;
|
|
|
|
clearTimeout(timer);
|
|
|
|
if (request) {
|
|
request.on('error', function(){});
|
|
request.on('data', function(){});
|
|
request.on('end', function(){});
|
|
request.abort && request.abort();
|
|
request = null;
|
|
}
|
|
failed && fail(response);
|
|
}
|
|
, timer = timeout( function(){done(1);} , xhrtme );
|
|
|
|
data['pnsdk'] = PNSDK;
|
|
|
|
var options = {};
|
|
var headers = {};
|
|
var payload = '';
|
|
|
|
if (mode == 'POST')
|
|
payload = decodeURIComponent(setup.url.pop());
|
|
|
|
var url = build_url( setup.url, data );
|
|
if (!ssl) ssl = (url.split('://')[0] == 'https')?true:false;
|
|
|
|
url = '/' + url.split('/').slice(3).join('/');
|
|
|
|
var origin = setup.url[0].split("//")[1]
|
|
|
|
options.hostname = proxy ? proxy.hostname : setup.url[0].split("//")[1];
|
|
options.port = proxy ? proxy.port : ssl ? 443 : 80;
|
|
options.path = proxy ? "http://" + origin + url:url;
|
|
options.headers = proxy ? { 'Host': origin }:null;
|
|
options.method = mode;
|
|
options.keepAlive= !!keepAliveAgent;
|
|
options.agent = keepAliveAgent;
|
|
options.body = payload;
|
|
|
|
_dereq_('http').globalAgent.maxSockets = Infinity;
|
|
try {
|
|
request = (ssl ? https : http)['request'](options, function(response) {
|
|
response.setEncoding('utf8');
|
|
response.on( 'error', function(){console.log('error');done(1, body || { "error" : "Network Connection Error"})});
|
|
response.on( 'abort', function(){console.log('abort');done(1, body || { "error" : "Network Connection Error"})});
|
|
response.on( 'data', function (chunk) {
|
|
if (chunk) body += chunk;
|
|
} );
|
|
response.on( 'end', function(){
|
|
var statusCode = response.statusCode;
|
|
|
|
switch(statusCode) {
|
|
case 401:
|
|
case 402:
|
|
case 403:
|
|
try {
|
|
response = JSON['parse'](body);
|
|
done(1,response);
|
|
}
|
|
catch (r) { return done(1, body); }
|
|
return;
|
|
default:
|
|
break;
|
|
}
|
|
finished();
|
|
});
|
|
});
|
|
request.timeout = xhrtme;
|
|
request.on( 'error', function() {
|
|
done( 1, {"error":"Network Connection Error"} );
|
|
} );
|
|
|
|
if (mode == 'POST') request.write(payload);
|
|
request.end();
|
|
|
|
} catch(e) {
|
|
done(0);
|
|
return xdr(setup);
|
|
}
|
|
|
|
return done;
|
|
}
|
|
|
|
/**
|
|
* LOCAL STORAGE
|
|
*/
|
|
var db = (function(){
|
|
var store = {};
|
|
return {
|
|
'get' : function(key) {
|
|
return store[key];
|
|
},
|
|
'set' : function( key, value ) {
|
|
store[key] = value;
|
|
}
|
|
};
|
|
})();
|
|
|
|
function crypto_obj() {
|
|
var iv = "0123456789012345";
|
|
function get_padded_key(key) {
|
|
return crypto.createHash('sha256').update(key).digest("hex").slice(0,32);
|
|
}
|
|
|
|
return {
|
|
'encrypt' : function(input, key) {
|
|
if (!key) return input;
|
|
var plain_text = JSON['stringify'](input);
|
|
var cipher = crypto.createCipheriv('aes-256-cbc', get_padded_key(key), iv);
|
|
var base_64_encrypted = cipher.update(plain_text, 'utf8', 'base64') + cipher.final('base64');
|
|
return base_64_encrypted || input;
|
|
},
|
|
'decrypt' : function(input, key) {
|
|
if (!key) return input;
|
|
var decipher = crypto.createDecipheriv('aes-256-cbc', get_padded_key(key), iv);
|
|
try {
|
|
var decrypted = decipher.update(input, 'base64', 'utf8') + decipher.final('utf8');
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
return JSON.parse(decrypted);
|
|
}
|
|
}
|
|
}
|
|
|
|
function keepAliveIsEmbedded() {
|
|
return 'EventEmitter' in http.Agent.super_;
|
|
}
|
|
|
|
|
|
var CREATE_PUBNUB = function(setup) {
|
|
proxy = setup['proxy'];
|
|
setup['xdr'] = xdr;
|
|
setup['db'] = db;
|
|
setup['error'] = setup['error'] || error;
|
|
setup['hmac_SHA256'] = get_hmac_SHA256;
|
|
setup['crypto_obj'] = crypto_obj();
|
|
setup['params'] = {'pnsdk' : PNSDK};
|
|
|
|
if (setup['keepAlive'] === false) {
|
|
keepAliveAgent = undefined;
|
|
}
|
|
|
|
SELF = function(setup) {
|
|
return CREATE_PUBNUB(setup);
|
|
}
|
|
var PN = PN_API(setup);
|
|
for (var prop in PN) {
|
|
if (PN.hasOwnProperty(prop)) {
|
|
SELF[prop] = PN[prop];
|
|
}
|
|
}
|
|
SELF.init = SELF;
|
|
SELF.secure = SELF;
|
|
SELF.ready();
|
|
return SELF;
|
|
}
|
|
CREATE_PUBNUB.init = CREATE_PUBNUB;
|
|
|
|
CREATE_PUBNUB.unique = unique
|
|
CREATE_PUBNUB.secure = CREATE_PUBNUB;
|
|
module.exports = CREATE_PUBNUB
|
|
module.exports.PNmessage = PNmessage;
|
|
|
|
}).call(this,_dereq_("buffer").Buffer)
|
|
},{"agentkeepalive":62,"buffer":128,"crypto":132,"http":138,"https":142}],66:[function(_dereq_,module,exports){
|
|
/*
|
|
Copyright (c) 2010,2011,2012,2013 Morgan Roderick http://roderick.dk
|
|
License: MIT - http://mrgnrdrck.mit-license.org
|
|
|
|
https://github.com/mroderick/PubSubJS
|
|
*/
|
|
/*jslint white:true, plusplus:true, stupid:true*/
|
|
/*global
|
|
setTimeout,
|
|
module,
|
|
exports,
|
|
define,
|
|
require,
|
|
window
|
|
*/
|
|
(function(root, factory){
|
|
'use strict';
|
|
|
|
// CommonJS
|
|
if (typeof exports === 'object' && module){
|
|
module.exports = factory();
|
|
|
|
// AMD
|
|
} else if (typeof define === 'function' && define.amd){
|
|
define(factory);
|
|
// Browser
|
|
} else {
|
|
root.PubSub = factory();
|
|
}
|
|
}( ( typeof window === 'object' && window ) || this, function(){
|
|
|
|
'use strict';
|
|
|
|
var PubSub = {},
|
|
messages = {},
|
|
lastUid = -1;
|
|
|
|
function hasKeys(obj){
|
|
var key;
|
|
|
|
for (key in obj){
|
|
if ( obj.hasOwnProperty(key) ){
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns a function that throws the passed exception, for use as argument for setTimeout
|
|
* @param { Object } ex An Error object
|
|
*/
|
|
function throwException( ex ){
|
|
return function reThrowException(){
|
|
throw ex;
|
|
};
|
|
}
|
|
|
|
function callSubscriberWithDelayedExceptions( subscriber, message, data ){
|
|
try {
|
|
subscriber( message, data );
|
|
} catch( ex ){
|
|
setTimeout( throwException( ex ), 0);
|
|
}
|
|
}
|
|
|
|
function callSubscriberWithImmediateExceptions( subscriber, message, data ){
|
|
subscriber( message, data );
|
|
}
|
|
|
|
function deliverMessage( originalMessage, matchedMessage, data, immediateExceptions ){
|
|
var subscribers = messages[matchedMessage],
|
|
callSubscriber = immediateExceptions ? callSubscriberWithImmediateExceptions : callSubscriberWithDelayedExceptions,
|
|
s;
|
|
|
|
if ( !messages.hasOwnProperty( matchedMessage ) ) {
|
|
return;
|
|
}
|
|
|
|
for (s in subscribers){
|
|
if ( subscribers.hasOwnProperty(s)){
|
|
callSubscriber( subscribers[s], originalMessage, data );
|
|
}
|
|
}
|
|
}
|
|
|
|
function createDeliveryFunction( message, data, immediateExceptions ){
|
|
return function deliverNamespaced(){
|
|
var topic = String( message ),
|
|
position = topic.lastIndexOf( '.' );
|
|
|
|
// deliver the message as it is now
|
|
deliverMessage(message, message, data, immediateExceptions);
|
|
|
|
// trim the hierarchy and deliver message to each level
|
|
while( position !== -1 ){
|
|
topic = topic.substr( 0, position );
|
|
position = topic.lastIndexOf('.');
|
|
deliverMessage( message, topic, data );
|
|
}
|
|
};
|
|
}
|
|
|
|
function messageHasSubscribers( message ){
|
|
var topic = String( message ),
|
|
found = Boolean(messages.hasOwnProperty( topic ) && hasKeys(messages[topic])),
|
|
position = topic.lastIndexOf( '.' );
|
|
|
|
while ( !found && position !== -1 ){
|
|
topic = topic.substr( 0, position );
|
|
position = topic.lastIndexOf( '.' );
|
|
found = Boolean(messages.hasOwnProperty( topic ) && hasKeys(messages[topic]));
|
|
}
|
|
|
|
return found;
|
|
}
|
|
|
|
function publish( message, data, sync, immediateExceptions ){
|
|
var deliver = createDeliveryFunction( message, data, immediateExceptions ),
|
|
hasSubscribers = messageHasSubscribers( message );
|
|
|
|
if ( !hasSubscribers ){
|
|
return false;
|
|
}
|
|
|
|
if ( sync === true ){
|
|
deliver();
|
|
} else {
|
|
setTimeout( deliver, 0 );
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* PubSub.publish( message[, data] ) -> Boolean
|
|
* - message (String): The message to publish
|
|
* - data: The data to pass to subscribers
|
|
* Publishes the the message, passing the data to it's subscribers
|
|
**/
|
|
PubSub.publish = function( message, data ){
|
|
return publish( message, data, false, PubSub.immediateExceptions );
|
|
};
|
|
|
|
/**
|
|
* PubSub.publishSync( message[, data] ) -> Boolean
|
|
* - message (String): The message to publish
|
|
* - data: The data to pass to subscribers
|
|
* Publishes the the message synchronously, passing the data to it's subscribers
|
|
**/
|
|
PubSub.publishSync = function( message, data ){
|
|
return publish( message, data, true, PubSub.immediateExceptions );
|
|
};
|
|
|
|
/**
|
|
* PubSub.subscribe( message, func ) -> String
|
|
* - message (String): The message to subscribe to
|
|
* - func (Function): The function to call when a new message is published
|
|
* Subscribes the passed function to the passed message. Every returned token is unique and should be stored if
|
|
* you need to unsubscribe
|
|
**/
|
|
PubSub.subscribe = function( message, func ){
|
|
if ( typeof func !== 'function'){
|
|
return false;
|
|
}
|
|
|
|
// message is not registered yet
|
|
if ( !messages.hasOwnProperty( message ) ){
|
|
messages[message] = {};
|
|
}
|
|
|
|
// forcing token as String, to allow for future expansions without breaking usage
|
|
// and allow for easy use as key names for the 'messages' object
|
|
var token = 'uid_' + String(++lastUid);
|
|
messages[message][token] = func;
|
|
|
|
// return token for unsubscribing
|
|
return token;
|
|
};
|
|
|
|
/**
|
|
* PubSub.unsubscribe( tokenOrFunction ) -> String | Boolean
|
|
* - tokenOrFunction (String|Function): The token of the function to unsubscribe or func passed in on subscribe
|
|
* Unsubscribes a specific subscriber from a specific message using the unique token
|
|
* or if using Function as argument, it will remove all subscriptions with that function
|
|
**/
|
|
PubSub.unsubscribe = function( tokenOrFunction ){
|
|
var isToken = typeof tokenOrFunction === 'string',
|
|
result = false,
|
|
m, message, t, token;
|
|
|
|
for ( m in messages ){
|
|
if ( messages.hasOwnProperty( m ) ){
|
|
message = messages[m];
|
|
|
|
if ( isToken && message[tokenOrFunction] ){
|
|
delete message[tokenOrFunction];
|
|
result = tokenOrFunction;
|
|
// tokens are unique, so we can just stop here
|
|
break;
|
|
} else if (!isToken) {
|
|
for ( t in message ){
|
|
if (message.hasOwnProperty(t) && message[t] === tokenOrFunction){
|
|
delete message[t];
|
|
result = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
return PubSub;
|
|
}));
|
|
|
|
},{}],67:[function(_dereq_,module,exports){
|
|
exports.Host = _dereq_('./lib/Host');
|
|
exports.Promise = _dereq_('./lib/Promise');
|
|
|
|
},{"./lib/Host":68,"./lib/Promise":70}],68:[function(_dereq_,module,exports){
|
|
var WebSocket = _dereq_('ws');
|
|
var WebSocketServer = _dereq_('ws').Server;
|
|
var uuid = _dereq_('node-uuid');
|
|
var Promise = _dereq_('./Promise');
|
|
var requestify = _dereq_('./requestify');
|
|
var Peer = _dereq_('./Peer');
|
|
|
|
/**
|
|
* Host
|
|
* @param {Object} [options] Available options: see Host.config
|
|
*/
|
|
function Host(options) {
|
|
var me = this;
|
|
|
|
// peers and cached peer addresses
|
|
this.peers = {}; // local peers
|
|
this.addresses = {}; // cached addresses of peers located on other hosts
|
|
|
|
// pubsub
|
|
this.channels = {}; // keys are the channels, values are arrays with callbacks of subscribers
|
|
|
|
// default options
|
|
this.options = {
|
|
reconnectTimeout: 5 * 60 * 1000, // give up reconnecting after 5 minutes
|
|
reconnectDelay: 1000, // try reconnecting after one second
|
|
reconnectDecay: 2
|
|
};
|
|
|
|
// server properties
|
|
this.server = null;
|
|
this.address = null;
|
|
this.port = null;
|
|
this.connections = {}; // List with open connections, key is the url and value is the connection
|
|
this.timers = {}; // reconnect timers
|
|
|
|
/**
|
|
* Send a message from one peer to another
|
|
* @param {string} from Id of the sending peer
|
|
* @param {string} to Id of the receiving peer
|
|
* @param {*} message JSON message
|
|
* @returns {Promise.<null, Error>} Resolves when sent
|
|
*/
|
|
this.send = function (from, to, message) {
|
|
// see if the peer lives on the same host
|
|
var peer = me.peers[to];
|
|
if (peer) {
|
|
peer.emit('message', from, message);
|
|
return Promise.resolve(null);
|
|
}
|
|
|
|
// find the remote host where the recipient is located
|
|
return me.find(to)
|
|
.then(function (url) {
|
|
var conn = me.connections[url];
|
|
if (conn) {
|
|
var request = {
|
|
method: 'send',
|
|
params: {
|
|
from: from,
|
|
to: to,
|
|
message: message
|
|
}
|
|
};
|
|
// TODO: there is a maximum callstack issue when queuing a lot of notifications
|
|
return conn.request(request) // the send request returns null
|
|
//return conn.notify(request) // the send request returns null
|
|
.catch(function (err) {
|
|
// FIXME: use a protocol for errors, use error code
|
|
if (err.toString().indexOf('Error: Peer not found') === 0) {
|
|
// this peer was deleted. Remove it from cache
|
|
delete me.addresses[to];
|
|
throw _peerNotFoundError(to);
|
|
}
|
|
})
|
|
}
|
|
else {
|
|
throw _peerUnreachable(to, url);
|
|
}
|
|
});
|
|
};
|
|
|
|
this.config(options);
|
|
}
|
|
|
|
/**
|
|
* Apply configuration options to the host, and/or retrieve the current
|
|
* configuration.
|
|
* @param {Object} [options] Available options:
|
|
* - networkId An id for the distribus
|
|
* network. A Host can only
|
|
* connect to other hosts with
|
|
* the same id. networkId cannot
|
|
* be changed once set.
|
|
* - reconnectTimeout Timeout in milliseconds for
|
|
* giving up reconnecting.
|
|
* 5 minutes by default
|
|
* - reconnectDelay Initial delay for trying to
|
|
* reconnect. for consecutive
|
|
* reconnect trials, the delay
|
|
* decays with a factor
|
|
* `reconnectDecay`.
|
|
* 1 second by default.
|
|
* - reconnectDecay Decay for the reconnect
|
|
* delay. 2 by default.
|
|
* @return {Object} Returns the current configuration
|
|
*/
|
|
Host.prototype.config = function (options) {
|
|
// apply new options
|
|
if (options) {
|
|
_merge(this.options, options);
|
|
|
|
// apply networkId
|
|
if (options.networkId) {
|
|
if (this.networkId !== null) {
|
|
this.networkId = options.networkId;
|
|
}
|
|
else {
|
|
throw new Error('Cannot replace networkId once set');
|
|
}
|
|
}
|
|
}
|
|
|
|
// return a copy of the options
|
|
return _merge({}, this.options);
|
|
};
|
|
|
|
/**
|
|
* Create a new peer.
|
|
* Throws an error when a peer with the same id already exists on this host.
|
|
* Does not check whether this id exists on any remote host (use Host.find(id)
|
|
* to validate this before creating a peer, or even better, use a uuid to
|
|
* prevent id collisions).
|
|
* @param {string} id The id for the new peer
|
|
* @return {Peer} Returns the created peer
|
|
*/
|
|
Host.prototype.create = function (id) {
|
|
if (id in this.peers) {
|
|
throw new Error('Id already exists (id: ' + id +')');
|
|
}
|
|
|
|
var peer = new Peer(id, this.send);
|
|
this.peers[id] = peer;
|
|
|
|
return peer;
|
|
};
|
|
|
|
/**
|
|
* Remove a peer from the host
|
|
* @param {Peer | string} peer A peer or the id of a peer
|
|
*/
|
|
Host.prototype.remove = function (peer) {
|
|
if (peer instanceof Peer) { // a peer instance
|
|
delete this.peers[peer.id];
|
|
}
|
|
else if (peer) { // a string with the peers id
|
|
delete this.peers[peer];
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Get a local peer by its id
|
|
* @param {string} id The id of an existing peer
|
|
* @return {Peer | null} returns the peer, or returns null when not existing.
|
|
*/
|
|
Host.prototype.get = function (id) {
|
|
return this.peers[id] || null;
|
|
};
|
|
|
|
/**
|
|
* Find the host of a peer by it's id
|
|
* @param {string} id Id of a peer
|
|
* @return {Promise.<string | null, Error>} The url of the peers host.
|
|
* Returns null if the found host has no url.
|
|
* Throws an error if not found.
|
|
*/
|
|
Host.prototype.find = function (id) {
|
|
var me = this;
|
|
|
|
// check if this is a local peer
|
|
if (id in me.peers) {
|
|
return Promise.resolve(me.url || null);
|
|
}
|
|
|
|
// check if this id is already in cache
|
|
var url = me.addresses[id];
|
|
if (url) {
|
|
// yes, we already have the address
|
|
return Promise.resolve(url);
|
|
}
|
|
|
|
// search on other hosts
|
|
return new Promise(function (resolve, reject) {
|
|
// TODO: send requests in small batches, not all at once
|
|
|
|
// send a find request to a host
|
|
var found = false;
|
|
function _find(url) {
|
|
var conn = me.connections[url];
|
|
return conn.request({method: 'find', params: {id: id}})
|
|
.then(function (url) {
|
|
if (url && !found) {
|
|
// we found the peer
|
|
found = true;
|
|
|
|
// put this address in cache
|
|
// TODO: limit the number of cached addresses. When exceeding the limit, store on disk in a temporary db
|
|
me.addresses[id] = url;
|
|
|
|
// return the found url
|
|
resolve(url);
|
|
}
|
|
});
|
|
}
|
|
|
|
// ask all connected hosts if they host this peer
|
|
var results = Object.keys(me.connections).map(_find);
|
|
|
|
// if all requests are finished and the peer is not found, reject with an error
|
|
Promise.all(results)
|
|
.then(function () {
|
|
if (!found || results.length == 0) {
|
|
reject(_peerNotFoundError(id));
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Start listening on a socket.
|
|
* @param {string} address
|
|
* @param {number} port
|
|
* @return {Promise.<Host, Error>} Returns itself when connected
|
|
*/
|
|
Host.prototype.listen = function (address, port) {
|
|
var me = this;
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
if (me.server) {
|
|
reject(new Error('Server already listening'));
|
|
return;
|
|
}
|
|
|
|
me.server = new WebSocketServer({port: port}, function () {
|
|
me.address = address;
|
|
me.port = port;
|
|
me.url = 'ws://' + address + ':' + port;
|
|
|
|
resolve(me);
|
|
});
|
|
|
|
me.server.on('connection', function (conn) {
|
|
conn = requestify(conn);
|
|
|
|
conn.onerror = function (err) {
|
|
// TODO: what to do with errors?
|
|
};
|
|
|
|
conn.onclose = function () {
|
|
// remove this connection from the connections list
|
|
// (we do not yet forget the cached peers)
|
|
var url = me._findUrl(conn);
|
|
delete me.connections[url];
|
|
|
|
me.timers[url] = setTimeout(function () {
|
|
delete me.timers[url];
|
|
|
|
// clear cache
|
|
me._forgetPeers(url);
|
|
}, me.options.reconnectTimeout);
|
|
};
|
|
|
|
conn.onrequest = function (request) {
|
|
return me._onRequest(conn, request);
|
|
};
|
|
});
|
|
|
|
me.server.on('error', function (err) {
|
|
reject(err)
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Handle a request
|
|
* @param {WebSocket} conn
|
|
* @param {Object} request
|
|
* @returns {Promise}
|
|
* @private
|
|
*/
|
|
Host.prototype._onRequest = function (conn, request) {
|
|
var me = this;
|
|
var url;
|
|
|
|
switch (request.method) {
|
|
case 'greeting':
|
|
url = request.params && request.params.url;
|
|
var networkId = request.params.networkId || null;
|
|
if (networkId === null || networkId === me.networkId) {
|
|
if (url && !(url in this.connections)) {
|
|
this.connections[url] = conn;
|
|
return this._broadcastJoin(url)
|
|
.then(function () {
|
|
return Promise.resolve({networkId: me.networkId})
|
|
});
|
|
}
|
|
else {
|
|
return Promise.resolve({networkId: me.networkId});
|
|
}
|
|
}
|
|
else {
|
|
return Promise.reject(new Error('Network id mismatch (' + networkId + ' !== ' + me.networkId + ')'));
|
|
}
|
|
|
|
case 'join':
|
|
url = request.params && request.params.url;
|
|
return this.join(url)
|
|
.then(function (host) {
|
|
return Promise.resolve();
|
|
});
|
|
|
|
case 'goodbye':
|
|
url = this._findUrl(conn);
|
|
this._forgetPeers(url);
|
|
this._disconnect(url);
|
|
return Promise.resolve('goodbye');
|
|
|
|
case 'hosts':
|
|
// connect to all newly retrieved urls
|
|
if (request.params && request.params.urls) {
|
|
this.join(request.params.urls);
|
|
}
|
|
|
|
// return a list with the urls of all known hosts
|
|
return Promise.resolve(Object.keys(this.connections));
|
|
|
|
case 'find': // find a peer
|
|
var id = request.params && request.params.id;
|
|
return Promise.resolve(this.peers[id] ? this.url : null);
|
|
|
|
case 'send':
|
|
var from = request.params && request.params.from;
|
|
var to = request.params && request.params.to;
|
|
var message = request.params && request.params.message;
|
|
|
|
// TODO: validate whether all parameters are there
|
|
var peer = this.peers[to];
|
|
if (peer) {
|
|
peer.emit('message', from, message);
|
|
return Promise.resolve(null);
|
|
}
|
|
else {
|
|
return Promise.reject(_peerNotFoundError(to).toString());
|
|
}
|
|
|
|
case 'publish':
|
|
var channel = request.params && request.params.channel;
|
|
var message = request.params && request.params.message;
|
|
this._publish(channel, message);
|
|
return Promise.resolve({
|
|
result: null,
|
|
error: null
|
|
});
|
|
|
|
case 'ping':
|
|
return Promise.resolve({
|
|
result: request.params,
|
|
error: null
|
|
});
|
|
|
|
default:
|
|
return Promise.reject('Unknown method "' + request.method + '"');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Find an url from a connection
|
|
* @param {WebSocket} conn
|
|
* @return {String | null} url
|
|
* @private
|
|
*/
|
|
Host.prototype._findUrl = function (conn) {
|
|
// search by instance
|
|
for (var url in this.connections) {
|
|
if (this.connections.hasOwnProperty(url) && this.connections[url] === conn) {
|
|
return url;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
};
|
|
|
|
/**
|
|
* Remove all cached peers of given
|
|
* @param {string} url Url of a host for which to forget the cached peers
|
|
* @private
|
|
*/
|
|
Host.prototype._forgetPeers = function (url) {
|
|
// remove all cached peers
|
|
for (var id in this.addresses) {
|
|
if (this.addresses.hasOwnProperty(id) && this.addresses[id] === url) {
|
|
delete this.addresses[id];
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Join an other Host.
|
|
* A host can only join another host when having the same id, or having no id
|
|
* defined. In the latter case, the host will orphan the id of the host it
|
|
* connects to.
|
|
* @param {string} url For example 'ws://localhost:3000'
|
|
* @return {Promise.<Host, Error>} Returns itself when joined
|
|
*/
|
|
Host.prototype.join = function (url) {
|
|
var me = this;
|
|
|
|
if (url && !(url in me.connections)) {
|
|
return me._connect(url)
|
|
.then(function () {
|
|
// broadcast the join request to all known hosts
|
|
return me._broadcastJoin(url);
|
|
})
|
|
.then(function (urls) {
|
|
// return the host itself as last result in the promise chain
|
|
return me;
|
|
});
|
|
// TODO: handle connection error
|
|
}
|
|
else {
|
|
// already known url. ignore this join
|
|
// FIXME: it is possible that this connection is still being established
|
|
return Promise.resolve(me);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Open a connection to an other host and add the host to the list of connected
|
|
* hosts.
|
|
* @param {String} url
|
|
* @returns {Promise.<WebSocket, Error>} Returns the established connection
|
|
* @private
|
|
*/
|
|
Host.prototype._connect = function(url) {
|
|
var me = this;
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
// open a web socket
|
|
var conn = new WebSocket(url);
|
|
requestify(conn);
|
|
me.connections[url] = conn;
|
|
|
|
conn.onrequest = function (request) {
|
|
return me._onRequest(conn, request);
|
|
};
|
|
|
|
conn.onclose = function () {
|
|
if (me.connections[url]) {
|
|
// remove the connection from the list
|
|
delete me.connections[url];
|
|
|
|
// schedule reconnection
|
|
me._reconnect(url);
|
|
}
|
|
};
|
|
|
|
conn.onopen = function () {
|
|
// send a greeting with the hosts url
|
|
conn.request({method: 'greeting', params: { url: me.url, networkId: me.networkId } })
|
|
.then(function (params) {
|
|
me.networkId = params.networkId;
|
|
resolve(conn);
|
|
})
|
|
.catch(function (err) {
|
|
// greeting rejected
|
|
delete me.connections[url];
|
|
conn.close();
|
|
reject(err);
|
|
});
|
|
};
|
|
|
|
conn.onerror = function (err) {
|
|
delete me.connections[url];
|
|
reject(err);
|
|
conn.close();
|
|
};
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Reconnect with a host
|
|
* @param {String} url Url of the host to which to reconnect
|
|
* @private
|
|
*/
|
|
Host.prototype._reconnect = function (url) {
|
|
var me = this;
|
|
var start = new Date().valueOf();
|
|
|
|
function scheduleReconnect(delay, trial) {
|
|
me.timers[url] = setTimeout(function () {
|
|
delete me.timers[url];
|
|
|
|
var now = new Date().valueOf();
|
|
if (now - start < me.options.reconnectTimeout) {
|
|
// reconnect
|
|
me._connect(url)
|
|
.catch(function (err) {
|
|
// schedule next reconnect trial
|
|
scheduleReconnect(delay / me.options.reconnectDecay, trial + 1);
|
|
});
|
|
}
|
|
else {
|
|
// give up trying to reconnect
|
|
me._forgetPeers(url);
|
|
}
|
|
}, delay);
|
|
}
|
|
|
|
// schedule reconnection after a delay
|
|
scheduleReconnect(me.options.reconnectDelay, 0);
|
|
};
|
|
|
|
/**
|
|
* Forward a join message to all known hosts
|
|
* @param {string} url For example 'ws://localhost:3000'
|
|
* @return {Promise.<String[], Error>} returns the joined urls
|
|
*/
|
|
Host.prototype._broadcastJoin = function (url) {
|
|
// TODO: implement a more efficient broadcast mechanism
|
|
|
|
var me = this;
|
|
var urls = Object.keys(me.connections)
|
|
.filter(function (u) {
|
|
return u !== url
|
|
});
|
|
|
|
function join (existingUrl) {
|
|
var conn = me.connections[existingUrl];
|
|
return conn.request({method: 'join', params: {'url': url}})
|
|
.catch(function (err) {
|
|
// TODO: what to do with failed requests? Right now we ignore them
|
|
})
|
|
.then(function () {
|
|
// return the url where the join is broadcasted to
|
|
return existingUrl;
|
|
})
|
|
}
|
|
|
|
// send a join request to all known hosts
|
|
return Promise.all(urls.map(join));
|
|
};
|
|
|
|
/**
|
|
* Stop listening on currently a socket
|
|
* @return {Promise.<Host, Error>} Returns itself
|
|
*/
|
|
Host.prototype.close = function () {
|
|
var me = this;
|
|
|
|
// TODO: create a flag while closing? and opening?
|
|
if (this.server) {
|
|
// close the host, and clean up cache
|
|
function closeHost() {
|
|
// close the host itself
|
|
me.addresses = {};
|
|
|
|
if (me.server) {
|
|
me.server.close();
|
|
me.server = null;
|
|
me.address = null;
|
|
me.port = null;
|
|
me.url = null;
|
|
}
|
|
|
|
return me;
|
|
}
|
|
|
|
// close all connections
|
|
var urls = Object.keys(this.connections);
|
|
return Promise.all(urls.map(function (url) {
|
|
return me._disconnect(url);
|
|
})).then(closeHost);
|
|
}
|
|
else {
|
|
// no socket open. resolve immediately
|
|
Promise.resolve(this);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Close the connection with a host. Note: peers are not removed from cache
|
|
* @param {string} url Url of a connected host
|
|
* @return {Promise.<undefined, Error>} Resolves a promise when closed
|
|
* @private
|
|
*/
|
|
Host.prototype._disconnect = function (url) {
|
|
var conn = this.connections[url];
|
|
if (conn) {
|
|
delete this.connections[url];
|
|
|
|
if (this.timers[url]) {
|
|
clearTimeout(this.timers[url]);
|
|
delete this.timers[url];
|
|
}
|
|
|
|
// send a goodbye message
|
|
return conn.request({method: 'goodbye'})
|
|
.catch(function (err) {
|
|
// ignore failing to send goodbye
|
|
})
|
|
|
|
// then close the connection
|
|
.then(function () {
|
|
conn.close();
|
|
});
|
|
}
|
|
else {
|
|
Promise.resolve();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Publish a message via a channel. All listeners subscribed to this channel
|
|
* will be triggered, both listeners on this host as well as connected hosts.
|
|
* @param {string} channel The name of the channel
|
|
* @param {*} message A message, can be any type. Must be serializable JSON.
|
|
*/
|
|
Host.prototype.publish = function (channel, message) {
|
|
// trigger local subscribers
|
|
this._publish(channel, message);
|
|
|
|
// send the message to all connected hosts
|
|
for (var url in this.connections) {
|
|
if (this.connections.hasOwnProperty(url)) {
|
|
var connection = this.connections[url];
|
|
connection.notify({
|
|
method: 'publish',
|
|
params: {
|
|
channel: channel,
|
|
message: message
|
|
}
|
|
});
|
|
}
|
|
}
|
|
// TODO: improve efficiency by having the hosts share the channels for which
|
|
// they have subscribers, so we only have to send a message to a
|
|
// particular host when it has subscribers to the channel.
|
|
};
|
|
|
|
/**
|
|
* Publish a channel to all subscribers on this host.
|
|
* @param {string} channel The name of the channel
|
|
* @param {*} message A message, can be any type. Must be serializable JSON.
|
|
* @private
|
|
*/
|
|
Host.prototype._publish = function (channel, message) {
|
|
// trigger local subscribers
|
|
var callbacks = this.channels[channel];
|
|
if (callbacks) {
|
|
callbacks.forEach(function (callback) {
|
|
callback(message);
|
|
});
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Subscribe to a channel.
|
|
* @param {string} channel The name of the channel
|
|
* @param {function} callback Called as callback(message)
|
|
*/
|
|
Host.prototype.subscribe = function (channel, callback) {
|
|
// TODO: implement support for wildcards, like subscribing to "foo.*" or something like that
|
|
var callbacks = this.channels[channel];
|
|
if (!callbacks) {
|
|
callbacks = [];
|
|
this.channels[channel] = callbacks;
|
|
}
|
|
callbacks.push(callback);
|
|
};
|
|
|
|
/**
|
|
* Unsubscribe from a channel.
|
|
* @param {string} channel The name of the channel
|
|
* @param {function} callback A callback used before to subscribe
|
|
*/
|
|
Host.prototype.unsubscribe = function (channel, callback) {
|
|
var callbacks = this.channels[channel];
|
|
if (callbacks) {
|
|
var index = callbacks.indexOf(callback);
|
|
if (index !== -1) {
|
|
callbacks.splice(index, 1);
|
|
if (callbacks.length === 0) {
|
|
delete this.channels[channel];
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Merge object b into object a: copy all properties of b to a
|
|
* @param {Object} a
|
|
* @param {Object} b
|
|
* @return {Object} returns the merged a
|
|
* @private
|
|
*/
|
|
function _merge (a, b) {
|
|
for (var prop in b) {
|
|
if (b.hasOwnProperty(prop)) {
|
|
a[prop] = b[prop];
|
|
}
|
|
}
|
|
return a;
|
|
}
|
|
|
|
/**
|
|
* Create an Error "Peer not found"
|
|
* @param {string} id The id of the peer
|
|
* @return {Error}
|
|
* @private
|
|
*/
|
|
function _peerNotFoundError(id) {
|
|
return new Error('Peer not found (id: ' + id + ')');
|
|
}
|
|
|
|
/**
|
|
* Create an Error "Peer unreachable"
|
|
* @param {string} id The id of the peer
|
|
* @param {string} url Url of the peers host
|
|
* @return {Error}
|
|
* @private
|
|
*/
|
|
function _peerUnreachable(id, url) {
|
|
return new Error('Peer unreachable (id: ' + id + ', url: ' + url + ')');
|
|
}
|
|
|
|
// TODO: implement a function list() which returns the id's of all peers in the system
|
|
|
|
module.exports = Host;
|
|
|
|
},{"./Peer":69,"./Promise":70,"./requestify":71,"node-uuid":113,"ws":109}],69:[function(_dereq_,module,exports){
|
|
//var Emitter = require('emitter-component');
|
|
|
|
|
|
/**
|
|
* Peer
|
|
* A peer can send and receive messages via a connected message bus
|
|
* @param {string} id
|
|
* @param {function(string, string, *)} send A function to send a message to an other peer
|
|
*/
|
|
function Peer(id, send) {
|
|
this.id = id;
|
|
this._send = send;
|
|
|
|
this.listeners = {};
|
|
}
|
|
|
|
/**
|
|
* Send a message to another peer
|
|
* @param {string} to Id of the recipient
|
|
* @param {*} message Message to be send, can be JSON
|
|
* @returns {Promise.<null, Error>} Resolves when sent
|
|
*/
|
|
Peer.prototype.send = function (to, message) {
|
|
return this._send(this.id, to, message);
|
|
};
|
|
|
|
// Extend the Peer with event emitter functionality
|
|
//Emitter(Peer.prototype);
|
|
|
|
// TODO: complete this custom event emitter, it's about 5 times as fast as Emitter because its not slicing arguments
|
|
|
|
/**
|
|
* Register an event listener
|
|
* @param {string} event Available events: 'message'
|
|
* @param {Function} callback Callback function, called as callback(from, message)
|
|
*/
|
|
Peer.prototype.on = function (event, callback) {
|
|
if (!(event in this.listeners)) this.listeners[event] = [];
|
|
this.listeners[event].push(callback);
|
|
};
|
|
|
|
// TODO: implement off
|
|
|
|
/**
|
|
* Emit an event
|
|
* @param {string} event For example 'message'
|
|
* @param {string} from Id of the sender, for example 'peer1'
|
|
* @param {*} message A message, can be any type. Must be serializable JSON.
|
|
*/
|
|
Peer.prototype.emit = function (event, from, message) {
|
|
var listeners = this.listeners[event];
|
|
if (listeners) {
|
|
for (var i = 0, ii = listeners.length; i < ii; i++) {
|
|
var listener = listeners[i];
|
|
listener(from, message);
|
|
}
|
|
}
|
|
};
|
|
|
|
module.exports = Peer;
|
|
|
|
},{}],70:[function(_dereq_,module,exports){
|
|
// Return a promise implementation.
|
|
module.exports = _dereq_('bluebird');
|
|
|
|
},{"bluebird":74}],71:[function(_dereq_,module,exports){
|
|
var uuid = _dereq_('node-uuid'),
|
|
Promise = _dereq_('./Promise');
|
|
|
|
var TIMEOUT = 60000; // ms
|
|
// TODO: make timeout a configuration setting
|
|
|
|
/**
|
|
* Wrap a socket in a request/response handling layer.
|
|
* Requests are wrapped in an envelope with id and data, and responses
|
|
* are packed in an envelope with this same id and response data.
|
|
*
|
|
* The socket is extended with functions:
|
|
* request(data: *) : Promise.<*, Error>
|
|
* onrequest(data: *) : Promise.<*, Error>
|
|
*
|
|
* @param {WebSocket} socket
|
|
* @return {WebSocket} requestified socket
|
|
*/
|
|
function requestify (socket) {
|
|
return (function () {
|
|
var queue = {}; // queue with requests in progress
|
|
|
|
if ('request' in socket) {
|
|
throw new Error('Socket already has a request property');
|
|
}
|
|
|
|
var requestified = socket;
|
|
|
|
/**
|
|
* Event handler, handles incoming messages
|
|
* @param {Object} event
|
|
*/
|
|
socket.onmessage = function (event) {
|
|
var data = event.data;
|
|
if (data.charAt(0) == '{') {
|
|
var envelope = JSON.parse(data);
|
|
|
|
// match the request from the id in the response
|
|
var request = queue[envelope.id];
|
|
if (request) {
|
|
// handle an incoming response
|
|
clearTimeout(request.timeout);
|
|
delete queue[envelope.id];
|
|
|
|
// resolve the promise with response data
|
|
if (envelope.error) {
|
|
// TODO: implement a smarter way to serialize and deserialize errors
|
|
request.reject(new Error(envelope.error));
|
|
}
|
|
else {
|
|
request.resolve(envelope.message);
|
|
}
|
|
}
|
|
else {
|
|
if ('id' in envelope) {
|
|
try {
|
|
// handle an incoming request
|
|
requestified.onrequest(envelope.message)
|
|
.then(function (message) {
|
|
var response = {
|
|
id: envelope.id,
|
|
message: message,
|
|
error: null
|
|
};
|
|
socket.send(JSON.stringify(response));
|
|
})
|
|
.catch(function (error) {
|
|
var response = {
|
|
id: envelope.id,
|
|
message: null,
|
|
error: error.message || error.toString()
|
|
};
|
|
socket.send(JSON.stringify(response));
|
|
});
|
|
}
|
|
catch (err) {
|
|
var response = {
|
|
id: envelope.id,
|
|
message: null,
|
|
error: err.message || err.toString()
|
|
};
|
|
socket.send(JSON.stringify(response));
|
|
}
|
|
}
|
|
else {
|
|
// handle incoming notification (we don't do anything with the response)
|
|
requestified.onrequest(envelope.message);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Send a request
|
|
* @param {*} message
|
|
* @returns {Promise.<*, Error>} Returns a promise resolving with the response message
|
|
*/
|
|
requestified.request = function (message) {
|
|
return new Promise(function (resolve, reject) {
|
|
// put the data in an envelope with id
|
|
var id = uuid.v1();
|
|
var envelope = {
|
|
id: id,
|
|
message: message
|
|
};
|
|
|
|
// add the request to the list with requests in progress
|
|
queue[id] = {
|
|
resolve: resolve,
|
|
reject: reject,
|
|
timeout: setTimeout(function () {
|
|
delete queue[id];
|
|
reject(new Error('Timeout'));
|
|
}, TIMEOUT)
|
|
};
|
|
|
|
socket.send(JSON.stringify(envelope));
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Send a notification. A notification does not receive a response.
|
|
* @param {*} message
|
|
* @returns {Promise.<null, Error>} Returns a promise resolving with the null
|
|
* when the notification has been sent.
|
|
*/
|
|
requestified.notify = function (message) {
|
|
return new Promise(function (resolve, reject) {
|
|
// put the data in an envelope
|
|
var envelope = {
|
|
// we don't add an id, so we send this as notification instead of a request
|
|
message: message
|
|
};
|
|
|
|
socket.send(JSON.stringify(envelope), function () {
|
|
resolve(null);
|
|
});
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Handle an incoming request.
|
|
* @param {*} message Request message
|
|
* @returns {Promise.<*, Error>} Resolves with a response message
|
|
*/
|
|
requestified.onrequest = function (message) {
|
|
// this function must be implemented by the socket
|
|
return Promise.reject('No onrequest handler implemented');
|
|
};
|
|
|
|
// TODO: disable send and onmessage on the requestified socket
|
|
|
|
return requestified;
|
|
})();
|
|
}
|
|
|
|
module.exports = requestify;
|
|
|
|
},{"./Promise":70,"node-uuid":113}],72:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, Promise$_CreatePromiseArray, PromiseArray) {
|
|
|
|
var SomePromiseArray = _dereq_("./some_promise_array.js")(PromiseArray);
|
|
function Promise$_Any(promises, useBound) {
|
|
var ret = Promise$_CreatePromiseArray(
|
|
promises,
|
|
SomePromiseArray,
|
|
useBound === true && promises._isBound()
|
|
? promises._boundTo
|
|
: void 0
|
|
);
|
|
var promise = ret.promise();
|
|
if (promise.isRejected()) {
|
|
return promise;
|
|
}
|
|
ret.setHowMany(1);
|
|
ret.setUnwrap();
|
|
ret.init();
|
|
return promise;
|
|
}
|
|
|
|
Promise.any = function Promise$Any(promises) {
|
|
return Promise$_Any(promises, false);
|
|
};
|
|
|
|
Promise.prototype.any = function Promise$any() {
|
|
return Promise$_Any(this, true);
|
|
};
|
|
|
|
};
|
|
|
|
},{"./some_promise_array.js":104}],73:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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 schedule = _dereq_("./schedule.js");
|
|
var Queue = _dereq_("./queue.js");
|
|
var errorObj = _dereq_("./util.js").errorObj;
|
|
var tryCatch1 = _dereq_("./util.js").tryCatch1;
|
|
var process = _dereq_("./global.js").process;
|
|
|
|
function Async() {
|
|
this._isTickUsed = false;
|
|
this._length = 0;
|
|
this._lateBuffer = new Queue();
|
|
this._functionBuffer = new Queue(25000 * 3);
|
|
var self = this;
|
|
this.consumeFunctionBuffer = function Async$consumeFunctionBuffer() {
|
|
self._consumeFunctionBuffer();
|
|
};
|
|
}
|
|
|
|
Async.prototype.haveItemsQueued = function Async$haveItemsQueued() {
|
|
return this._length > 0;
|
|
};
|
|
|
|
Async.prototype.invokeLater = function Async$invokeLater(fn, receiver, arg) {
|
|
if (process !== void 0 &&
|
|
process.domain != null &&
|
|
!fn.domain) {
|
|
fn = process.domain.bind(fn);
|
|
}
|
|
this._lateBuffer.push(fn, receiver, arg);
|
|
this._queueTick();
|
|
};
|
|
|
|
Async.prototype.invoke = function Async$invoke(fn, receiver, arg) {
|
|
if (process !== void 0 &&
|
|
process.domain != null &&
|
|
!fn.domain) {
|
|
fn = process.domain.bind(fn);
|
|
}
|
|
var functionBuffer = this._functionBuffer;
|
|
functionBuffer.push(fn, receiver, arg);
|
|
this._length = functionBuffer.length();
|
|
this._queueTick();
|
|
};
|
|
|
|
Async.prototype._consumeFunctionBuffer =
|
|
function Async$_consumeFunctionBuffer() {
|
|
var functionBuffer = this._functionBuffer;
|
|
while(functionBuffer.length() > 0) {
|
|
var fn = functionBuffer.shift();
|
|
var receiver = functionBuffer.shift();
|
|
var arg = functionBuffer.shift();
|
|
fn.call(receiver, arg);
|
|
}
|
|
this._reset();
|
|
this._consumeLateBuffer();
|
|
};
|
|
|
|
Async.prototype._consumeLateBuffer = function Async$_consumeLateBuffer() {
|
|
var buffer = this._lateBuffer;
|
|
while(buffer.length() > 0) {
|
|
var fn = buffer.shift();
|
|
var receiver = buffer.shift();
|
|
var arg = buffer.shift();
|
|
var res = tryCatch1(fn, receiver, arg);
|
|
if (res === errorObj) {
|
|
this._queueTick();
|
|
if (fn.domain != null) {
|
|
fn.domain.emit("error", res.e);
|
|
}
|
|
else {
|
|
throw res.e;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
Async.prototype._queueTick = function Async$_queue() {
|
|
if (!this._isTickUsed) {
|
|
schedule(this.consumeFunctionBuffer);
|
|
this._isTickUsed = true;
|
|
}
|
|
};
|
|
|
|
Async.prototype._reset = function Async$_reset() {
|
|
this._isTickUsed = false;
|
|
this._length = 0;
|
|
};
|
|
|
|
module.exports = new Async();
|
|
|
|
},{"./global.js":86,"./queue.js":97,"./schedule.js":100,"./util.js":108}],74:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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 Promise = _dereq_("./promise.js")();
|
|
module.exports = Promise;
|
|
},{"./promise.js":90}],75:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise) {
|
|
Promise.prototype.call = function Promise$call(propertyName) {
|
|
var $_len = arguments.length;var args = new Array($_len - 1); for(var $_i = 1; $_i < $_len; ++$_i) {args[$_i - 1] = arguments[$_i];}
|
|
|
|
return this._then(function(obj) {
|
|
return obj[propertyName].apply(obj, args);
|
|
},
|
|
void 0,
|
|
void 0,
|
|
void 0,
|
|
void 0
|
|
);
|
|
};
|
|
|
|
function Promise$getter(obj) {
|
|
var prop = typeof this === "string"
|
|
? this
|
|
: ("" + this);
|
|
return obj[prop];
|
|
}
|
|
Promise.prototype.get = function Promise$get(propertyName) {
|
|
return this._then(
|
|
Promise$getter,
|
|
void 0,
|
|
void 0,
|
|
propertyName,
|
|
void 0
|
|
);
|
|
};
|
|
};
|
|
|
|
},{}],76:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, INTERNAL) {
|
|
var errors = _dereq_("./errors.js");
|
|
var async = _dereq_("./async.js");
|
|
var CancellationError = errors.CancellationError;
|
|
|
|
Promise.prototype._cancel = function Promise$_cancel() {
|
|
if (!this.isCancellable()) return this;
|
|
var parent;
|
|
var promiseToReject = this;
|
|
while ((parent = promiseToReject._cancellationParent) !== void 0 &&
|
|
parent.isCancellable()) {
|
|
promiseToReject = parent;
|
|
}
|
|
var err = new CancellationError();
|
|
promiseToReject._attachExtraTrace(err);
|
|
promiseToReject._rejectUnchecked(err);
|
|
};
|
|
|
|
Promise.prototype.cancel = function Promise$cancel() {
|
|
if (!this.isCancellable()) return this;
|
|
async.invokeLater(this._cancel, this, void 0);
|
|
return this;
|
|
};
|
|
|
|
Promise.prototype.cancellable = function Promise$cancellable() {
|
|
if (this._cancellable()) return this;
|
|
this._setCancellable();
|
|
this._cancellationParent = void 0;
|
|
return this;
|
|
};
|
|
|
|
Promise.prototype.uncancellable = function Promise$uncancellable() {
|
|
var ret = new Promise(INTERNAL);
|
|
ret._setTrace(this);
|
|
ret._follow(this);
|
|
ret._unsetCancellable();
|
|
if (this._isBound()) ret._setBoundTo(this._boundTo);
|
|
return ret;
|
|
};
|
|
|
|
Promise.prototype.fork =
|
|
function Promise$fork(didFulfill, didReject, didProgress) {
|
|
var ret = this._then(didFulfill, didReject, didProgress,
|
|
void 0, void 0);
|
|
|
|
ret._setCancellable();
|
|
ret._cancellationParent = void 0;
|
|
return ret;
|
|
};
|
|
};
|
|
|
|
},{"./async.js":73,"./errors.js":80}],77:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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() {
|
|
var inherits = _dereq_("./util.js").inherits;
|
|
var defineProperty = _dereq_("./es5.js").defineProperty;
|
|
|
|
var rignore = new RegExp(
|
|
"\\b(?:[a-zA-Z0-9.]+\\$_\\w+|" +
|
|
"tryCatch(?:1|2|Apply)|new \\w*PromiseArray|" +
|
|
"\\w*PromiseArray\\.\\w*PromiseArray|" +
|
|
"setTimeout|CatchFilter\\$_\\w+|makeNodePromisified|processImmediate|" +
|
|
"process._tickCallback|nextTick|Async\\$\\w+)\\b"
|
|
);
|
|
|
|
var rtraceline = null;
|
|
var formatStack = null;
|
|
|
|
function formatNonError(obj) {
|
|
var str;
|
|
if (typeof obj === "function") {
|
|
str = "[function " +
|
|
(obj.name || "anonymous") +
|
|
"]";
|
|
}
|
|
else {
|
|
str = obj.toString();
|
|
var ruselessToString = /\[object [a-zA-Z0-9$_]+\]/;
|
|
if (ruselessToString.test(str)) {
|
|
try {
|
|
var newStr = JSON.stringify(obj);
|
|
str = newStr;
|
|
}
|
|
catch(e) {
|
|
|
|
}
|
|
}
|
|
if (str.length === 0) {
|
|
str = "(empty array)";
|
|
}
|
|
}
|
|
return ("(<" + snip(str) + ">, no stack trace)");
|
|
}
|
|
|
|
function snip(str) {
|
|
var maxChars = 41;
|
|
if (str.length < maxChars) {
|
|
return str;
|
|
}
|
|
return str.substr(0, maxChars - 3) + "...";
|
|
}
|
|
|
|
function CapturedTrace(ignoreUntil, isTopLevel) {
|
|
this.captureStackTrace(CapturedTrace, isTopLevel);
|
|
|
|
}
|
|
inherits(CapturedTrace, Error);
|
|
|
|
CapturedTrace.prototype.captureStackTrace =
|
|
function CapturedTrace$captureStackTrace(ignoreUntil, isTopLevel) {
|
|
captureStackTrace(this, ignoreUntil, isTopLevel);
|
|
};
|
|
|
|
CapturedTrace.possiblyUnhandledRejection =
|
|
function CapturedTrace$PossiblyUnhandledRejection(reason) {
|
|
if (typeof console === "object") {
|
|
var message;
|
|
if (typeof reason === "object" || typeof reason === "function") {
|
|
var stack = reason.stack;
|
|
message = "Possibly unhandled " + formatStack(stack, reason);
|
|
}
|
|
else {
|
|
message = "Possibly unhandled " + String(reason);
|
|
}
|
|
if (typeof console.error === "function" ||
|
|
typeof console.error === "object") {
|
|
console.error(message);
|
|
}
|
|
else if (typeof console.log === "function" ||
|
|
typeof console.log === "object") {
|
|
console.log(message);
|
|
}
|
|
}
|
|
};
|
|
|
|
CapturedTrace.combine = function CapturedTrace$Combine(current, prev) {
|
|
var curLast = current.length - 1;
|
|
for (var i = prev.length - 1; i >= 0; --i) {
|
|
var line = prev[i];
|
|
if (current[curLast] === line) {
|
|
current.pop();
|
|
curLast--;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
current.push("From previous event:");
|
|
var lines = current.concat(prev);
|
|
|
|
var ret = [];
|
|
|
|
for (var i = 0, len = lines.length; i < len; ++i) {
|
|
|
|
if ((rignore.test(lines[i]) ||
|
|
(i > 0 && !rtraceline.test(lines[i])) &&
|
|
lines[i] !== "From previous event:")
|
|
) {
|
|
continue;
|
|
}
|
|
ret.push(lines[i]);
|
|
}
|
|
return ret;
|
|
};
|
|
|
|
CapturedTrace.isSupported = function CapturedTrace$IsSupported() {
|
|
return typeof captureStackTrace === "function";
|
|
};
|
|
|
|
var captureStackTrace = (function stackDetection() {
|
|
if (typeof Error.stackTraceLimit === "number" &&
|
|
typeof Error.captureStackTrace === "function") {
|
|
rtraceline = /^\s*at\s*/;
|
|
formatStack = function(stack, error) {
|
|
if (typeof stack === "string") return stack;
|
|
|
|
if (error.name !== void 0 &&
|
|
error.message !== void 0) {
|
|
return error.name + ". " + error.message;
|
|
}
|
|
return formatNonError(error);
|
|
|
|
|
|
};
|
|
var captureStackTrace = Error.captureStackTrace;
|
|
return function CapturedTrace$_captureStackTrace(
|
|
receiver, ignoreUntil) {
|
|
captureStackTrace(receiver, ignoreUntil);
|
|
};
|
|
}
|
|
var err = new Error();
|
|
|
|
if (typeof err.stack === "string" &&
|
|
typeof "".startsWith === "function" &&
|
|
(err.stack.startsWith("stackDetection@")) &&
|
|
stackDetection.name === "stackDetection") {
|
|
|
|
defineProperty(Error, "stackTraceLimit", {
|
|
writable: true,
|
|
enumerable: false,
|
|
configurable: false,
|
|
value: 25
|
|
});
|
|
rtraceline = /@/;
|
|
var rline = /[@\n]/;
|
|
|
|
formatStack = function(stack, error) {
|
|
if (typeof stack === "string") {
|
|
return (error.name + ". " + error.message + "\n" + stack);
|
|
}
|
|
|
|
if (error.name !== void 0 &&
|
|
error.message !== void 0) {
|
|
return error.name + ". " + error.message;
|
|
}
|
|
return formatNonError(error);
|
|
};
|
|
|
|
return function captureStackTrace(o) {
|
|
var stack = new Error().stack;
|
|
var split = stack.split(rline);
|
|
var len = split.length;
|
|
var ret = "";
|
|
for (var i = 0; i < len; i += 2) {
|
|
ret += split[i];
|
|
ret += "@";
|
|
ret += split[i + 1];
|
|
ret += "\n";
|
|
}
|
|
o.stack = ret;
|
|
};
|
|
}
|
|
else {
|
|
formatStack = function(stack, error) {
|
|
if (typeof stack === "string") return stack;
|
|
|
|
if ((typeof error === "object" ||
|
|
typeof error === "function") &&
|
|
error.name !== void 0 &&
|
|
error.message !== void 0) {
|
|
return error.name + ". " + error.message;
|
|
}
|
|
return formatNonError(error);
|
|
};
|
|
|
|
return null;
|
|
}
|
|
})();
|
|
|
|
return CapturedTrace;
|
|
};
|
|
|
|
},{"./es5.js":82,"./util.js":108}],78:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(NEXT_FILTER) {
|
|
var util = _dereq_("./util.js");
|
|
var errors = _dereq_("./errors.js");
|
|
var tryCatch1 = util.tryCatch1;
|
|
var errorObj = util.errorObj;
|
|
var keys = _dereq_("./es5.js").keys;
|
|
var TypeError = errors.TypeError;
|
|
|
|
function CatchFilter(instances, callback, promise) {
|
|
this._instances = instances;
|
|
this._callback = callback;
|
|
this._promise = promise;
|
|
}
|
|
|
|
function CatchFilter$_safePredicate(predicate, e) {
|
|
var safeObject = {};
|
|
var retfilter = tryCatch1(predicate, safeObject, e);
|
|
|
|
if (retfilter === errorObj) return retfilter;
|
|
|
|
var safeKeys = keys(safeObject);
|
|
if (safeKeys.length) {
|
|
errorObj.e = new TypeError(
|
|
"Catch filter must inherit from Error "
|
|
+ "or be a simple predicate function");
|
|
return errorObj;
|
|
}
|
|
return retfilter;
|
|
}
|
|
|
|
CatchFilter.prototype.doFilter = function CatchFilter$_doFilter(e) {
|
|
var cb = this._callback;
|
|
var promise = this._promise;
|
|
var boundTo = promise._isBound() ? promise._boundTo : void 0;
|
|
for (var i = 0, len = this._instances.length; i < len; ++i) {
|
|
var item = this._instances[i];
|
|
var itemIsErrorType = item === Error ||
|
|
(item != null && item.prototype instanceof Error);
|
|
|
|
if (itemIsErrorType && e instanceof item) {
|
|
var ret = tryCatch1(cb, boundTo, e);
|
|
if (ret === errorObj) {
|
|
NEXT_FILTER.e = ret.e;
|
|
return NEXT_FILTER;
|
|
}
|
|
return ret;
|
|
} else if (typeof item === "function" && !itemIsErrorType) {
|
|
var shouldHandle = CatchFilter$_safePredicate(item, e);
|
|
if (shouldHandle === errorObj) {
|
|
var trace = errors.canAttach(errorObj.e)
|
|
? errorObj.e
|
|
: new Error(errorObj.e + "");
|
|
this._promise._attachExtraTrace(trace);
|
|
e = errorObj.e;
|
|
break;
|
|
} else if (shouldHandle) {
|
|
var ret = tryCatch1(cb, boundTo, e);
|
|
if (ret === errorObj) {
|
|
NEXT_FILTER.e = ret.e;
|
|
return NEXT_FILTER;
|
|
}
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
NEXT_FILTER.e = e;
|
|
return NEXT_FILTER;
|
|
};
|
|
|
|
return CatchFilter;
|
|
};
|
|
|
|
},{"./errors.js":80,"./es5.js":82,"./util.js":108}],79:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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 util = _dereq_("./util.js");
|
|
var isPrimitive = util.isPrimitive;
|
|
var wrapsPrimitiveReceiver = util.wrapsPrimitiveReceiver;
|
|
|
|
module.exports = function(Promise) {
|
|
var returner = function Promise$_returner() {
|
|
return this;
|
|
};
|
|
var thrower = function Promise$_thrower() {
|
|
throw this;
|
|
};
|
|
|
|
var wrapper = function Promise$_wrapper(value, action) {
|
|
if (action === 1) {
|
|
return function Promise$_thrower() {
|
|
throw value;
|
|
};
|
|
}
|
|
else if (action === 2) {
|
|
return function Promise$_returner() {
|
|
return value;
|
|
};
|
|
}
|
|
};
|
|
|
|
|
|
Promise.prototype["return"] =
|
|
Promise.prototype.thenReturn =
|
|
function Promise$thenReturn(value) {
|
|
if (wrapsPrimitiveReceiver && isPrimitive(value)) {
|
|
return this._then(
|
|
wrapper(value, 2),
|
|
void 0,
|
|
void 0,
|
|
void 0,
|
|
void 0
|
|
);
|
|
}
|
|
return this._then(returner, void 0, void 0, value, void 0);
|
|
};
|
|
|
|
Promise.prototype["throw"] =
|
|
Promise.prototype.thenThrow =
|
|
function Promise$thenThrow(reason) {
|
|
if (wrapsPrimitiveReceiver && isPrimitive(reason)) {
|
|
return this._then(
|
|
wrapper(reason, 1),
|
|
void 0,
|
|
void 0,
|
|
void 0,
|
|
void 0
|
|
);
|
|
}
|
|
return this._then(thrower, void 0, void 0, reason, void 0);
|
|
};
|
|
};
|
|
|
|
},{"./util.js":108}],80:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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 global = _dereq_("./global.js");
|
|
var Objectfreeze = _dereq_("./es5.js").freeze;
|
|
var util = _dereq_("./util.js");
|
|
var inherits = util.inherits;
|
|
var notEnumerableProp = util.notEnumerableProp;
|
|
var Error = global.Error;
|
|
|
|
function markAsOriginatingFromRejection(e) {
|
|
try {
|
|
notEnumerableProp(e, "isAsync", true);
|
|
}
|
|
catch(ignore) {}
|
|
}
|
|
|
|
function originatesFromRejection(e) {
|
|
if (e == null) return false;
|
|
return ((e instanceof RejectionError) ||
|
|
e["isAsync"] === true);
|
|
}
|
|
|
|
function isError(obj) {
|
|
return obj instanceof Error;
|
|
}
|
|
|
|
function canAttach(obj) {
|
|
return isError(obj);
|
|
}
|
|
|
|
function subError(nameProperty, defaultMessage) {
|
|
function SubError(message) {
|
|
if (!(this instanceof SubError)) return new SubError(message);
|
|
this.message = typeof message === "string" ? message : defaultMessage;
|
|
this.name = nameProperty;
|
|
if (Error.captureStackTrace) {
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
}
|
|
inherits(SubError, Error);
|
|
return SubError;
|
|
}
|
|
|
|
var TypeError = global.TypeError;
|
|
if (typeof TypeError !== "function") {
|
|
TypeError = subError("TypeError", "type error");
|
|
}
|
|
var RangeError = global.RangeError;
|
|
if (typeof RangeError !== "function") {
|
|
RangeError = subError("RangeError", "range error");
|
|
}
|
|
var CancellationError = subError("CancellationError", "cancellation error");
|
|
var TimeoutError = subError("TimeoutError", "timeout error");
|
|
|
|
function RejectionError(message) {
|
|
this.name = "RejectionError";
|
|
this.message = message;
|
|
this.cause = message;
|
|
this.isAsync = true;
|
|
|
|
if (message instanceof Error) {
|
|
this.message = message.message;
|
|
this.stack = message.stack;
|
|
}
|
|
else if (Error.captureStackTrace) {
|
|
Error.captureStackTrace(this, this.constructor);
|
|
}
|
|
|
|
}
|
|
inherits(RejectionError, Error);
|
|
|
|
var key = "__BluebirdErrorTypes__";
|
|
var errorTypes = global[key];
|
|
if (!errorTypes) {
|
|
errorTypes = Objectfreeze({
|
|
CancellationError: CancellationError,
|
|
TimeoutError: TimeoutError,
|
|
RejectionError: RejectionError
|
|
});
|
|
notEnumerableProp(global, key, errorTypes);
|
|
}
|
|
|
|
module.exports = {
|
|
Error: Error,
|
|
TypeError: TypeError,
|
|
RangeError: RangeError,
|
|
CancellationError: errorTypes.CancellationError,
|
|
RejectionError: errorTypes.RejectionError,
|
|
TimeoutError: errorTypes.TimeoutError,
|
|
originatesFromRejection: originatesFromRejection,
|
|
markAsOriginatingFromRejection: markAsOriginatingFromRejection,
|
|
canAttach: canAttach
|
|
};
|
|
|
|
},{"./es5.js":82,"./global.js":86,"./util.js":108}],81:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise) {
|
|
var TypeError = _dereq_('./errors.js').TypeError;
|
|
|
|
function apiRejection(msg) {
|
|
var error = new TypeError(msg);
|
|
var ret = Promise.rejected(error);
|
|
var parent = ret._peekContext();
|
|
if (parent != null) {
|
|
parent._attachExtraTrace(error);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
return apiRejection;
|
|
};
|
|
|
|
},{"./errors.js":80}],82:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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 isES5 = (function(){
|
|
"use strict";
|
|
return this === void 0;
|
|
})();
|
|
|
|
if (isES5) {
|
|
module.exports = {
|
|
freeze: Object.freeze,
|
|
defineProperty: Object.defineProperty,
|
|
keys: Object.keys,
|
|
getPrototypeOf: Object.getPrototypeOf,
|
|
isArray: Array.isArray,
|
|
isES5: isES5
|
|
};
|
|
}
|
|
|
|
else {
|
|
var has = {}.hasOwnProperty;
|
|
var str = {}.toString;
|
|
var proto = {}.constructor.prototype;
|
|
|
|
var ObjectKeys = function ObjectKeys(o) {
|
|
var ret = [];
|
|
for (var key in o) {
|
|
if (has.call(o, key)) {
|
|
ret.push(key);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
var ObjectDefineProperty = function ObjectDefineProperty(o, key, desc) {
|
|
o[key] = desc.value;
|
|
return o;
|
|
}
|
|
|
|
var ObjectFreeze = function ObjectFreeze(obj) {
|
|
return obj;
|
|
}
|
|
|
|
var ObjectGetPrototypeOf = function ObjectGetPrototypeOf(obj) {
|
|
try {
|
|
return Object(obj).constructor.prototype;
|
|
}
|
|
catch (e) {
|
|
return proto;
|
|
}
|
|
}
|
|
|
|
var ArrayIsArray = function ArrayIsArray(obj) {
|
|
try {
|
|
return str.call(obj) === "[object Array]";
|
|
}
|
|
catch(e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
isArray: ArrayIsArray,
|
|
keys: ObjectKeys,
|
|
defineProperty: ObjectDefineProperty,
|
|
freeze: ObjectFreeze,
|
|
getPrototypeOf: ObjectGetPrototypeOf,
|
|
isES5: isES5
|
|
};
|
|
}
|
|
|
|
},{}],83:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise) {
|
|
var isArray = _dereq_("./util.js").isArray;
|
|
|
|
function Promise$_filter(booleans) {
|
|
var values = this instanceof Promise ? this._settledValue : this;
|
|
var len = values.length;
|
|
var ret = new Array(len);
|
|
var j = 0;
|
|
|
|
for (var i = 0; i < len; ++i) {
|
|
if (booleans[i]) ret[j++] = values[i];
|
|
|
|
}
|
|
ret.length = j;
|
|
return ret;
|
|
}
|
|
|
|
var ref = {ref: null};
|
|
Promise.filter = function Promise$Filter(promises, fn) {
|
|
return Promise.map(promises, fn, ref)
|
|
._then(Promise$_filter, void 0, void 0, ref.ref, void 0);
|
|
};
|
|
|
|
Promise.prototype.filter = function Promise$filter(fn) {
|
|
return this.map(fn, ref)
|
|
._then(Promise$_filter, void 0, void 0, ref.ref, void 0);
|
|
};
|
|
};
|
|
|
|
},{"./util.js":108}],84:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, NEXT_FILTER) {
|
|
var util = _dereq_("./util.js");
|
|
var wrapsPrimitiveReceiver = util.wrapsPrimitiveReceiver;
|
|
var isPrimitive = util.isPrimitive;
|
|
var thrower = util.thrower;
|
|
|
|
|
|
function returnThis() {
|
|
return this;
|
|
}
|
|
function throwThis() {
|
|
throw this;
|
|
}
|
|
function return$(r) {
|
|
return function Promise$_returner() {
|
|
return r;
|
|
};
|
|
}
|
|
function throw$(r) {
|
|
return function Promise$_thrower() {
|
|
throw r;
|
|
};
|
|
}
|
|
function promisedFinally(ret, reasonOrValue, isFulfilled) {
|
|
var then;
|
|
if (wrapsPrimitiveReceiver && isPrimitive(reasonOrValue)) {
|
|
then = isFulfilled ? return$(reasonOrValue) : throw$(reasonOrValue);
|
|
}
|
|
else {
|
|
then = isFulfilled ? returnThis : throwThis;
|
|
}
|
|
return ret._then(then, thrower, void 0, reasonOrValue, void 0);
|
|
}
|
|
|
|
function finallyHandler(reasonOrValue) {
|
|
var promise = this.promise;
|
|
var handler = this.handler;
|
|
|
|
var ret = promise._isBound()
|
|
? handler.call(promise._boundTo)
|
|
: handler();
|
|
|
|
if (ret !== void 0) {
|
|
var maybePromise = Promise._cast(ret, void 0);
|
|
if (maybePromise instanceof Promise) {
|
|
return promisedFinally(maybePromise, reasonOrValue,
|
|
promise.isFulfilled());
|
|
}
|
|
}
|
|
|
|
if (promise.isRejected()) {
|
|
NEXT_FILTER.e = reasonOrValue;
|
|
return NEXT_FILTER;
|
|
}
|
|
else {
|
|
return reasonOrValue;
|
|
}
|
|
}
|
|
|
|
function tapHandler(value) {
|
|
var promise = this.promise;
|
|
var handler = this.handler;
|
|
|
|
var ret = promise._isBound()
|
|
? handler.call(promise._boundTo, value)
|
|
: handler(value);
|
|
|
|
if (ret !== void 0) {
|
|
var maybePromise = Promise._cast(ret, void 0);
|
|
if (maybePromise instanceof Promise) {
|
|
return promisedFinally(maybePromise, value, true);
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
Promise.prototype._passThroughHandler =
|
|
function Promise$_passThroughHandler(handler, isFinally) {
|
|
if (typeof handler !== "function") return this.then();
|
|
|
|
var promiseAndHandler = {
|
|
promise: this,
|
|
handler: handler
|
|
};
|
|
|
|
return this._then(
|
|
isFinally ? finallyHandler : tapHandler,
|
|
isFinally ? finallyHandler : void 0, void 0,
|
|
promiseAndHandler, void 0);
|
|
};
|
|
|
|
Promise.prototype.lastly =
|
|
Promise.prototype["finally"] = function Promise$finally(handler) {
|
|
return this._passThroughHandler(handler, true);
|
|
};
|
|
|
|
Promise.prototype.tap = function Promise$tap(handler) {
|
|
return this._passThroughHandler(handler, false);
|
|
};
|
|
};
|
|
|
|
},{"./util.js":108}],85:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, apiRejection, INTERNAL) {
|
|
var PromiseSpawn = _dereq_("./promise_spawn.js")(Promise, INTERNAL);
|
|
var errors = _dereq_("./errors.js");
|
|
var TypeError = errors.TypeError;
|
|
var deprecated = _dereq_("./util.js").deprecated;
|
|
|
|
Promise.coroutine = function Promise$Coroutine(generatorFunction) {
|
|
if (typeof generatorFunction !== "function") {
|
|
throw new TypeError("generatorFunction must be a function");
|
|
}
|
|
var PromiseSpawn$ = PromiseSpawn;
|
|
return function () {
|
|
var generator = generatorFunction.apply(this, arguments);
|
|
var spawn = new PromiseSpawn$(void 0, void 0);
|
|
spawn._generator = generator;
|
|
spawn._next(void 0);
|
|
return spawn.promise();
|
|
};
|
|
};
|
|
|
|
Promise.coroutine.addYieldHandler = PromiseSpawn.addYieldHandler;
|
|
|
|
Promise.spawn = function Promise$Spawn(generatorFunction) {
|
|
deprecated("Promise.spawn is deprecated. Use Promise.coroutine instead.");
|
|
if (typeof generatorFunction !== "function") {
|
|
return apiRejection("generatorFunction must be a function");
|
|
}
|
|
var spawn = new PromiseSpawn(generatorFunction, this);
|
|
var ret = spawn.promise();
|
|
spawn._run(Promise.spawn);
|
|
return ret;
|
|
};
|
|
};
|
|
|
|
},{"./errors.js":80,"./promise_spawn.js":93,"./util.js":108}],86:[function(_dereq_,module,exports){
|
|
(function (global){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
module.exports = (function() {
|
|
if (this !== void 0) return this;
|
|
try {return global;}
|
|
catch(e) {}
|
|
try {return window;}
|
|
catch(e) {}
|
|
try {return self;}
|
|
catch(e) {}
|
|
})();
|
|
|
|
}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
|
},{}],87:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, PromiseArray, INTERNAL, apiRejection) {
|
|
|
|
var all = Promise.all;
|
|
var util = _dereq_("./util.js");
|
|
var canAttach = _dereq_("./errors.js").canAttach;
|
|
var isArray = util.isArray;
|
|
var _cast = Promise._cast;
|
|
|
|
function unpack(values) {
|
|
return Promise$_Map(values, this[0], this[1], this[2]);
|
|
}
|
|
|
|
function Promise$_Map(promises, fn, useBound, ref) {
|
|
if (typeof fn !== "function") {
|
|
return apiRejection("fn must be a function");
|
|
}
|
|
|
|
var receiver = void 0;
|
|
if (useBound === true) {
|
|
if (promises._isBound()) {
|
|
receiver = promises._boundTo;
|
|
}
|
|
}
|
|
else if (useBound !== false) {
|
|
receiver = useBound;
|
|
}
|
|
|
|
var shouldUnwrapItems = ref !== void 0;
|
|
if (shouldUnwrapItems) ref.ref = promises;
|
|
|
|
if (promises instanceof Promise) {
|
|
var pack = [fn, receiver, ref];
|
|
return promises._then(unpack, void 0, void 0, pack, void 0);
|
|
}
|
|
else if (!isArray(promises)) {
|
|
return apiRejection("expecting an array, a promise or a thenable");
|
|
}
|
|
|
|
var promise = new Promise(INTERNAL);
|
|
if (receiver !== void 0) promise._setBoundTo(receiver);
|
|
promise._setTrace(void 0);
|
|
|
|
var mapping = new Mapping(promise,
|
|
fn,
|
|
promises,
|
|
receiver,
|
|
shouldUnwrapItems);
|
|
mapping.init();
|
|
return promise;
|
|
}
|
|
|
|
var pending = {};
|
|
function Mapping(promise, callback, items, receiver, shouldUnwrapItems) {
|
|
this.shouldUnwrapItems = shouldUnwrapItems;
|
|
this.index = 0;
|
|
this.items = items;
|
|
this.callback = callback;
|
|
this.receiver = receiver;
|
|
this.promise = promise;
|
|
this.result = new Array(items.length);
|
|
}
|
|
util.inherits(Mapping, PromiseArray);
|
|
|
|
Mapping.prototype.init = function Mapping$init() {
|
|
var items = this.items;
|
|
var len = items.length;
|
|
var result = this.result;
|
|
var isRejected = false;
|
|
for (var i = 0; i < len; ++i) {
|
|
var maybePromise = _cast(items[i], void 0);
|
|
if (maybePromise instanceof Promise) {
|
|
if (maybePromise.isPending()) {
|
|
result[i] = pending;
|
|
maybePromise._proxyPromiseArray(this, i);
|
|
}
|
|
else if (maybePromise.isFulfilled()) {
|
|
result[i] = maybePromise.value();
|
|
}
|
|
else {
|
|
maybePromise._unsetRejectionIsUnhandled();
|
|
if (!isRejected) {
|
|
this.reject(maybePromise.reason());
|
|
isRejected = true;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
result[i] = maybePromise;
|
|
}
|
|
}
|
|
if (!isRejected) this.iterate();
|
|
};
|
|
|
|
Mapping.prototype.isResolved = function Mapping$isResolved() {
|
|
return this.promise === null;
|
|
};
|
|
|
|
Mapping.prototype._promiseProgressed =
|
|
function Mapping$_promiseProgressed(value) {
|
|
if (this.isResolved()) return;
|
|
this.promise._progress(value);
|
|
};
|
|
|
|
Mapping.prototype._promiseFulfilled =
|
|
function Mapping$_promiseFulfilled(value, index) {
|
|
if (this.isResolved()) return;
|
|
this.result[index] = value;
|
|
if (this.shouldUnwrapItems) this.items[index] = value;
|
|
if (this.index === index) this.iterate();
|
|
};
|
|
|
|
Mapping.prototype._promiseRejected =
|
|
function Mapping$_promiseRejected(reason) {
|
|
this.reject(reason);
|
|
};
|
|
|
|
Mapping.prototype.reject = function Mapping$reject(reason) {
|
|
if (this.isResolved()) return;
|
|
var trace = canAttach(reason) ? reason : new Error(reason + "");
|
|
this.promise._attachExtraTrace(trace);
|
|
this.promise._reject(reason, trace);
|
|
};
|
|
|
|
Mapping.prototype.iterate = function Mapping$iterate() {
|
|
var i = this.index;
|
|
var items = this.items;
|
|
var result = this.result;
|
|
var len = items.length;
|
|
var result = this.result;
|
|
var receiver = this.receiver;
|
|
var callback = this.callback;
|
|
|
|
for (; i < len; ++i) {
|
|
var value = result[i];
|
|
if (value === pending) {
|
|
this.index = i;
|
|
return;
|
|
}
|
|
try { result[i] = callback.call(receiver, value, i, len); }
|
|
catch (e) { return this.reject(e); }
|
|
}
|
|
this.promise._follow(all(result));
|
|
this.items = this.result = this.callback = this.promise = null;
|
|
};
|
|
|
|
Promise.prototype.map = function Promise$map(fn, ref) {
|
|
return Promise$_Map(this, fn, true, ref);
|
|
};
|
|
|
|
Promise.map = function Promise$Map(promises, fn, ref) {
|
|
return Promise$_Map(promises, fn, false, ref);
|
|
};
|
|
};
|
|
|
|
},{"./errors.js":80,"./util.js":108}],88:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise) {
|
|
var util = _dereq_("./util.js");
|
|
var async = _dereq_("./async.js");
|
|
var tryCatch2 = util.tryCatch2;
|
|
var tryCatch1 = util.tryCatch1;
|
|
var errorObj = util.errorObj;
|
|
|
|
function thrower(r) {
|
|
throw r;
|
|
}
|
|
|
|
function Promise$_successAdapter(val, receiver) {
|
|
var nodeback = this;
|
|
var ret = val === void 0
|
|
? tryCatch1(nodeback, receiver, null)
|
|
: tryCatch2(nodeback, receiver, null, val);
|
|
if (ret === errorObj) {
|
|
async.invokeLater(thrower, void 0, ret.e);
|
|
}
|
|
}
|
|
function Promise$_errorAdapter(reason, receiver) {
|
|
var nodeback = this;
|
|
var ret = tryCatch1(nodeback, receiver, reason);
|
|
if (ret === errorObj) {
|
|
async.invokeLater(thrower, void 0, ret.e);
|
|
}
|
|
}
|
|
|
|
Promise.prototype.nodeify = function Promise$nodeify(nodeback) {
|
|
if (typeof nodeback == "function") {
|
|
this._then(
|
|
Promise$_successAdapter,
|
|
Promise$_errorAdapter,
|
|
void 0,
|
|
nodeback,
|
|
this._isBound() ? this._boundTo : null
|
|
);
|
|
}
|
|
return this;
|
|
};
|
|
};
|
|
|
|
},{"./async.js":73,"./util.js":108}],89:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, isPromiseArrayProxy) {
|
|
var util = _dereq_("./util.js");
|
|
var async = _dereq_("./async.js");
|
|
var errors = _dereq_("./errors.js");
|
|
var tryCatch1 = util.tryCatch1;
|
|
var errorObj = util.errorObj;
|
|
|
|
Promise.prototype.progressed = function Promise$progressed(handler) {
|
|
return this._then(void 0, void 0, handler, void 0, void 0);
|
|
};
|
|
|
|
Promise.prototype._progress = function Promise$_progress(progressValue) {
|
|
if (this._isFollowingOrFulfilledOrRejected()) return;
|
|
this._progressUnchecked(progressValue);
|
|
|
|
};
|
|
|
|
Promise.prototype._progressHandlerAt =
|
|
function Promise$_progressHandlerAt(index) {
|
|
if (index === 0) return this._progressHandler0;
|
|
return this[index + 2 - 5];
|
|
};
|
|
|
|
Promise.prototype._doProgressWith =
|
|
function Promise$_doProgressWith(progression) {
|
|
var progressValue = progression.value;
|
|
var handler = progression.handler;
|
|
var promise = progression.promise;
|
|
var receiver = progression.receiver;
|
|
|
|
this._pushContext();
|
|
var ret = tryCatch1(handler, receiver, progressValue);
|
|
this._popContext();
|
|
|
|
if (ret === errorObj) {
|
|
if (ret.e != null &&
|
|
ret.e.name !== "StopProgressPropagation") {
|
|
var trace = errors.canAttach(ret.e)
|
|
? ret.e : new Error(ret.e + "");
|
|
promise._attachExtraTrace(trace);
|
|
promise._progress(ret.e);
|
|
}
|
|
}
|
|
else if (ret instanceof Promise) {
|
|
ret._then(promise._progress, null, null, promise, void 0);
|
|
}
|
|
else {
|
|
promise._progress(ret);
|
|
}
|
|
};
|
|
|
|
|
|
Promise.prototype._progressUnchecked =
|
|
function Promise$_progressUnchecked(progressValue) {
|
|
if (!this.isPending()) return;
|
|
var len = this._length();
|
|
var progress = this._progress;
|
|
for (var i = 0; i < len; i += 5) {
|
|
var handler = this._progressHandlerAt(i);
|
|
var promise = this._promiseAt(i);
|
|
if (!(promise instanceof Promise)) {
|
|
var receiver = this._receiverAt(i);
|
|
if (typeof handler === "function") {
|
|
handler.call(receiver, progressValue, promise);
|
|
}
|
|
else if (receiver instanceof Promise && receiver._isProxied()) {
|
|
receiver._progressUnchecked(progressValue);
|
|
}
|
|
else if (isPromiseArrayProxy(receiver, promise)) {
|
|
receiver._promiseProgressed(progressValue, promise);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (typeof handler === "function") {
|
|
async.invoke(this._doProgressWith, this, {
|
|
handler: handler,
|
|
promise: promise,
|
|
receiver: this._receiverAt(i),
|
|
value: progressValue
|
|
});
|
|
}
|
|
else {
|
|
async.invoke(progress, promise, progressValue);
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
},{"./async.js":73,"./errors.js":80,"./util.js":108}],90:[function(_dereq_,module,exports){
|
|
(function (process){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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() {
|
|
var global = _dereq_("./global.js");
|
|
var util = _dereq_("./util.js");
|
|
var async = _dereq_("./async.js");
|
|
var errors = _dereq_("./errors.js");
|
|
|
|
var INTERNAL = function(){};
|
|
var APPLY = {};
|
|
var NEXT_FILTER = {e: null};
|
|
|
|
var PromiseArray = _dereq_("./promise_array.js")(Promise, INTERNAL);
|
|
var CapturedTrace = _dereq_("./captured_trace.js")();
|
|
var CatchFilter = _dereq_("./catch_filter.js")(NEXT_FILTER);
|
|
var PromiseResolver = _dereq_("./promise_resolver.js");
|
|
|
|
var isArray = util.isArray;
|
|
|
|
var errorObj = util.errorObj;
|
|
var tryCatch1 = util.tryCatch1;
|
|
var tryCatch2 = util.tryCatch2;
|
|
var tryCatchApply = util.tryCatchApply;
|
|
var RangeError = errors.RangeError;
|
|
var TypeError = errors.TypeError;
|
|
var CancellationError = errors.CancellationError;
|
|
var TimeoutError = errors.TimeoutError;
|
|
var RejectionError = errors.RejectionError;
|
|
var originatesFromRejection = errors.originatesFromRejection;
|
|
var markAsOriginatingFromRejection = errors.markAsOriginatingFromRejection;
|
|
var canAttach = errors.canAttach;
|
|
var thrower = util.thrower;
|
|
var apiRejection = _dereq_("./errors_api_rejection")(Promise);
|
|
|
|
|
|
var makeSelfResolutionError = function Promise$_makeSelfResolutionError() {
|
|
return new TypeError("circular promise resolution chain");
|
|
};
|
|
|
|
function isPromise(obj) {
|
|
if (obj === void 0) return false;
|
|
return obj instanceof Promise;
|
|
}
|
|
|
|
function isPromiseArrayProxy(receiver, promiseSlotValue) {
|
|
if (receiver instanceof PromiseArray) {
|
|
return promiseSlotValue >= 0;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function Promise(resolver) {
|
|
if (typeof resolver !== "function") {
|
|
throw new TypeError("the promise constructor requires a resolver function");
|
|
}
|
|
if (this.constructor !== Promise) {
|
|
throw new TypeError("the promise constructor cannot be invoked directly");
|
|
}
|
|
this._bitField = 0;
|
|
this._fulfillmentHandler0 = void 0;
|
|
this._rejectionHandler0 = void 0;
|
|
this._promise0 = void 0;
|
|
this._receiver0 = void 0;
|
|
this._settledValue = void 0;
|
|
this._boundTo = void 0;
|
|
if (resolver !== INTERNAL) this._resolveFromResolver(resolver);
|
|
}
|
|
|
|
Promise.prototype.bind = function Promise$bind(thisArg) {
|
|
var ret = new Promise(INTERNAL);
|
|
ret._setTrace(this);
|
|
ret._follow(this);
|
|
ret._setBoundTo(thisArg);
|
|
if (this._cancellable()) {
|
|
ret._setCancellable();
|
|
ret._cancellationParent = this;
|
|
}
|
|
return ret;
|
|
};
|
|
|
|
Promise.prototype.toString = function Promise$toString() {
|
|
return "[object Promise]";
|
|
};
|
|
|
|
Promise.prototype.caught = Promise.prototype["catch"] =
|
|
function Promise$catch(fn) {
|
|
var len = arguments.length;
|
|
if (len > 1) {
|
|
var catchInstances = new Array(len - 1),
|
|
j = 0, i;
|
|
for (i = 0; i < len - 1; ++i) {
|
|
var item = arguments[i];
|
|
if (typeof item === "function") {
|
|
catchInstances[j++] = item;
|
|
}
|
|
else {
|
|
var catchFilterTypeError =
|
|
new TypeError(
|
|
"A catch filter must be an error constructor "
|
|
+ "or a filter function");
|
|
|
|
this._attachExtraTrace(catchFilterTypeError);
|
|
async.invoke(this._reject, this, catchFilterTypeError);
|
|
return;
|
|
}
|
|
}
|
|
catchInstances.length = j;
|
|
fn = arguments[i];
|
|
|
|
this._resetTrace();
|
|
var catchFilter = new CatchFilter(catchInstances, fn, this);
|
|
return this._then(void 0, catchFilter.doFilter, void 0,
|
|
catchFilter, void 0);
|
|
}
|
|
return this._then(void 0, fn, void 0, void 0, void 0);
|
|
};
|
|
|
|
Promise.prototype.then =
|
|
function Promise$then(didFulfill, didReject, didProgress) {
|
|
return this._then(didFulfill, didReject, didProgress,
|
|
void 0, void 0);
|
|
};
|
|
|
|
|
|
Promise.prototype.done =
|
|
function Promise$done(didFulfill, didReject, didProgress) {
|
|
var promise = this._then(didFulfill, didReject, didProgress,
|
|
void 0, void 0);
|
|
promise._setIsFinal();
|
|
};
|
|
|
|
Promise.prototype.spread = function Promise$spread(didFulfill, didReject) {
|
|
return this._then(didFulfill, didReject, void 0,
|
|
APPLY, void 0);
|
|
};
|
|
|
|
Promise.prototype.isCancellable = function Promise$isCancellable() {
|
|
return !this.isResolved() &&
|
|
this._cancellable();
|
|
};
|
|
|
|
Promise.prototype.toJSON = function Promise$toJSON() {
|
|
var ret = {
|
|
isFulfilled: false,
|
|
isRejected: false,
|
|
fulfillmentValue: void 0,
|
|
rejectionReason: void 0
|
|
};
|
|
if (this.isFulfilled()) {
|
|
ret.fulfillmentValue = this._settledValue;
|
|
ret.isFulfilled = true;
|
|
}
|
|
else if (this.isRejected()) {
|
|
ret.rejectionReason = this._settledValue;
|
|
ret.isRejected = true;
|
|
}
|
|
return ret;
|
|
};
|
|
|
|
Promise.prototype.all = function Promise$all() {
|
|
return Promise$_all(this, true);
|
|
};
|
|
|
|
|
|
Promise.is = isPromise;
|
|
|
|
function Promise$_all(promises, useBound) {
|
|
return Promise$_CreatePromiseArray(
|
|
promises,
|
|
PromiseArray,
|
|
useBound === true && promises._isBound()
|
|
? promises._boundTo
|
|
: void 0
|
|
).promise();
|
|
}
|
|
Promise.all = function Promise$All(promises) {
|
|
return Promise$_all(promises, false);
|
|
};
|
|
|
|
Promise.join = function Promise$Join() {
|
|
var $_len = arguments.length;var args = new Array($_len); for(var $_i = 0; $_i < $_len; ++$_i) {args[$_i] = arguments[$_i];}
|
|
return Promise$_CreatePromiseArray(args, PromiseArray, void 0).promise();
|
|
};
|
|
|
|
Promise.resolve = Promise.fulfilled =
|
|
function Promise$Resolve(value) {
|
|
var ret = new Promise(INTERNAL);
|
|
ret._setTrace(void 0);
|
|
if (ret._tryFollow(value)) {
|
|
return ret;
|
|
}
|
|
ret._cleanValues();
|
|
ret._setFulfilled();
|
|
ret._settledValue = value;
|
|
return ret;
|
|
};
|
|
|
|
Promise.reject = Promise.rejected = function Promise$Reject(reason) {
|
|
var ret = new Promise(INTERNAL);
|
|
ret._setTrace(void 0);
|
|
markAsOriginatingFromRejection(reason);
|
|
ret._cleanValues();
|
|
ret._setRejected();
|
|
ret._settledValue = reason;
|
|
if (!canAttach(reason)) {
|
|
var trace = new Error(reason + "");
|
|
ret._setCarriedStackTrace(trace);
|
|
}
|
|
ret._ensurePossibleRejectionHandled();
|
|
return ret;
|
|
};
|
|
|
|
Promise.prototype.error = function Promise$_error(fn) {
|
|
return this.caught(originatesFromRejection, fn);
|
|
};
|
|
|
|
Promise.prototype._resolveFromSyncValue =
|
|
function Promise$_resolveFromSyncValue(value) {
|
|
if (value === errorObj) {
|
|
this._cleanValues();
|
|
this._setRejected();
|
|
this._settledValue = value.e;
|
|
this._ensurePossibleRejectionHandled();
|
|
}
|
|
else {
|
|
var maybePromise = Promise._cast(value, void 0);
|
|
if (maybePromise instanceof Promise) {
|
|
this._follow(maybePromise);
|
|
}
|
|
else {
|
|
this._cleanValues();
|
|
this._setFulfilled();
|
|
this._settledValue = value;
|
|
}
|
|
}
|
|
};
|
|
|
|
Promise.method = function Promise$_Method(fn) {
|
|
if (typeof fn !== "function") {
|
|
throw new TypeError("fn must be a function");
|
|
}
|
|
return function Promise$_method() {
|
|
var value;
|
|
switch(arguments.length) {
|
|
case 0: value = tryCatch1(fn, this, void 0); break;
|
|
case 1: value = tryCatch1(fn, this, arguments[0]); break;
|
|
case 2: value = tryCatch2(fn, this, arguments[0], arguments[1]); break;
|
|
default:
|
|
var $_len = arguments.length;var args = new Array($_len); for(var $_i = 0; $_i < $_len; ++$_i) {args[$_i] = arguments[$_i];}
|
|
value = tryCatchApply(fn, args, this); break;
|
|
}
|
|
var ret = new Promise(INTERNAL);
|
|
ret._setTrace(void 0);
|
|
ret._resolveFromSyncValue(value);
|
|
return ret;
|
|
};
|
|
};
|
|
|
|
Promise.attempt = Promise["try"] = function Promise$_Try(fn, args, ctx) {
|
|
if (typeof fn !== "function") {
|
|
return apiRejection("fn must be a function");
|
|
}
|
|
var value = isArray(args)
|
|
? tryCatchApply(fn, args, ctx)
|
|
: tryCatch1(fn, ctx, args);
|
|
|
|
var ret = new Promise(INTERNAL);
|
|
ret._setTrace(void 0);
|
|
ret._resolveFromSyncValue(value);
|
|
return ret;
|
|
};
|
|
|
|
Promise.defer = Promise.pending = function Promise$Defer() {
|
|
var promise = new Promise(INTERNAL);
|
|
promise._setTrace(void 0);
|
|
return new PromiseResolver(promise);
|
|
};
|
|
|
|
Promise.bind = function Promise$Bind(thisArg) {
|
|
var ret = new Promise(INTERNAL);
|
|
ret._setTrace(void 0);
|
|
ret._setFulfilled();
|
|
ret._setBoundTo(thisArg);
|
|
return ret;
|
|
};
|
|
|
|
Promise.cast = function Promise$_Cast(obj) {
|
|
var ret = Promise._cast(obj, void 0);
|
|
if (!(ret instanceof Promise)) {
|
|
return Promise.resolve(ret);
|
|
}
|
|
return ret;
|
|
};
|
|
|
|
Promise.onPossiblyUnhandledRejection =
|
|
function Promise$OnPossiblyUnhandledRejection(fn) {
|
|
CapturedTrace.possiblyUnhandledRejection = typeof fn === "function"
|
|
? fn : void 0;
|
|
};
|
|
|
|
var unhandledRejectionHandled;
|
|
Promise.onUnhandledRejectionHandled =
|
|
function Promise$onUnhandledRejectionHandled(fn) {
|
|
unhandledRejectionHandled = typeof fn === "function" ? fn : void 0;
|
|
};
|
|
|
|
var debugging = false || !!(
|
|
typeof process !== "undefined" &&
|
|
typeof process.execPath === "string" &&
|
|
typeof process.env === "object" &&
|
|
(process.env["BLUEBIRD_DEBUG"] ||
|
|
process.env["NODE_ENV"] === "development")
|
|
);
|
|
|
|
|
|
Promise.longStackTraces = function Promise$LongStackTraces() {
|
|
if (async.haveItemsQueued() &&
|
|
debugging === false
|
|
) {
|
|
throw new Error("cannot enable long stack traces after promises have been created");
|
|
}
|
|
debugging = CapturedTrace.isSupported();
|
|
};
|
|
|
|
Promise.hasLongStackTraces = function Promise$HasLongStackTraces() {
|
|
return debugging && CapturedTrace.isSupported();
|
|
};
|
|
|
|
Promise.prototype._setProxyHandlers =
|
|
function Promise$_setProxyHandlers(receiver, promiseSlotValue) {
|
|
var index = this._length();
|
|
|
|
if (index >= 524287 - 5) {
|
|
index = 0;
|
|
this._setLength(0);
|
|
}
|
|
if (index === 0) {
|
|
this._promise0 = promiseSlotValue;
|
|
this._receiver0 = receiver;
|
|
}
|
|
else {
|
|
var i = index - 5;
|
|
this[i + 3] = promiseSlotValue;
|
|
this[i + 4] = receiver;
|
|
this[i + 0] =
|
|
this[i + 1] =
|
|
this[i + 2] = void 0;
|
|
}
|
|
this._setLength(index + 5);
|
|
};
|
|
|
|
Promise.prototype._proxyPromiseArray =
|
|
function Promise$_proxyPromiseArray(promiseArray, index) {
|
|
this._setProxyHandlers(promiseArray, index);
|
|
};
|
|
|
|
Promise.prototype._proxyPromise = function Promise$_proxyPromise(promise) {
|
|
promise._setProxied();
|
|
this._setProxyHandlers(promise, -1);
|
|
};
|
|
|
|
Promise.prototype._then =
|
|
function Promise$_then(
|
|
didFulfill,
|
|
didReject,
|
|
didProgress,
|
|
receiver,
|
|
internalData
|
|
) {
|
|
var haveInternalData = internalData !== void 0;
|
|
var ret = haveInternalData ? internalData : new Promise(INTERNAL);
|
|
|
|
if (debugging && !haveInternalData) {
|
|
var haveSameContext = this._peekContext() === this._traceParent;
|
|
ret._traceParent = haveSameContext ? this._traceParent : this;
|
|
ret._setTrace(this);
|
|
}
|
|
|
|
if (!haveInternalData && this._isBound()) {
|
|
ret._setBoundTo(this._boundTo);
|
|
}
|
|
|
|
var callbackIndex =
|
|
this._addCallbacks(didFulfill, didReject, didProgress, ret, receiver);
|
|
|
|
if (!haveInternalData && this._cancellable()) {
|
|
ret._setCancellable();
|
|
ret._cancellationParent = this;
|
|
}
|
|
|
|
if (this.isResolved()) {
|
|
async.invoke(this._queueSettleAt, this, callbackIndex);
|
|
}
|
|
|
|
return ret;
|
|
};
|
|
|
|
Promise.prototype._length = function Promise$_length() {
|
|
return this._bitField & 524287;
|
|
};
|
|
|
|
Promise.prototype._isFollowingOrFulfilledOrRejected =
|
|
function Promise$_isFollowingOrFulfilledOrRejected() {
|
|
return (this._bitField & 939524096) > 0;
|
|
};
|
|
|
|
Promise.prototype._isFollowing = function Promise$_isFollowing() {
|
|
return (this._bitField & 536870912) === 536870912;
|
|
};
|
|
|
|
Promise.prototype._setLength = function Promise$_setLength(len) {
|
|
this._bitField = (this._bitField & -524288) |
|
|
(len & 524287);
|
|
};
|
|
|
|
Promise.prototype._setFulfilled = function Promise$_setFulfilled() {
|
|
this._bitField = this._bitField | 268435456;
|
|
};
|
|
|
|
Promise.prototype._setRejected = function Promise$_setRejected() {
|
|
this._bitField = this._bitField | 134217728;
|
|
};
|
|
|
|
Promise.prototype._setFollowing = function Promise$_setFollowing() {
|
|
this._bitField = this._bitField | 536870912;
|
|
};
|
|
|
|
Promise.prototype._setIsFinal = function Promise$_setIsFinal() {
|
|
this._bitField = this._bitField | 33554432;
|
|
};
|
|
|
|
Promise.prototype._isFinal = function Promise$_isFinal() {
|
|
return (this._bitField & 33554432) > 0;
|
|
};
|
|
|
|
Promise.prototype._cancellable = function Promise$_cancellable() {
|
|
return (this._bitField & 67108864) > 0;
|
|
};
|
|
|
|
Promise.prototype._setCancellable = function Promise$_setCancellable() {
|
|
this._bitField = this._bitField | 67108864;
|
|
};
|
|
|
|
Promise.prototype._unsetCancellable = function Promise$_unsetCancellable() {
|
|
this._bitField = this._bitField & (~67108864);
|
|
};
|
|
|
|
Promise.prototype._setRejectionIsUnhandled =
|
|
function Promise$_setRejectionIsUnhandled() {
|
|
this._bitField = this._bitField | 2097152;
|
|
};
|
|
|
|
Promise.prototype._unsetRejectionIsUnhandled =
|
|
function Promise$_unsetRejectionIsUnhandled() {
|
|
this._bitField = this._bitField & (~2097152);
|
|
if (this._isUnhandledRejectionNotified()) {
|
|
this._unsetUnhandledRejectionIsNotified();
|
|
this._notifyUnhandledRejectionIsHandled();
|
|
}
|
|
};
|
|
|
|
Promise.prototype._isRejectionUnhandled =
|
|
function Promise$_isRejectionUnhandled() {
|
|
return (this._bitField & 2097152) > 0;
|
|
};
|
|
|
|
Promise.prototype._setUnhandledRejectionIsNotified =
|
|
function Promise$_setUnhandledRejectionIsNotified() {
|
|
this._bitField = this._bitField | 524288;
|
|
};
|
|
|
|
Promise.prototype._unsetUnhandledRejectionIsNotified =
|
|
function Promise$_unsetUnhandledRejectionIsNotified() {
|
|
this._bitField = this._bitField & (~524288);
|
|
};
|
|
|
|
Promise.prototype._isUnhandledRejectionNotified =
|
|
function Promise$_isUnhandledRejectionNotified() {
|
|
return (this._bitField & 524288) > 0;
|
|
};
|
|
|
|
Promise.prototype._setCarriedStackTrace =
|
|
function Promise$_setCarriedStackTrace(capturedTrace) {
|
|
this._bitField = this._bitField | 1048576;
|
|
this._fulfillmentHandler0 = capturedTrace;
|
|
};
|
|
|
|
Promise.prototype._unsetCarriedStackTrace =
|
|
function Promise$_unsetCarriedStackTrace() {
|
|
this._bitField = this._bitField & (~1048576);
|
|
this._fulfillmentHandler0 = void 0;
|
|
};
|
|
|
|
Promise.prototype._isCarryingStackTrace =
|
|
function Promise$_isCarryingStackTrace() {
|
|
return (this._bitField & 1048576) > 0;
|
|
};
|
|
|
|
Promise.prototype._getCarriedStackTrace =
|
|
function Promise$_getCarriedStackTrace() {
|
|
return this._isCarryingStackTrace()
|
|
? this._fulfillmentHandler0
|
|
: void 0;
|
|
};
|
|
|
|
Promise.prototype._receiverAt = function Promise$_receiverAt(index) {
|
|
var ret;
|
|
if (index === 0) {
|
|
ret = this._receiver0;
|
|
}
|
|
else {
|
|
ret = this[index + 4 - 5];
|
|
}
|
|
if (this._isBound() && ret === void 0) {
|
|
return this._boundTo;
|
|
}
|
|
return ret;
|
|
};
|
|
|
|
Promise.prototype._promiseAt = function Promise$_promiseAt(index) {
|
|
if (index === 0) return this._promise0;
|
|
return this[index + 3 - 5];
|
|
};
|
|
|
|
Promise.prototype._fulfillmentHandlerAt =
|
|
function Promise$_fulfillmentHandlerAt(index) {
|
|
if (index === 0) return this._fulfillmentHandler0;
|
|
return this[index + 0 - 5];
|
|
};
|
|
|
|
Promise.prototype._rejectionHandlerAt =
|
|
function Promise$_rejectionHandlerAt(index) {
|
|
if (index === 0) return this._rejectionHandler0;
|
|
return this[index + 1 - 5];
|
|
};
|
|
|
|
Promise.prototype._unsetAt = function Promise$_unsetAt(index) {
|
|
if (index === 0) {
|
|
this._rejectionHandler0 =
|
|
this._progressHandler0 =
|
|
this._promise0 =
|
|
this._receiver0 = void 0;
|
|
if (!this._isCarryingStackTrace()) {
|
|
this._fulfillmentHandler0 = void 0;
|
|
}
|
|
}
|
|
else {
|
|
this[index - 5 + 0] =
|
|
this[index - 5 + 1] =
|
|
this[index - 5 + 2] =
|
|
this[index - 5 + 3] =
|
|
this[index - 5 + 4] = void 0;
|
|
}
|
|
};
|
|
|
|
Promise.prototype._resolveFromResolver =
|
|
function Promise$_resolveFromResolver(resolver) {
|
|
var promise = this;
|
|
this._setTrace(void 0);
|
|
this._pushContext();
|
|
|
|
function Promise$_resolver(val) {
|
|
if (promise._tryFollow(val)) {
|
|
return;
|
|
}
|
|
promise._fulfill(val);
|
|
}
|
|
function Promise$_rejecter(val) {
|
|
var trace = canAttach(val) ? val : new Error(val + "");
|
|
promise._attachExtraTrace(trace);
|
|
markAsOriginatingFromRejection(val);
|
|
promise._reject(val, trace === val ? void 0 : trace);
|
|
}
|
|
var r = tryCatch2(resolver, void 0, Promise$_resolver, Promise$_rejecter);
|
|
this._popContext();
|
|
|
|
if (r !== void 0 && r === errorObj) {
|
|
var e = r.e;
|
|
var trace = canAttach(e) ? e : new Error(e + "");
|
|
promise._reject(e, trace);
|
|
}
|
|
};
|
|
|
|
Promise.prototype._addCallbacks = function Promise$_addCallbacks(
|
|
fulfill,
|
|
reject,
|
|
progress,
|
|
promise,
|
|
receiver
|
|
) {
|
|
var index = this._length();
|
|
|
|
if (index >= 524287 - 5) {
|
|
index = 0;
|
|
this._setLength(0);
|
|
}
|
|
|
|
if (index === 0) {
|
|
this._promise0 = promise;
|
|
if (receiver !== void 0) this._receiver0 = receiver;
|
|
if (typeof fulfill === "function" && !this._isCarryingStackTrace())
|
|
this._fulfillmentHandler0 = fulfill;
|
|
if (typeof reject === "function") this._rejectionHandler0 = reject;
|
|
if (typeof progress === "function") this._progressHandler0 = progress;
|
|
}
|
|
else {
|
|
var i = index - 5;
|
|
this[i + 3] = promise;
|
|
this[i + 4] = receiver;
|
|
this[i + 0] = typeof fulfill === "function"
|
|
? fulfill : void 0;
|
|
this[i + 1] = typeof reject === "function"
|
|
? reject : void 0;
|
|
this[i + 2] = typeof progress === "function"
|
|
? progress : void 0;
|
|
}
|
|
this._setLength(index + 5);
|
|
return index;
|
|
};
|
|
|
|
|
|
|
|
Promise.prototype._setBoundTo = function Promise$_setBoundTo(obj) {
|
|
if (obj !== void 0) {
|
|
this._bitField = this._bitField | 8388608;
|
|
this._boundTo = obj;
|
|
}
|
|
else {
|
|
this._bitField = this._bitField & (~8388608);
|
|
}
|
|
};
|
|
|
|
Promise.prototype._isBound = function Promise$_isBound() {
|
|
return (this._bitField & 8388608) === 8388608;
|
|
};
|
|
|
|
Promise.prototype._spreadSlowCase =
|
|
function Promise$_spreadSlowCase(targetFn, promise, values, boundTo) {
|
|
var promiseForAll =
|
|
Promise$_CreatePromiseArray
|
|
(values, PromiseArray, boundTo)
|
|
.promise()
|
|
._then(function() {
|
|
return targetFn.apply(boundTo, arguments);
|
|
}, void 0, void 0, APPLY, void 0);
|
|
|
|
promise._follow(promiseForAll);
|
|
};
|
|
|
|
Promise.prototype._callSpread =
|
|
function Promise$_callSpread(handler, promise, value, localDebugging) {
|
|
var boundTo = this._isBound() ? this._boundTo : void 0;
|
|
if (isArray(value)) {
|
|
for (var i = 0, len = value.length; i < len; ++i) {
|
|
if (isPromise(Promise._cast(value[i], void 0))) {
|
|
this._spreadSlowCase(handler, promise, value, boundTo);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (localDebugging) promise._pushContext();
|
|
return tryCatchApply(handler, value, boundTo);
|
|
};
|
|
|
|
Promise.prototype._callHandler =
|
|
function Promise$_callHandler(
|
|
handler, receiver, promise, value, localDebugging) {
|
|
var x;
|
|
if (receiver === APPLY && !this.isRejected()) {
|
|
x = this._callSpread(handler, promise, value, localDebugging);
|
|
}
|
|
else {
|
|
if (localDebugging) promise._pushContext();
|
|
x = tryCatch1(handler, receiver, value);
|
|
}
|
|
if (localDebugging) promise._popContext();
|
|
return x;
|
|
};
|
|
|
|
Promise.prototype._settlePromiseFromHandler =
|
|
function Promise$_settlePromiseFromHandler(
|
|
handler, receiver, value, promise
|
|
) {
|
|
if (!isPromise(promise)) {
|
|
handler.call(receiver, value, promise);
|
|
return;
|
|
}
|
|
|
|
var localDebugging = debugging;
|
|
var x = this._callHandler(handler, receiver,
|
|
promise, value, localDebugging);
|
|
|
|
if (promise._isFollowing()) return;
|
|
|
|
if (x === errorObj || x === promise || x === NEXT_FILTER) {
|
|
var err = x === promise
|
|
? makeSelfResolutionError()
|
|
: x.e;
|
|
var trace = canAttach(err) ? err : new Error(err + "");
|
|
if (x !== NEXT_FILTER) promise._attachExtraTrace(trace);
|
|
promise._rejectUnchecked(err, trace);
|
|
}
|
|
else {
|
|
var castValue = Promise._cast(x, promise);
|
|
if (isPromise(castValue)) {
|
|
if (castValue.isRejected() &&
|
|
!castValue._isCarryingStackTrace() &&
|
|
!canAttach(castValue._settledValue)) {
|
|
var trace = new Error(castValue._settledValue + "");
|
|
promise._attachExtraTrace(trace);
|
|
castValue._setCarriedStackTrace(trace);
|
|
}
|
|
promise._follow(castValue);
|
|
if (castValue._cancellable()) {
|
|
promise._cancellationParent = castValue;
|
|
promise._setCancellable();
|
|
}
|
|
}
|
|
else {
|
|
promise._fulfillUnchecked(x);
|
|
}
|
|
}
|
|
};
|
|
|
|
Promise.prototype._follow =
|
|
function Promise$_follow(promise) {
|
|
this._setFollowing();
|
|
|
|
if (promise.isPending()) {
|
|
if (promise._cancellable() ) {
|
|
this._cancellationParent = promise;
|
|
this._setCancellable();
|
|
}
|
|
promise._proxyPromise(this);
|
|
}
|
|
else if (promise.isFulfilled()) {
|
|
this._fulfillUnchecked(promise._settledValue);
|
|
}
|
|
else {
|
|
this._rejectUnchecked(promise._settledValue,
|
|
promise._getCarriedStackTrace());
|
|
}
|
|
|
|
if (promise._isRejectionUnhandled()) promise._unsetRejectionIsUnhandled();
|
|
|
|
if (debugging &&
|
|
promise._traceParent == null) {
|
|
promise._traceParent = this;
|
|
}
|
|
};
|
|
|
|
Promise.prototype._tryFollow =
|
|
function Promise$_tryFollow(value) {
|
|
if (this._isFollowingOrFulfilledOrRejected() ||
|
|
value === this) {
|
|
return false;
|
|
}
|
|
var maybePromise = Promise._cast(value, void 0);
|
|
if (!isPromise(maybePromise)) {
|
|
return false;
|
|
}
|
|
this._follow(maybePromise);
|
|
return true;
|
|
};
|
|
|
|
Promise.prototype._resetTrace = function Promise$_resetTrace() {
|
|
if (debugging) {
|
|
this._trace = new CapturedTrace(this._peekContext() === void 0);
|
|
}
|
|
};
|
|
|
|
Promise.prototype._setTrace = function Promise$_setTrace(parent) {
|
|
if (debugging) {
|
|
var context = this._peekContext();
|
|
this._traceParent = context;
|
|
var isTopLevel = context === void 0;
|
|
if (parent !== void 0 &&
|
|
parent._traceParent === context) {
|
|
this._trace = parent._trace;
|
|
}
|
|
else {
|
|
this._trace = new CapturedTrace(isTopLevel);
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
|
|
Promise.prototype._attachExtraTrace =
|
|
function Promise$_attachExtraTrace(error) {
|
|
if (debugging) {
|
|
var promise = this;
|
|
var stack = error.stack;
|
|
stack = typeof stack === "string"
|
|
? stack.split("\n") : [];
|
|
var headerLineCount = 1;
|
|
|
|
while(promise != null &&
|
|
promise._trace != null) {
|
|
stack = CapturedTrace.combine(
|
|
stack,
|
|
promise._trace.stack.split("\n")
|
|
);
|
|
promise = promise._traceParent;
|
|
}
|
|
|
|
var max = Error.stackTraceLimit + headerLineCount;
|
|
var len = stack.length;
|
|
if (len > max) {
|
|
stack.length = max;
|
|
}
|
|
if (stack.length <= headerLineCount) {
|
|
error.stack = "(No stack trace)";
|
|
}
|
|
else {
|
|
error.stack = stack.join("\n");
|
|
}
|
|
}
|
|
};
|
|
|
|
Promise.prototype._cleanValues = function Promise$_cleanValues() {
|
|
if (this._cancellable()) {
|
|
this._cancellationParent = void 0;
|
|
}
|
|
};
|
|
|
|
Promise.prototype._fulfill = function Promise$_fulfill(value) {
|
|
if (this._isFollowingOrFulfilledOrRejected()) return;
|
|
this._fulfillUnchecked(value);
|
|
};
|
|
|
|
Promise.prototype._reject =
|
|
function Promise$_reject(reason, carriedStackTrace) {
|
|
if (this._isFollowingOrFulfilledOrRejected()) return;
|
|
this._rejectUnchecked(reason, carriedStackTrace);
|
|
};
|
|
|
|
Promise.prototype._settlePromiseAt = function Promise$_settlePromiseAt(index) {
|
|
var handler = this.isFulfilled()
|
|
? this._fulfillmentHandlerAt(index)
|
|
: this._rejectionHandlerAt(index);
|
|
|
|
var value = this._settledValue;
|
|
var receiver = this._receiverAt(index);
|
|
var promise = this._promiseAt(index);
|
|
|
|
if (typeof handler === "function") {
|
|
this._settlePromiseFromHandler(handler, receiver, value, promise);
|
|
}
|
|
else {
|
|
var done = false;
|
|
var isFulfilled = this.isFulfilled();
|
|
if (receiver !== void 0) {
|
|
if (receiver instanceof Promise &&
|
|
receiver._isProxied()) {
|
|
receiver._unsetProxied();
|
|
|
|
if (isFulfilled) receiver._fulfillUnchecked(value);
|
|
else receiver._rejectUnchecked(value,
|
|
this._getCarriedStackTrace());
|
|
done = true;
|
|
}
|
|
else if (isPromiseArrayProxy(receiver, promise)) {
|
|
if (isFulfilled) receiver._promiseFulfilled(value, promise);
|
|
else receiver._promiseRejected(value, promise);
|
|
done = true;
|
|
}
|
|
}
|
|
|
|
if (!done) {
|
|
if (isFulfilled) promise._fulfill(value);
|
|
else promise._reject(value, this._getCarriedStackTrace());
|
|
}
|
|
}
|
|
|
|
if (index >= 256) {
|
|
this._queueGC();
|
|
}
|
|
};
|
|
|
|
Promise.prototype._isProxied = function Promise$_isProxied() {
|
|
return (this._bitField & 4194304) === 4194304;
|
|
};
|
|
|
|
Promise.prototype._setProxied = function Promise$_setProxied() {
|
|
this._bitField = this._bitField | 4194304;
|
|
};
|
|
|
|
Promise.prototype._unsetProxied = function Promise$_unsetProxied() {
|
|
this._bitField = this._bitField & (~4194304);
|
|
};
|
|
|
|
Promise.prototype._isGcQueued = function Promise$_isGcQueued() {
|
|
return (this._bitField & -1073741824) === -1073741824;
|
|
};
|
|
|
|
Promise.prototype._setGcQueued = function Promise$_setGcQueued() {
|
|
this._bitField = this._bitField | -1073741824;
|
|
};
|
|
|
|
Promise.prototype._unsetGcQueued = function Promise$_unsetGcQueued() {
|
|
this._bitField = this._bitField & (~-1073741824);
|
|
};
|
|
|
|
Promise.prototype._queueGC = function Promise$_queueGC() {
|
|
if (this._isGcQueued()) return;
|
|
this._setGcQueued();
|
|
async.invokeLater(this._gc, this, void 0);
|
|
};
|
|
|
|
Promise.prototype._gc = function Promise$gc() {
|
|
var len = this._length();
|
|
this._unsetAt(0);
|
|
for (var i = 0; i < len; i++) {
|
|
delete this[i];
|
|
}
|
|
this._setLength(0);
|
|
this._unsetGcQueued();
|
|
};
|
|
|
|
Promise.prototype._queueSettleAt = function Promise$_queueSettleAt(index) {
|
|
if (this._isRejectionUnhandled()) this._unsetRejectionIsUnhandled();
|
|
async.invoke(this._settlePromiseAt, this, index);
|
|
};
|
|
|
|
Promise.prototype._fulfillUnchecked =
|
|
function Promise$_fulfillUnchecked(value) {
|
|
if (!this.isPending()) return;
|
|
if (value === this) {
|
|
var err = makeSelfResolutionError();
|
|
this._attachExtraTrace(err);
|
|
return this._rejectUnchecked(err, void 0);
|
|
}
|
|
this._cleanValues();
|
|
this._setFulfilled();
|
|
this._settledValue = value;
|
|
var len = this._length();
|
|
|
|
if (len > 0) {
|
|
async.invoke(this._settlePromises, this, len);
|
|
}
|
|
};
|
|
|
|
Promise.prototype._rejectUncheckedCheckError =
|
|
function Promise$_rejectUncheckedCheckError(reason) {
|
|
var trace = canAttach(reason) ? reason : new Error(reason + "");
|
|
this._rejectUnchecked(reason, trace === reason ? void 0 : trace);
|
|
};
|
|
|
|
Promise.prototype._rejectUnchecked =
|
|
function Promise$_rejectUnchecked(reason, trace) {
|
|
if (!this.isPending()) return;
|
|
if (reason === this) {
|
|
var err = makeSelfResolutionError();
|
|
this._attachExtraTrace(err);
|
|
return this._rejectUnchecked(err);
|
|
}
|
|
this._cleanValues();
|
|
this._setRejected();
|
|
this._settledValue = reason;
|
|
|
|
if (this._isFinal()) {
|
|
async.invokeLater(thrower, void 0, trace === void 0 ? reason : trace);
|
|
return;
|
|
}
|
|
var len = this._length();
|
|
|
|
if (trace !== void 0) this._setCarriedStackTrace(trace);
|
|
|
|
if (len > 0) {
|
|
async.invoke(this._rejectPromises, this, null);
|
|
}
|
|
else {
|
|
this._ensurePossibleRejectionHandled();
|
|
}
|
|
};
|
|
|
|
Promise.prototype._rejectPromises = function Promise$_rejectPromises() {
|
|
this._settlePromises();
|
|
this._unsetCarriedStackTrace();
|
|
};
|
|
|
|
Promise.prototype._settlePromises = function Promise$_settlePromises() {
|
|
var len = this._length();
|
|
for (var i = 0; i < len; i+= 5) {
|
|
this._settlePromiseAt(i);
|
|
}
|
|
};
|
|
|
|
Promise.prototype._ensurePossibleRejectionHandled =
|
|
function Promise$_ensurePossibleRejectionHandled() {
|
|
this._setRejectionIsUnhandled();
|
|
if (CapturedTrace.possiblyUnhandledRejection !== void 0) {
|
|
async.invokeLater(this._notifyUnhandledRejection, this, void 0);
|
|
}
|
|
};
|
|
|
|
Promise.prototype._notifyUnhandledRejectionIsHandled =
|
|
function Promise$_notifyUnhandledRejectionIsHandled() {
|
|
if (typeof unhandledRejectionHandled === "function") {
|
|
async.invokeLater(unhandledRejectionHandled, void 0, this);
|
|
}
|
|
};
|
|
|
|
Promise.prototype._notifyUnhandledRejection =
|
|
function Promise$_notifyUnhandledRejection() {
|
|
if (this._isRejectionUnhandled()) {
|
|
var reason = this._settledValue;
|
|
var trace = this._getCarriedStackTrace();
|
|
|
|
this._setUnhandledRejectionIsNotified();
|
|
|
|
if (trace !== void 0) {
|
|
this._unsetCarriedStackTrace();
|
|
reason = trace;
|
|
}
|
|
if (typeof CapturedTrace.possiblyUnhandledRejection === "function") {
|
|
CapturedTrace.possiblyUnhandledRejection(reason, this);
|
|
}
|
|
}
|
|
};
|
|
|
|
var contextStack = [];
|
|
Promise.prototype._peekContext = function Promise$_peekContext() {
|
|
var lastIndex = contextStack.length - 1;
|
|
if (lastIndex >= 0) {
|
|
return contextStack[lastIndex];
|
|
}
|
|
return void 0;
|
|
|
|
};
|
|
|
|
Promise.prototype._pushContext = function Promise$_pushContext() {
|
|
if (!debugging) return;
|
|
contextStack.push(this);
|
|
};
|
|
|
|
Promise.prototype._popContext = function Promise$_popContext() {
|
|
if (!debugging) return;
|
|
contextStack.pop();
|
|
};
|
|
|
|
function Promise$_CreatePromiseArray(
|
|
promises, PromiseArrayConstructor, boundTo) {
|
|
|
|
var list = null;
|
|
if (isArray(promises)) {
|
|
list = promises;
|
|
}
|
|
else {
|
|
list = Promise._cast(promises, void 0);
|
|
if (list !== promises) {
|
|
list._setBoundTo(boundTo);
|
|
}
|
|
else if (!isPromise(list)) {
|
|
list = null;
|
|
}
|
|
}
|
|
if (list !== null) {
|
|
return new PromiseArrayConstructor(list, boundTo);
|
|
}
|
|
return {
|
|
promise: function() {return apiRejection("expecting an array, a promise or a thenable");}
|
|
};
|
|
}
|
|
|
|
var old = global.Promise;
|
|
Promise.noConflict = function() {
|
|
if (global.Promise === Promise) {
|
|
global.Promise = old;
|
|
}
|
|
return Promise;
|
|
};
|
|
|
|
if (!CapturedTrace.isSupported()) {
|
|
Promise.longStackTraces = function(){};
|
|
debugging = false;
|
|
}
|
|
|
|
Promise._makeSelfResolutionError = makeSelfResolutionError;
|
|
_dereq_("./finally.js")(Promise, NEXT_FILTER);
|
|
_dereq_("./direct_resolve.js")(Promise);
|
|
_dereq_("./thenables.js")(Promise, INTERNAL);
|
|
_dereq_("./synchronous_inspection.js")(Promise);
|
|
Promise.RangeError = RangeError;
|
|
Promise.CancellationError = CancellationError;
|
|
Promise.TimeoutError = TimeoutError;
|
|
Promise.TypeError = TypeError;
|
|
Promise.RejectionError = RejectionError;
|
|
|
|
util.toFastProperties(Promise);
|
|
util.toFastProperties(Promise.prototype);
|
|
_dereq_('./timers.js')(Promise,INTERNAL);
|
|
_dereq_('./any.js')(Promise,Promise$_CreatePromiseArray,PromiseArray);
|
|
_dereq_('./race.js')(Promise,INTERNAL);
|
|
_dereq_('./call_get.js')(Promise);
|
|
_dereq_('./filter.js')(Promise,Promise$_CreatePromiseArray,PromiseArray,apiRejection);
|
|
_dereq_('./generators.js')(Promise,apiRejection,INTERNAL);
|
|
_dereq_('./map.js')(Promise,PromiseArray,INTERNAL,apiRejection);
|
|
_dereq_('./nodeify.js')(Promise);
|
|
_dereq_('./promisify.js')(Promise,INTERNAL);
|
|
_dereq_('./props.js')(Promise,PromiseArray);
|
|
_dereq_('./reduce.js')(Promise,Promise$_CreatePromiseArray,PromiseArray,apiRejection,INTERNAL);
|
|
_dereq_('./settle.js')(Promise,Promise$_CreatePromiseArray,PromiseArray);
|
|
_dereq_('./some.js')(Promise,Promise$_CreatePromiseArray,PromiseArray,apiRejection);
|
|
_dereq_('./progress.js')(Promise,isPromiseArrayProxy);
|
|
_dereq_('./cancel.js')(Promise,INTERNAL);
|
|
|
|
Promise.prototype = Promise.prototype;
|
|
return Promise;
|
|
|
|
};
|
|
|
|
}).call(this,_dereq_("C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"))
|
|
},{"./any.js":72,"./async.js":73,"./call_get.js":75,"./cancel.js":76,"./captured_trace.js":77,"./catch_filter.js":78,"./direct_resolve.js":79,"./errors.js":80,"./errors_api_rejection":81,"./filter.js":83,"./finally.js":84,"./generators.js":85,"./global.js":86,"./map.js":87,"./nodeify.js":88,"./progress.js":89,"./promise_array.js":91,"./promise_resolver.js":92,"./promisify.js":94,"./props.js":96,"./race.js":98,"./reduce.js":99,"./settle.js":101,"./some.js":103,"./synchronous_inspection.js":105,"./thenables.js":106,"./timers.js":107,"./util.js":108,"C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":144}],91:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, INTERNAL) {
|
|
var canAttach = _dereq_("./errors.js").canAttach;
|
|
var util = _dereq_("./util.js");
|
|
var async = _dereq_("./async.js");
|
|
var hasOwn = {}.hasOwnProperty;
|
|
var isArray = util.isArray;
|
|
|
|
function toResolutionValue(val) {
|
|
switch(val) {
|
|
case -1: return void 0;
|
|
case -2: return [];
|
|
case -3: return {};
|
|
}
|
|
}
|
|
|
|
function PromiseArray(values, boundTo) {
|
|
var promise = this._promise = new Promise(INTERNAL);
|
|
var parent = void 0;
|
|
if (values instanceof Promise) {
|
|
parent = values;
|
|
if (values._cancellable()) {
|
|
promise._setCancellable();
|
|
promise._cancellationParent = values;
|
|
}
|
|
if (values._isBound()) {
|
|
promise._setBoundTo(boundTo);
|
|
}
|
|
}
|
|
promise._setTrace(parent);
|
|
this._values = values;
|
|
this._length = 0;
|
|
this._totalResolved = 0;
|
|
this._init(void 0, -2);
|
|
}
|
|
PromiseArray.PropertiesPromiseArray = function() {};
|
|
|
|
PromiseArray.prototype.length = function PromiseArray$length() {
|
|
return this._length;
|
|
};
|
|
|
|
PromiseArray.prototype.promise = function PromiseArray$promise() {
|
|
return this._promise;
|
|
};
|
|
|
|
PromiseArray.prototype._init =
|
|
function PromiseArray$_init(_, resolveValueIfEmpty) {
|
|
var values = this._values;
|
|
if (values instanceof Promise) {
|
|
if (values.isFulfilled()) {
|
|
values = values._settledValue;
|
|
if (!isArray(values)) {
|
|
var err = new Promise.TypeError("expecting an array, a promise or a thenable");
|
|
this.__hardReject__(err);
|
|
return;
|
|
}
|
|
this._values = values;
|
|
}
|
|
else if (values.isPending()) {
|
|
values._then(
|
|
this._init,
|
|
this._reject,
|
|
void 0,
|
|
this,
|
|
resolveValueIfEmpty
|
|
);
|
|
return;
|
|
}
|
|
else {
|
|
values._unsetRejectionIsUnhandled();
|
|
this._reject(values._settledValue);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (values.length === 0) {
|
|
this._resolve(toResolutionValue(resolveValueIfEmpty));
|
|
return;
|
|
}
|
|
var len = values.length;
|
|
var newLen = len;
|
|
var newValues;
|
|
if (this instanceof PromiseArray.PropertiesPromiseArray) {
|
|
newValues = this._values;
|
|
}
|
|
else {
|
|
newValues = new Array(len);
|
|
}
|
|
var isDirectScanNeeded = false;
|
|
for (var i = 0; i < len; ++i) {
|
|
var promise = values[i];
|
|
if (promise === void 0 && !hasOwn.call(values, i)) {
|
|
newLen--;
|
|
continue;
|
|
}
|
|
var maybePromise = Promise._cast(promise, void 0);
|
|
if (maybePromise instanceof Promise) {
|
|
if (maybePromise.isPending()) {
|
|
maybePromise._proxyPromiseArray(this, i);
|
|
}
|
|
else {
|
|
maybePromise._unsetRejectionIsUnhandled();
|
|
isDirectScanNeeded = true;
|
|
}
|
|
}
|
|
else {
|
|
isDirectScanNeeded = true;
|
|
}
|
|
newValues[i] = maybePromise;
|
|
}
|
|
if (newLen === 0) {
|
|
if (resolveValueIfEmpty === -2) {
|
|
this._resolve(newValues);
|
|
}
|
|
else {
|
|
this._resolve(toResolutionValue(resolveValueIfEmpty));
|
|
}
|
|
return;
|
|
}
|
|
this._values = newValues;
|
|
this._length = newLen;
|
|
if (isDirectScanNeeded) {
|
|
var scanMethod = newLen === len
|
|
? this._scanDirectValues
|
|
: this._scanDirectValuesHoled;
|
|
async.invoke(scanMethod, this, len);
|
|
}
|
|
};
|
|
|
|
PromiseArray.prototype._settlePromiseAt =
|
|
function PromiseArray$_settlePromiseAt(index) {
|
|
var value = this._values[index];
|
|
if (!(value instanceof Promise)) {
|
|
this._promiseFulfilled(value, index);
|
|
}
|
|
else if (value.isFulfilled()) {
|
|
this._promiseFulfilled(value._settledValue, index);
|
|
}
|
|
else if (value.isRejected()) {
|
|
this._promiseRejected(value._settledValue, index);
|
|
}
|
|
};
|
|
|
|
PromiseArray.prototype._scanDirectValuesHoled =
|
|
function PromiseArray$_scanDirectValuesHoled(len) {
|
|
for (var i = 0; i < len; ++i) {
|
|
if (this._isResolved()) {
|
|
break;
|
|
}
|
|
if (hasOwn.call(this._values, i)) {
|
|
this._settlePromiseAt(i);
|
|
}
|
|
}
|
|
};
|
|
|
|
PromiseArray.prototype._scanDirectValues =
|
|
function PromiseArray$_scanDirectValues(len) {
|
|
for (var i = 0; i < len; ++i) {
|
|
if (this._isResolved()) {
|
|
break;
|
|
}
|
|
this._settlePromiseAt(i);
|
|
}
|
|
};
|
|
|
|
PromiseArray.prototype._isResolved = function PromiseArray$_isResolved() {
|
|
return this._values === null;
|
|
};
|
|
|
|
PromiseArray.prototype._resolve = function PromiseArray$_resolve(value) {
|
|
this._values = null;
|
|
this._promise._fulfill(value);
|
|
};
|
|
|
|
PromiseArray.prototype.__hardReject__ =
|
|
PromiseArray.prototype._reject = function PromiseArray$_reject(reason) {
|
|
this._values = null;
|
|
var trace = canAttach(reason) ? reason : new Error(reason + "");
|
|
this._promise._attachExtraTrace(trace);
|
|
this._promise._reject(reason, trace);
|
|
};
|
|
|
|
PromiseArray.prototype._promiseProgressed =
|
|
function PromiseArray$_promiseProgressed(progressValue, index) {
|
|
if (this._isResolved()) return;
|
|
this._promise._progress({
|
|
index: index,
|
|
value: progressValue
|
|
});
|
|
};
|
|
|
|
|
|
PromiseArray.prototype._promiseFulfilled =
|
|
function PromiseArray$_promiseFulfilled(value, index) {
|
|
if (this._isResolved()) return;
|
|
this._values[index] = value;
|
|
var totalResolved = ++this._totalResolved;
|
|
if (totalResolved >= this._length) {
|
|
this._resolve(this._values);
|
|
}
|
|
};
|
|
|
|
PromiseArray.prototype._promiseRejected =
|
|
function PromiseArray$_promiseRejected(reason, index) {
|
|
if (this._isResolved()) return;
|
|
this._totalResolved++;
|
|
this._reject(reason);
|
|
};
|
|
|
|
return PromiseArray;
|
|
};
|
|
|
|
},{"./async.js":73,"./errors.js":80,"./util.js":108}],92:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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 util = _dereq_("./util.js");
|
|
var maybeWrapAsError = util.maybeWrapAsError;
|
|
var errors = _dereq_("./errors.js");
|
|
var TimeoutError = errors.TimeoutError;
|
|
var RejectionError = errors.RejectionError;
|
|
var async = _dereq_("./async.js");
|
|
var haveGetters = util.haveGetters;
|
|
var es5 = _dereq_("./es5.js");
|
|
|
|
function isUntypedError(obj) {
|
|
return obj instanceof Error &&
|
|
es5.getPrototypeOf(obj) === Error.prototype;
|
|
}
|
|
|
|
function wrapAsRejectionError(obj) {
|
|
var ret;
|
|
if (isUntypedError(obj)) {
|
|
ret = new RejectionError(obj);
|
|
}
|
|
else {
|
|
ret = obj;
|
|
}
|
|
errors.markAsOriginatingFromRejection(ret);
|
|
return ret;
|
|
}
|
|
|
|
function nodebackForPromise(promise) {
|
|
function PromiseResolver$_callback(err, value) {
|
|
if (promise === null) return;
|
|
|
|
if (err) {
|
|
var wrapped = wrapAsRejectionError(maybeWrapAsError(err));
|
|
promise._attachExtraTrace(wrapped);
|
|
promise._reject(wrapped);
|
|
}
|
|
else {
|
|
if (arguments.length > 2) {
|
|
var $_len = arguments.length;var args = new Array($_len - 1); for(var $_i = 1; $_i < $_len; ++$_i) {args[$_i - 1] = arguments[$_i];}
|
|
promise._fulfill(args);
|
|
}
|
|
else {
|
|
promise._fulfill(value);
|
|
}
|
|
}
|
|
|
|
promise = null;
|
|
}
|
|
return PromiseResolver$_callback;
|
|
}
|
|
|
|
|
|
var PromiseResolver;
|
|
if (!haveGetters) {
|
|
PromiseResolver = function PromiseResolver(promise) {
|
|
this.promise = promise;
|
|
this.asCallback = nodebackForPromise(promise);
|
|
this.callback = this.asCallback;
|
|
};
|
|
}
|
|
else {
|
|
PromiseResolver = function PromiseResolver(promise) {
|
|
this.promise = promise;
|
|
};
|
|
}
|
|
if (haveGetters) {
|
|
var prop = {
|
|
get: function() {
|
|
return nodebackForPromise(this.promise);
|
|
}
|
|
};
|
|
es5.defineProperty(PromiseResolver.prototype, "asCallback", prop);
|
|
es5.defineProperty(PromiseResolver.prototype, "callback", prop);
|
|
}
|
|
|
|
PromiseResolver._nodebackForPromise = nodebackForPromise;
|
|
|
|
PromiseResolver.prototype.toString = function PromiseResolver$toString() {
|
|
return "[object PromiseResolver]";
|
|
};
|
|
|
|
PromiseResolver.prototype.resolve =
|
|
PromiseResolver.prototype.fulfill = function PromiseResolver$resolve(value) {
|
|
var promise = this.promise;
|
|
if ((promise === void 0) || (promise._tryFollow === void 0)) {
|
|
throw new TypeError("Illegal invocation, resolver resolve/reject must be called within a resolver context. Consider using the promise constructor instead.");
|
|
}
|
|
if (promise._tryFollow(value)) {
|
|
return;
|
|
}
|
|
async.invoke(promise._fulfill, promise, value);
|
|
};
|
|
|
|
PromiseResolver.prototype.reject = function PromiseResolver$reject(reason) {
|
|
var promise = this.promise;
|
|
if ((promise === void 0) || (promise._attachExtraTrace === void 0)) {
|
|
throw new TypeError("Illegal invocation, resolver resolve/reject must be called within a resolver context. Consider using the promise constructor instead.");
|
|
}
|
|
errors.markAsOriginatingFromRejection(reason);
|
|
var trace = errors.canAttach(reason) ? reason : new Error(reason + "");
|
|
promise._attachExtraTrace(trace);
|
|
async.invoke(promise._reject, promise, reason);
|
|
if (trace !== reason) {
|
|
async.invoke(this._setCarriedStackTrace, this, trace);
|
|
}
|
|
};
|
|
|
|
PromiseResolver.prototype.progress =
|
|
function PromiseResolver$progress(value) {
|
|
async.invoke(this.promise._progress, this.promise, value);
|
|
};
|
|
|
|
PromiseResolver.prototype.cancel = function PromiseResolver$cancel() {
|
|
async.invoke(this.promise.cancel, this.promise, void 0);
|
|
};
|
|
|
|
PromiseResolver.prototype.timeout = function PromiseResolver$timeout() {
|
|
this.reject(new TimeoutError("timeout"));
|
|
};
|
|
|
|
PromiseResolver.prototype.isResolved = function PromiseResolver$isResolved() {
|
|
return this.promise.isResolved();
|
|
};
|
|
|
|
PromiseResolver.prototype.toJSON = function PromiseResolver$toJSON() {
|
|
return this.promise.toJSON();
|
|
};
|
|
|
|
PromiseResolver.prototype._setCarriedStackTrace =
|
|
function PromiseResolver$_setCarriedStackTrace(trace) {
|
|
if (this.promise.isRejected()) {
|
|
this.promise._setCarriedStackTrace(trace);
|
|
}
|
|
};
|
|
|
|
module.exports = PromiseResolver;
|
|
|
|
},{"./async.js":73,"./errors.js":80,"./es5.js":82,"./util.js":108}],93:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, INTERNAL) {
|
|
var errors = _dereq_("./errors.js");
|
|
var TypeError = errors.TypeError;
|
|
var util = _dereq_("./util.js");
|
|
var isArray = util.isArray;
|
|
var errorObj = util.errorObj;
|
|
var tryCatch1 = util.tryCatch1;
|
|
var yieldHandlers = [];
|
|
|
|
function promiseFromYieldHandler(value) {
|
|
var _yieldHandlers = yieldHandlers;
|
|
var _errorObj = errorObj;
|
|
var _Promise = Promise;
|
|
var len = _yieldHandlers.length;
|
|
for (var i = 0; i < len; ++i) {
|
|
var result = tryCatch1(_yieldHandlers[i], void 0, value);
|
|
if (result === _errorObj) {
|
|
return _Promise.reject(_errorObj.e);
|
|
}
|
|
var maybePromise = _Promise._cast(result,
|
|
promiseFromYieldHandler, void 0);
|
|
if (maybePromise instanceof _Promise) return maybePromise;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function PromiseSpawn(generatorFunction, receiver) {
|
|
var promise = this._promise = new Promise(INTERNAL);
|
|
promise._setTrace(void 0);
|
|
this._generatorFunction = generatorFunction;
|
|
this._receiver = receiver;
|
|
this._generator = void 0;
|
|
}
|
|
|
|
PromiseSpawn.prototype.promise = function PromiseSpawn$promise() {
|
|
return this._promise;
|
|
};
|
|
|
|
PromiseSpawn.prototype._run = function PromiseSpawn$_run() {
|
|
this._generator = this._generatorFunction.call(this._receiver);
|
|
this._receiver =
|
|
this._generatorFunction = void 0;
|
|
this._next(void 0);
|
|
};
|
|
|
|
PromiseSpawn.prototype._continue = function PromiseSpawn$_continue(result) {
|
|
if (result === errorObj) {
|
|
this._generator = void 0;
|
|
var trace = errors.canAttach(result.e)
|
|
? result.e : new Error(result.e + "");
|
|
this._promise._attachExtraTrace(trace);
|
|
this._promise._reject(result.e, trace);
|
|
return;
|
|
}
|
|
|
|
var value = result.value;
|
|
if (result.done === true) {
|
|
this._generator = void 0;
|
|
if (!this._promise._tryFollow(value)) {
|
|
this._promise._fulfill(value);
|
|
}
|
|
}
|
|
else {
|
|
var maybePromise = Promise._cast(value, PromiseSpawn$_continue, void 0);
|
|
if (!(maybePromise instanceof Promise)) {
|
|
if (isArray(maybePromise)) {
|
|
maybePromise = Promise.all(maybePromise);
|
|
}
|
|
else {
|
|
maybePromise = promiseFromYieldHandler(maybePromise);
|
|
}
|
|
if (maybePromise === null) {
|
|
this._throw(new TypeError("A value was yielded that could not be treated as a promise"));
|
|
return;
|
|
}
|
|
}
|
|
maybePromise._then(
|
|
this._next,
|
|
this._throw,
|
|
void 0,
|
|
this,
|
|
null
|
|
);
|
|
}
|
|
};
|
|
|
|
PromiseSpawn.prototype._throw = function PromiseSpawn$_throw(reason) {
|
|
if (errors.canAttach(reason))
|
|
this._promise._attachExtraTrace(reason);
|
|
this._continue(
|
|
tryCatch1(this._generator["throw"], this._generator, reason)
|
|
);
|
|
};
|
|
|
|
PromiseSpawn.prototype._next = function PromiseSpawn$_next(value) {
|
|
this._continue(
|
|
tryCatch1(this._generator.next, this._generator, value)
|
|
);
|
|
};
|
|
|
|
PromiseSpawn.addYieldHandler = function PromiseSpawn$AddYieldHandler(fn) {
|
|
if (typeof fn !== "function") throw new TypeError("fn must be a function");
|
|
yieldHandlers.push(fn);
|
|
};
|
|
|
|
return PromiseSpawn;
|
|
};
|
|
|
|
},{"./errors.js":80,"./util.js":108}],94:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, INTERNAL) {
|
|
var THIS = {};
|
|
var util = _dereq_("./util.js");
|
|
var es5 = _dereq_("./es5.js");
|
|
var nodebackForPromise = _dereq_("./promise_resolver.js")
|
|
._nodebackForPromise;
|
|
var withAppended = util.withAppended;
|
|
var maybeWrapAsError = util.maybeWrapAsError;
|
|
var canEvaluate = util.canEvaluate;
|
|
var deprecated = util.deprecated;
|
|
var TypeError = _dereq_("./errors").TypeError;
|
|
|
|
|
|
var rasyncSuffix = new RegExp("Async" + "$");
|
|
function isPromisified(fn) {
|
|
return fn.__isPromisified__ === true;
|
|
}
|
|
function hasPromisified(obj, key) {
|
|
var containsKey = ((key + "Async") in obj);
|
|
return containsKey ? isPromisified(obj[key + "Async"])
|
|
: false;
|
|
}
|
|
function checkValid(ret) {
|
|
for (var i = 0; i < ret.length; i += 2) {
|
|
var key = ret[i];
|
|
if (rasyncSuffix.test(key)) {
|
|
var keyWithoutAsyncSuffix = key.replace(rasyncSuffix, "");
|
|
for (var j = 0; j < ret.length; j += 2) {
|
|
if (ret[j] === keyWithoutAsyncSuffix) {
|
|
throw new TypeError("Cannot promisify an API " +
|
|
"that has normal methods with Async-suffix");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var inheritedMethods = (function() {
|
|
if (es5.isES5) {
|
|
var create = Object.create;
|
|
var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
|
|
return function(cur) {
|
|
var ret = [];
|
|
var visitedKeys = create(null);
|
|
var original = cur;
|
|
while (cur !== null) {
|
|
var keys = es5.keys(cur);
|
|
for (var i = 0, len = keys.length; i < len; ++i) {
|
|
var key = keys[i];
|
|
if (visitedKeys[key]) continue;
|
|
visitedKeys[key] = true;
|
|
var desc = getOwnPropertyDescriptor(cur, key);
|
|
|
|
if (desc != null &&
|
|
typeof desc.value === "function" &&
|
|
!isPromisified(desc.value) &&
|
|
!hasPromisified(original, key)) {
|
|
ret.push(key, desc.value);
|
|
}
|
|
}
|
|
cur = es5.getPrototypeOf(cur);
|
|
}
|
|
checkValid(ret);
|
|
return ret;
|
|
};
|
|
}
|
|
else {
|
|
return function(obj) {
|
|
var ret = [];
|
|
/*jshint forin:false */
|
|
for (var key in obj) {
|
|
var fn = obj[key];
|
|
if (typeof fn === "function" &&
|
|
!isPromisified(fn) &&
|
|
!hasPromisified(obj, key)) {
|
|
ret.push(key, fn);
|
|
}
|
|
}
|
|
checkValid(ret);
|
|
return ret;
|
|
};
|
|
}
|
|
})();
|
|
|
|
function switchCaseArgumentOrder(likelyArgumentCount) {
|
|
var ret = [likelyArgumentCount];
|
|
var min = Math.max(0, likelyArgumentCount - 1 - 5);
|
|
for(var i = likelyArgumentCount - 1; i >= min; --i) {
|
|
if (i === likelyArgumentCount) continue;
|
|
ret.push(i);
|
|
}
|
|
for(var i = likelyArgumentCount + 1; i <= 5; ++i) {
|
|
ret.push(i);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
function parameterDeclaration(parameterCount) {
|
|
var ret = new Array(parameterCount);
|
|
for(var i = 0; i < ret.length; ++i) {
|
|
ret[i] = "_arg" + i;
|
|
}
|
|
return ret.join(", ");
|
|
}
|
|
|
|
function parameterCount(fn) {
|
|
if (typeof fn.length === "number") {
|
|
return Math.max(Math.min(fn.length, 1023 + 1), 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
var rident = /^[a-z$_][a-z$_0-9]*$/i;
|
|
function propertyAccess(id) {
|
|
if (rident.test(id)) {
|
|
return "." + id;
|
|
}
|
|
else return "['" + id.replace(/(['\\])/g, "\\$1") + "']";
|
|
}
|
|
|
|
function makeNodePromisifiedEval(callback, receiver, originalName, fn) {
|
|
var newParameterCount = Math.max(0, parameterCount(fn) - 1);
|
|
var argumentOrder = switchCaseArgumentOrder(newParameterCount);
|
|
|
|
var callbackName = (typeof originalName === "string" ?
|
|
originalName + "Async" :
|
|
"promisified");
|
|
|
|
function generateCallForArgumentCount(count) {
|
|
var args = new Array(count);
|
|
for (var i = 0, len = args.length; i < len; ++i) {
|
|
args[i] = "arguments[" + i + "]";
|
|
}
|
|
var comma = count > 0 ? "," : "";
|
|
|
|
if (typeof callback === "string" &&
|
|
receiver === THIS) {
|
|
return "this" + propertyAccess(callback) + "("+args.join(",") +
|
|
comma +" fn);"+
|
|
"break;";
|
|
}
|
|
return (receiver === void 0
|
|
? "callback("+args.join(",")+ comma +" fn);"
|
|
: "callback.call("+(receiver === THIS
|
|
? "this"
|
|
: "receiver")+", "+args.join(",") + comma + " fn);") +
|
|
"break;";
|
|
}
|
|
|
|
if (!rident.test(callbackName)) {
|
|
callbackName = "promisified";
|
|
}
|
|
|
|
function generateArgumentSwitchCase() {
|
|
var ret = "";
|
|
for(var i = 0; i < argumentOrder.length; ++i) {
|
|
ret += "case " + argumentOrder[i] +":" +
|
|
generateCallForArgumentCount(argumentOrder[i]);
|
|
}
|
|
ret += "default: var args = new Array(len + 1);" +
|
|
"var i = 0;" +
|
|
"for (var i = 0; i < len; ++i) { " +
|
|
" args[i] = arguments[i];" +
|
|
"}" +
|
|
"args[i] = fn;" +
|
|
|
|
(typeof callback === "string"
|
|
? "this" + propertyAccess(callback) + ".apply("
|
|
: "callback.apply(") +
|
|
|
|
(receiver === THIS ? "this" : "receiver") +
|
|
", args); break;";
|
|
return ret;
|
|
}
|
|
|
|
return new Function("Promise", "callback", "receiver",
|
|
"withAppended", "maybeWrapAsError", "nodebackForPromise",
|
|
"INTERNAL",
|
|
"var ret = function " + callbackName +
|
|
"(" + parameterDeclaration(newParameterCount) + ") {\"use strict\";" +
|
|
"var len = arguments.length;" +
|
|
"var promise = new Promise(INTERNAL);"+
|
|
"promise._setTrace(void 0);" +
|
|
"var fn = nodebackForPromise(promise);"+
|
|
"try {" +
|
|
"switch(len) {" +
|
|
generateArgumentSwitchCase() +
|
|
"}" +
|
|
"}" +
|
|
"catch(e){ " +
|
|
"var wrapped = maybeWrapAsError(e);" +
|
|
"promise._attachExtraTrace(wrapped);" +
|
|
"promise._reject(wrapped);" +
|
|
"}" +
|
|
"return promise;" +
|
|
"" +
|
|
"}; ret.__isPromisified__ = true; return ret;"
|
|
)(Promise, callback, receiver, withAppended,
|
|
maybeWrapAsError, nodebackForPromise, INTERNAL);
|
|
}
|
|
|
|
function makeNodePromisifiedClosure(callback, receiver) {
|
|
function promisified() {
|
|
var _receiver = receiver;
|
|
if (receiver === THIS) _receiver = this;
|
|
if (typeof callback === "string") {
|
|
callback = _receiver[callback];
|
|
}
|
|
var promise = new Promise(INTERNAL);
|
|
promise._setTrace(void 0);
|
|
var fn = nodebackForPromise(promise);
|
|
try {
|
|
callback.apply(_receiver, withAppended(arguments, fn));
|
|
}
|
|
catch(e) {
|
|
var wrapped = maybeWrapAsError(e);
|
|
promise._attachExtraTrace(wrapped);
|
|
promise._reject(wrapped);
|
|
}
|
|
return promise;
|
|
}
|
|
promisified.__isPromisified__ = true;
|
|
return promisified;
|
|
}
|
|
|
|
var makeNodePromisified = canEvaluate
|
|
? makeNodePromisifiedEval
|
|
: makeNodePromisifiedClosure;
|
|
|
|
function _promisify(callback, receiver, isAll) {
|
|
if (isAll) {
|
|
var methods = inheritedMethods(callback);
|
|
for (var i = 0, len = methods.length; i < len; i+= 2) {
|
|
var key = methods[i];
|
|
var fn = methods[i+1];
|
|
var promisifiedKey = key + "Async";
|
|
callback[promisifiedKey] = makeNodePromisified(key, THIS, key, fn);
|
|
}
|
|
util.toFastProperties(callback);
|
|
return callback;
|
|
}
|
|
else {
|
|
return makeNodePromisified(callback, receiver, void 0, callback);
|
|
}
|
|
}
|
|
|
|
Promise.promisify = function Promise$Promisify(fn, receiver) {
|
|
if (typeof fn === "object" && fn !== null) {
|
|
deprecated("Promise.promisify for promisifying entire objects is deprecated. Use Promise.promisifyAll instead.");
|
|
return _promisify(fn, receiver, true);
|
|
}
|
|
if (typeof fn !== "function") {
|
|
throw new TypeError("fn must be a function");
|
|
}
|
|
if (isPromisified(fn)) {
|
|
return fn;
|
|
}
|
|
return _promisify(
|
|
fn,
|
|
arguments.length < 2 ? THIS : receiver,
|
|
false);
|
|
};
|
|
|
|
Promise.promisifyAll = function Promise$PromisifyAll(target) {
|
|
if (typeof target !== "function" && typeof target !== "object") {
|
|
throw new TypeError("the target of promisifyAll must be an object or a function");
|
|
}
|
|
return _promisify(target, void 0, true);
|
|
};
|
|
};
|
|
|
|
|
|
},{"./errors":80,"./es5.js":82,"./promise_resolver.js":92,"./util.js":108}],95:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, PromiseArray) {
|
|
var util = _dereq_("./util.js");
|
|
var inherits = util.inherits;
|
|
var es5 = _dereq_("./es5.js");
|
|
|
|
function PropertiesPromiseArray(obj, boundTo) {
|
|
var keys = es5.keys(obj);
|
|
var values = new Array(keys.length);
|
|
for (var i = 0, len = values.length; i < len; ++i) {
|
|
values[i] = obj[keys[i]];
|
|
}
|
|
this.constructor$(values, boundTo);
|
|
if (!this._isResolved()) {
|
|
for (var i = 0, len = keys.length; i < len; ++i) {
|
|
values.push(keys[i]);
|
|
}
|
|
}
|
|
}
|
|
inherits(PropertiesPromiseArray, PromiseArray);
|
|
|
|
PropertiesPromiseArray.prototype._init =
|
|
function PropertiesPromiseArray$_init() {
|
|
this._init$(void 0, -3) ;
|
|
};
|
|
|
|
PropertiesPromiseArray.prototype._promiseFulfilled =
|
|
function PropertiesPromiseArray$_promiseFulfilled(value, index) {
|
|
if (this._isResolved()) return;
|
|
this._values[index] = value;
|
|
var totalResolved = ++this._totalResolved;
|
|
if (totalResolved >= this._length) {
|
|
var val = {};
|
|
var keyOffset = this.length();
|
|
for (var i = 0, len = this.length(); i < len; ++i) {
|
|
val[this._values[i + keyOffset]] = this._values[i];
|
|
}
|
|
this._resolve(val);
|
|
}
|
|
};
|
|
|
|
PropertiesPromiseArray.prototype._promiseProgressed =
|
|
function PropertiesPromiseArray$_promiseProgressed(value, index) {
|
|
if (this._isResolved()) return;
|
|
|
|
this._promise._progress({
|
|
key: this._values[index + this.length()],
|
|
value: value
|
|
});
|
|
};
|
|
|
|
PromiseArray.PropertiesPromiseArray = PropertiesPromiseArray;
|
|
|
|
return PropertiesPromiseArray;
|
|
};
|
|
|
|
},{"./es5.js":82,"./util.js":108}],96:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, PromiseArray) {
|
|
var PropertiesPromiseArray = _dereq_("./properties_promise_array.js")(
|
|
Promise, PromiseArray);
|
|
var util = _dereq_("./util.js");
|
|
var apiRejection = _dereq_("./errors_api_rejection")(Promise);
|
|
var isObject = util.isObject;
|
|
|
|
function Promise$_Props(promises, useBound) {
|
|
var ret;
|
|
var castValue = Promise._cast(promises, void 0);
|
|
|
|
if (!isObject(castValue)) {
|
|
return apiRejection("cannot await properties of a non-object");
|
|
}
|
|
else if (castValue instanceof Promise) {
|
|
ret = castValue._then(Promise.props, void 0, void 0,
|
|
void 0, void 0);
|
|
}
|
|
else {
|
|
ret = new PropertiesPromiseArray(
|
|
castValue,
|
|
useBound === true && castValue._isBound()
|
|
? castValue._boundTo
|
|
: void 0
|
|
).promise();
|
|
useBound = false;
|
|
}
|
|
if (useBound === true && castValue._isBound()) {
|
|
ret._setBoundTo(castValue._boundTo);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
Promise.prototype.props = function Promise$props() {
|
|
return Promise$_Props(this, true);
|
|
};
|
|
|
|
Promise.props = function Promise$Props(promises) {
|
|
return Promise$_Props(promises, false);
|
|
};
|
|
};
|
|
|
|
},{"./errors_api_rejection":81,"./properties_promise_array.js":95,"./util.js":108}],97:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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";
|
|
function arrayCopy(src, srcIndex, dst, dstIndex, len) {
|
|
for (var j = 0; j < len; ++j) {
|
|
dst[j + dstIndex] = src[j + srcIndex];
|
|
}
|
|
}
|
|
|
|
function pow2AtLeast(n) {
|
|
n = n >>> 0;
|
|
n = n - 1;
|
|
n = n | (n >> 1);
|
|
n = n | (n >> 2);
|
|
n = n | (n >> 4);
|
|
n = n | (n >> 8);
|
|
n = n | (n >> 16);
|
|
return n + 1;
|
|
}
|
|
|
|
function getCapacity(capacity) {
|
|
if (typeof capacity !== "number") return 16;
|
|
return pow2AtLeast(
|
|
Math.min(
|
|
Math.max(16, capacity), 1073741824)
|
|
);
|
|
}
|
|
|
|
function Queue(capacity) {
|
|
this._capacity = getCapacity(capacity);
|
|
this._length = 0;
|
|
this._front = 0;
|
|
this._makeCapacity();
|
|
}
|
|
|
|
Queue.prototype._willBeOverCapacity =
|
|
function Queue$_willBeOverCapacity(size) {
|
|
return this._capacity < size;
|
|
};
|
|
|
|
Queue.prototype._pushOne = function Queue$_pushOne(arg) {
|
|
var length = this.length();
|
|
this._checkCapacity(length + 1);
|
|
var i = (this._front + length) & (this._capacity - 1);
|
|
this[i] = arg;
|
|
this._length = length + 1;
|
|
};
|
|
|
|
Queue.prototype.push = function Queue$push(fn, receiver, arg) {
|
|
var length = this.length() + 3;
|
|
if (this._willBeOverCapacity(length)) {
|
|
this._pushOne(fn);
|
|
this._pushOne(receiver);
|
|
this._pushOne(arg);
|
|
return;
|
|
}
|
|
var j = this._front + length - 3;
|
|
this._checkCapacity(length);
|
|
var wrapMask = this._capacity - 1;
|
|
this[(j + 0) & wrapMask] = fn;
|
|
this[(j + 1) & wrapMask] = receiver;
|
|
this[(j + 2) & wrapMask] = arg;
|
|
this._length = length;
|
|
};
|
|
|
|
Queue.prototype.shift = function Queue$shift() {
|
|
var front = this._front,
|
|
ret = this[front];
|
|
|
|
this[front] = void 0;
|
|
this._front = (front + 1) & (this._capacity - 1);
|
|
this._length--;
|
|
return ret;
|
|
};
|
|
|
|
Queue.prototype.length = function Queue$length() {
|
|
return this._length;
|
|
};
|
|
|
|
Queue.prototype._makeCapacity = function Queue$_makeCapacity() {
|
|
var len = this._capacity;
|
|
for (var i = 0; i < len; ++i) {
|
|
this[i] = void 0;
|
|
}
|
|
};
|
|
|
|
Queue.prototype._checkCapacity = function Queue$_checkCapacity(size) {
|
|
if (this._capacity < size) {
|
|
this._resizeTo(this._capacity << 3);
|
|
}
|
|
};
|
|
|
|
Queue.prototype._resizeTo = function Queue$_resizeTo(capacity) {
|
|
var oldFront = this._front;
|
|
var oldCapacity = this._capacity;
|
|
var oldQueue = new Array(oldCapacity);
|
|
var length = this.length();
|
|
|
|
arrayCopy(this, 0, oldQueue, 0, oldCapacity);
|
|
this._capacity = capacity;
|
|
this._makeCapacity();
|
|
this._front = 0;
|
|
if (oldFront + length <= oldCapacity) {
|
|
arrayCopy(oldQueue, oldFront, this, 0, length);
|
|
}
|
|
else { var lengthBeforeWrapping =
|
|
length - ((oldFront + length) & (oldCapacity - 1));
|
|
|
|
arrayCopy(oldQueue, oldFront, this, 0, lengthBeforeWrapping);
|
|
arrayCopy(oldQueue, 0, this, lengthBeforeWrapping,
|
|
length - lengthBeforeWrapping);
|
|
}
|
|
};
|
|
|
|
module.exports = Queue;
|
|
|
|
},{}],98:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, INTERNAL) {
|
|
var apiRejection = _dereq_("./errors_api_rejection.js")(Promise);
|
|
var isArray = _dereq_("./util.js").isArray;
|
|
|
|
var raceLater = function Promise$_raceLater(promise) {
|
|
return promise.then(function(array) {
|
|
return Promise$_Race(array, promise);
|
|
});
|
|
};
|
|
|
|
var hasOwn = {}.hasOwnProperty;
|
|
function Promise$_Race(promises, parent) {
|
|
var maybePromise = Promise._cast(promises, void 0);
|
|
|
|
if (maybePromise instanceof Promise) {
|
|
return raceLater(maybePromise);
|
|
}
|
|
else if (!isArray(promises)) {
|
|
return apiRejection("expecting an array, a promise or a thenable");
|
|
}
|
|
|
|
var ret = new Promise(INTERNAL);
|
|
ret._setTrace(parent);
|
|
if (parent !== void 0) {
|
|
if (parent._isBound()) {
|
|
ret._setBoundTo(parent._boundTo);
|
|
}
|
|
if (parent._cancellable()) {
|
|
ret._setCancellable();
|
|
ret._cancellationParent = parent;
|
|
}
|
|
}
|
|
var fulfill = ret._fulfill;
|
|
var reject = ret._reject;
|
|
for (var i = 0, len = promises.length; i < len; ++i) {
|
|
var val = promises[i];
|
|
|
|
if (val === void 0 && !(hasOwn.call(promises, i))) {
|
|
continue;
|
|
}
|
|
|
|
Promise.cast(val)._then(
|
|
fulfill,
|
|
reject,
|
|
void 0,
|
|
ret,
|
|
null
|
|
);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
Promise.race = function Promise$Race(promises) {
|
|
return Promise$_Race(promises, void 0);
|
|
};
|
|
|
|
Promise.prototype.race = function Promise$race() {
|
|
return Promise$_Race(this, void 0);
|
|
};
|
|
|
|
};
|
|
|
|
},{"./errors_api_rejection.js":81,"./util.js":108}],99:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(
|
|
Promise, Promise$_CreatePromiseArray,
|
|
PromiseArray, apiRejection, INTERNAL) {
|
|
|
|
function Reduction(callback, index, accum, items, receiver) {
|
|
this.promise = new Promise(INTERNAL);
|
|
this.index = index;
|
|
this.length = items.length;
|
|
this.items = items;
|
|
this.callback = callback;
|
|
this.receiver = receiver;
|
|
this.accum = accum;
|
|
}
|
|
|
|
Reduction.prototype.reject = function Reduction$reject(e) {
|
|
this.promise._reject(e);
|
|
};
|
|
|
|
Reduction.prototype.fulfill = function Reduction$fulfill(value, index) {
|
|
this.accum = value;
|
|
this.index = index + 1;
|
|
this.iterate();
|
|
};
|
|
|
|
Reduction.prototype.iterate = function Reduction$iterate() {
|
|
var i = this.index;
|
|
var len = this.length;
|
|
var items = this.items;
|
|
var result = this.accum;
|
|
var receiver = this.receiver;
|
|
var callback = this.callback;
|
|
|
|
for (; i < len; ++i) {
|
|
result = callback.call(receiver, result, items[i], i, len);
|
|
result = Promise._cast(result, void 0);
|
|
|
|
if (result instanceof Promise) {
|
|
result._then(
|
|
this.fulfill, this.reject, void 0, this, i);
|
|
return;
|
|
}
|
|
}
|
|
this.promise._fulfill(result);
|
|
};
|
|
|
|
function Promise$_reducer(fulfilleds, initialValue) {
|
|
var fn = this;
|
|
var receiver = void 0;
|
|
if (typeof fn !== "function") {
|
|
receiver = fn.receiver;
|
|
fn = fn.fn;
|
|
}
|
|
var len = fulfilleds.length;
|
|
var accum = void 0;
|
|
var startIndex = 0;
|
|
|
|
if (initialValue !== void 0) {
|
|
accum = initialValue;
|
|
startIndex = 0;
|
|
}
|
|
else {
|
|
startIndex = 1;
|
|
if (len > 0) accum = fulfilleds[0];
|
|
}
|
|
var i = startIndex;
|
|
|
|
if (i >= len) {
|
|
return accum;
|
|
}
|
|
|
|
var reduction = new Reduction(fn, i, accum, fulfilleds, receiver);
|
|
reduction.iterate();
|
|
return reduction.promise;
|
|
}
|
|
|
|
function Promise$_unpackReducer(fulfilleds) {
|
|
var fn = this.fn;
|
|
var initialValue = this.initialValue;
|
|
return Promise$_reducer.call(fn, fulfilleds, initialValue);
|
|
}
|
|
|
|
function Promise$_slowReduce(
|
|
promises, fn, initialValue, useBound) {
|
|
return initialValue._then(function(initialValue) {
|
|
return Promise$_Reduce(
|
|
promises, fn, initialValue, useBound);
|
|
}, void 0, void 0, void 0, void 0);
|
|
}
|
|
|
|
function Promise$_Reduce(promises, fn, initialValue, useBound) {
|
|
if (typeof fn !== "function") {
|
|
return apiRejection("fn must be a function");
|
|
}
|
|
|
|
if (useBound === true && promises._isBound()) {
|
|
fn = {
|
|
fn: fn,
|
|
receiver: promises._boundTo
|
|
};
|
|
}
|
|
|
|
if (initialValue !== void 0) {
|
|
if (initialValue instanceof Promise) {
|
|
if (initialValue.isFulfilled()) {
|
|
initialValue = initialValue._settledValue;
|
|
}
|
|
else {
|
|
return Promise$_slowReduce(promises,
|
|
fn, initialValue, useBound);
|
|
}
|
|
}
|
|
|
|
return Promise$_CreatePromiseArray(promises, PromiseArray,
|
|
useBound === true && promises._isBound()
|
|
? promises._boundTo
|
|
: void 0)
|
|
.promise()
|
|
._then(Promise$_unpackReducer, void 0, void 0, {
|
|
fn: fn,
|
|
initialValue: initialValue
|
|
}, void 0);
|
|
}
|
|
return Promise$_CreatePromiseArray(promises, PromiseArray,
|
|
useBound === true && promises._isBound()
|
|
? promises._boundTo
|
|
: void 0).promise()
|
|
._then(Promise$_reducer, void 0, void 0, fn, void 0);
|
|
}
|
|
|
|
|
|
Promise.reduce = function Promise$Reduce(promises, fn, initialValue) {
|
|
return Promise$_Reduce(promises, fn, initialValue, false);
|
|
};
|
|
|
|
Promise.prototype.reduce = function Promise$reduce(fn, initialValue) {
|
|
return Promise$_Reduce(this, fn, initialValue, true);
|
|
};
|
|
};
|
|
|
|
},{}],100:[function(_dereq_,module,exports){
|
|
(function (process){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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 global = _dereq_("./global.js");
|
|
var schedule;
|
|
if (typeof process !== "undefined" && process !== null &&
|
|
typeof process.cwd === "function" &&
|
|
typeof process.nextTick === "function" &&
|
|
typeof process.version === "string") {
|
|
schedule = function Promise$_Scheduler(fn) {
|
|
process.nextTick(fn);
|
|
};
|
|
}
|
|
else if ((typeof global.MutationObserver === "function" ||
|
|
typeof global.WebkitMutationObserver === "function" ||
|
|
typeof global.WebKitMutationObserver === "function") &&
|
|
typeof document !== "undefined" &&
|
|
typeof document.createElement === "function") {
|
|
|
|
|
|
schedule = (function(){
|
|
var MutationObserver = global.MutationObserver ||
|
|
global.WebkitMutationObserver ||
|
|
global.WebKitMutationObserver;
|
|
var div = document.createElement("div");
|
|
var queuedFn = void 0;
|
|
var observer = new MutationObserver(
|
|
function Promise$_Scheduler() {
|
|
var fn = queuedFn;
|
|
queuedFn = void 0;
|
|
fn();
|
|
}
|
|
);
|
|
observer.observe(div, {
|
|
attributes: true
|
|
});
|
|
return function Promise$_Scheduler(fn) {
|
|
queuedFn = fn;
|
|
div.setAttribute("class", "foo");
|
|
};
|
|
|
|
})();
|
|
}
|
|
else if (typeof global.postMessage === "function" &&
|
|
typeof global.importScripts !== "function" &&
|
|
typeof global.addEventListener === "function" &&
|
|
typeof global.removeEventListener === "function") {
|
|
|
|
var MESSAGE_KEY = "bluebird_message_key_" + Math.random();
|
|
schedule = (function(){
|
|
var queuedFn = void 0;
|
|
|
|
function Promise$_Scheduler(e) {
|
|
if (e.source === global &&
|
|
e.data === MESSAGE_KEY) {
|
|
var fn = queuedFn;
|
|
queuedFn = void 0;
|
|
fn();
|
|
}
|
|
}
|
|
|
|
global.addEventListener("message", Promise$_Scheduler, false);
|
|
|
|
return function Promise$_Scheduler(fn) {
|
|
queuedFn = fn;
|
|
global.postMessage(
|
|
MESSAGE_KEY, "*"
|
|
);
|
|
};
|
|
|
|
})();
|
|
}
|
|
else if (typeof global.MessageChannel === "function") {
|
|
schedule = (function(){
|
|
var queuedFn = void 0;
|
|
|
|
var channel = new global.MessageChannel();
|
|
channel.port1.onmessage = function Promise$_Scheduler() {
|
|
var fn = queuedFn;
|
|
queuedFn = void 0;
|
|
fn();
|
|
};
|
|
|
|
return function Promise$_Scheduler(fn) {
|
|
queuedFn = fn;
|
|
channel.port2.postMessage(null);
|
|
};
|
|
})();
|
|
}
|
|
else if (global.setTimeout) {
|
|
schedule = function Promise$_Scheduler(fn) {
|
|
setTimeout(fn, 4);
|
|
};
|
|
}
|
|
else {
|
|
schedule = function Promise$_Scheduler(fn) {
|
|
fn();
|
|
};
|
|
}
|
|
|
|
module.exports = schedule;
|
|
|
|
}).call(this,_dereq_("C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"))
|
|
},{"./global.js":86,"C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":144}],101:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, Promise$_CreatePromiseArray, PromiseArray) {
|
|
|
|
var SettledPromiseArray = _dereq_("./settled_promise_array.js")(
|
|
Promise, PromiseArray);
|
|
|
|
function Promise$_Settle(promises, useBound) {
|
|
return Promise$_CreatePromiseArray(
|
|
promises,
|
|
SettledPromiseArray,
|
|
useBound === true && promises._isBound()
|
|
? promises._boundTo
|
|
: void 0
|
|
).promise();
|
|
}
|
|
|
|
Promise.settle = function Promise$Settle(promises) {
|
|
return Promise$_Settle(promises, false);
|
|
};
|
|
|
|
Promise.prototype.settle = function Promise$settle() {
|
|
return Promise$_Settle(this, true);
|
|
};
|
|
};
|
|
|
|
},{"./settled_promise_array.js":102}],102:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, PromiseArray) {
|
|
var PromiseInspection = Promise.PromiseInspection;
|
|
var util = _dereq_("./util.js");
|
|
var inherits = util.inherits;
|
|
function SettledPromiseArray(values, boundTo) {
|
|
this.constructor$(values, boundTo);
|
|
}
|
|
inherits(SettledPromiseArray, PromiseArray);
|
|
|
|
SettledPromiseArray.prototype._promiseResolved =
|
|
function SettledPromiseArray$_promiseResolved(index, inspection) {
|
|
this._values[index] = inspection;
|
|
var totalResolved = ++this._totalResolved;
|
|
if (totalResolved >= this._length) {
|
|
this._resolve(this._values);
|
|
}
|
|
};
|
|
|
|
SettledPromiseArray.prototype._promiseFulfilled =
|
|
function SettledPromiseArray$_promiseFulfilled(value, index) {
|
|
if (this._isResolved()) return;
|
|
var ret = new PromiseInspection();
|
|
ret._bitField = 268435456;
|
|
ret._settledValue = value;
|
|
this._promiseResolved(index, ret);
|
|
};
|
|
SettledPromiseArray.prototype._promiseRejected =
|
|
function SettledPromiseArray$_promiseRejected(reason, index) {
|
|
if (this._isResolved()) return;
|
|
var ret = new PromiseInspection();
|
|
ret._bitField = 134217728;
|
|
ret._settledValue = reason;
|
|
this._promiseResolved(index, ret);
|
|
};
|
|
|
|
return SettledPromiseArray;
|
|
};
|
|
|
|
},{"./util.js":108}],103:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, Promise$_CreatePromiseArray, PromiseArray, apiRejection) {
|
|
|
|
var SomePromiseArray = _dereq_("./some_promise_array.js")(PromiseArray);
|
|
function Promise$_Some(promises, howMany, useBound) {
|
|
if ((howMany | 0) !== howMany || howMany < 0) {
|
|
return apiRejection("expecting a positive integer");
|
|
}
|
|
var ret = Promise$_CreatePromiseArray(
|
|
promises,
|
|
SomePromiseArray,
|
|
useBound === true && promises._isBound()
|
|
? promises._boundTo
|
|
: void 0
|
|
);
|
|
var promise = ret.promise();
|
|
if (promise.isRejected()) {
|
|
return promise;
|
|
}
|
|
ret.setHowMany(howMany);
|
|
ret.init();
|
|
return promise;
|
|
}
|
|
|
|
Promise.some = function Promise$Some(promises, howMany) {
|
|
return Promise$_Some(promises, howMany, false);
|
|
};
|
|
|
|
Promise.prototype.some = function Promise$some(count) {
|
|
return Promise$_Some(this, count, true);
|
|
};
|
|
|
|
};
|
|
|
|
},{"./some_promise_array.js":104}],104:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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 (PromiseArray) {
|
|
var util = _dereq_("./util.js");
|
|
var RangeError = _dereq_("./errors.js").RangeError;
|
|
var inherits = util.inherits;
|
|
var isArray = util.isArray;
|
|
|
|
function SomePromiseArray(values, boundTo) {
|
|
this.constructor$(values, boundTo);
|
|
this._howMany = 0;
|
|
this._unwrap = false;
|
|
this._initialized = false;
|
|
}
|
|
inherits(SomePromiseArray, PromiseArray);
|
|
|
|
SomePromiseArray.prototype._init = function SomePromiseArray$_init() {
|
|
if (!this._initialized) {
|
|
return;
|
|
}
|
|
if (this._howMany === 0) {
|
|
this._resolve([]);
|
|
return;
|
|
}
|
|
this._init$(void 0, -2);
|
|
var isArrayResolved = isArray(this._values);
|
|
this._holes = isArrayResolved ? this._values.length - this.length() : 0;
|
|
|
|
if (!this._isResolved() &&
|
|
isArrayResolved &&
|
|
this._howMany > this._canPossiblyFulfill()) {
|
|
var message = "(Promise.some) input array contains less than " +
|
|
this._howMany + " promises";
|
|
this._reject(new RangeError(message));
|
|
}
|
|
};
|
|
|
|
SomePromiseArray.prototype.init = function SomePromiseArray$init() {
|
|
this._initialized = true;
|
|
this._init();
|
|
};
|
|
|
|
SomePromiseArray.prototype.setUnwrap = function SomePromiseArray$setUnwrap() {
|
|
this._unwrap = true;
|
|
};
|
|
|
|
SomePromiseArray.prototype.howMany = function SomePromiseArray$howMany() {
|
|
return this._howMany;
|
|
};
|
|
|
|
SomePromiseArray.prototype.setHowMany =
|
|
function SomePromiseArray$setHowMany(count) {
|
|
if (this._isResolved()) return;
|
|
this._howMany = count;
|
|
};
|
|
|
|
SomePromiseArray.prototype._promiseFulfilled =
|
|
function SomePromiseArray$_promiseFulfilled(value) {
|
|
if (this._isResolved()) return;
|
|
this._addFulfilled(value);
|
|
if (this._fulfilled() === this.howMany()) {
|
|
this._values.length = this.howMany();
|
|
if (this.howMany() === 1 && this._unwrap) {
|
|
this._resolve(this._values[0]);
|
|
}
|
|
else {
|
|
this._resolve(this._values);
|
|
}
|
|
}
|
|
|
|
};
|
|
SomePromiseArray.prototype._promiseRejected =
|
|
function SomePromiseArray$_promiseRejected(reason) {
|
|
if (this._isResolved()) return;
|
|
this._addRejected(reason);
|
|
if (this.howMany() > this._canPossiblyFulfill()) {
|
|
if (this._values.length === this.length()) {
|
|
this._reject([]);
|
|
}
|
|
else {
|
|
this._reject(this._values.slice(this.length() + this._holes));
|
|
}
|
|
}
|
|
};
|
|
|
|
SomePromiseArray.prototype._fulfilled = function SomePromiseArray$_fulfilled() {
|
|
return this._totalResolved;
|
|
};
|
|
|
|
SomePromiseArray.prototype._rejected = function SomePromiseArray$_rejected() {
|
|
return this._values.length - this.length() - this._holes;
|
|
};
|
|
|
|
SomePromiseArray.prototype._addRejected =
|
|
function SomePromiseArray$_addRejected(reason) {
|
|
this._values.push(reason);
|
|
};
|
|
|
|
SomePromiseArray.prototype._addFulfilled =
|
|
function SomePromiseArray$_addFulfilled(value) {
|
|
this._values[this._totalResolved++] = value;
|
|
};
|
|
|
|
SomePromiseArray.prototype._canPossiblyFulfill =
|
|
function SomePromiseArray$_canPossiblyFulfill() {
|
|
return this.length() - this._rejected();
|
|
};
|
|
|
|
return SomePromiseArray;
|
|
};
|
|
|
|
},{"./errors.js":80,"./util.js":108}],105:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise) {
|
|
function PromiseInspection(promise) {
|
|
if (promise !== void 0) {
|
|
this._bitField = promise._bitField;
|
|
this._settledValue = promise.isResolved()
|
|
? promise._settledValue
|
|
: void 0;
|
|
}
|
|
else {
|
|
this._bitField = 0;
|
|
this._settledValue = void 0;
|
|
}
|
|
}
|
|
|
|
PromiseInspection.prototype.isFulfilled =
|
|
Promise.prototype.isFulfilled = function Promise$isFulfilled() {
|
|
return (this._bitField & 268435456) > 0;
|
|
};
|
|
|
|
PromiseInspection.prototype.isRejected =
|
|
Promise.prototype.isRejected = function Promise$isRejected() {
|
|
return (this._bitField & 134217728) > 0;
|
|
};
|
|
|
|
PromiseInspection.prototype.isPending =
|
|
Promise.prototype.isPending = function Promise$isPending() {
|
|
return (this._bitField & 402653184) === 0;
|
|
};
|
|
|
|
PromiseInspection.prototype.value =
|
|
Promise.prototype.value = function Promise$value() {
|
|
if (!this.isFulfilled()) {
|
|
throw new TypeError("cannot get fulfillment value of a non-fulfilled promise");
|
|
}
|
|
return this._settledValue;
|
|
};
|
|
|
|
PromiseInspection.prototype.error =
|
|
Promise.prototype.reason = function Promise$reason() {
|
|
if (!this.isRejected()) {
|
|
throw new TypeError("cannot get rejection reason of a non-rejected promise");
|
|
}
|
|
return this._settledValue;
|
|
};
|
|
|
|
PromiseInspection.prototype.isResolved =
|
|
Promise.prototype.isResolved = function Promise$isResolved() {
|
|
return (this._bitField & 402653184) > 0;
|
|
};
|
|
|
|
Promise.prototype.inspect = function Promise$inspect() {
|
|
return new PromiseInspection(this);
|
|
};
|
|
|
|
Promise.PromiseInspection = PromiseInspection;
|
|
};
|
|
|
|
},{}],106:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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(Promise, INTERNAL) {
|
|
var util = _dereq_("./util.js");
|
|
var canAttach = _dereq_("./errors.js").canAttach;
|
|
var errorObj = util.errorObj;
|
|
var isObject = util.isObject;
|
|
|
|
function getThen(obj) {
|
|
try {
|
|
return obj.then;
|
|
}
|
|
catch(e) {
|
|
errorObj.e = e;
|
|
return errorObj;
|
|
}
|
|
}
|
|
|
|
function Promise$_Cast(obj, originalPromise) {
|
|
if (isObject(obj)) {
|
|
if (obj instanceof Promise) {
|
|
return obj;
|
|
}
|
|
else if (isAnyBluebirdPromise(obj)) {
|
|
var ret = new Promise(INTERNAL);
|
|
ret._setTrace(void 0);
|
|
obj._then(
|
|
ret._fulfillUnchecked,
|
|
ret._rejectUncheckedCheckError,
|
|
ret._progressUnchecked,
|
|
ret,
|
|
null
|
|
);
|
|
ret._setFollowing();
|
|
return ret;
|
|
}
|
|
var then = getThen(obj);
|
|
if (then === errorObj) {
|
|
if (originalPromise !== void 0 && canAttach(then.e)) {
|
|
originalPromise._attachExtraTrace(then.e);
|
|
}
|
|
return Promise.reject(then.e);
|
|
}
|
|
else if (typeof then === "function") {
|
|
return Promise$_doThenable(obj, then, originalPromise);
|
|
}
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
var hasProp = {}.hasOwnProperty;
|
|
function isAnyBluebirdPromise(obj) {
|
|
return hasProp.call(obj, "_promise0");
|
|
}
|
|
|
|
function Promise$_doThenable(x, then, originalPromise) {
|
|
var resolver = Promise.defer();
|
|
var called = false;
|
|
try {
|
|
then.call(
|
|
x,
|
|
Promise$_resolveFromThenable,
|
|
Promise$_rejectFromThenable,
|
|
Promise$_progressFromThenable
|
|
);
|
|
}
|
|
catch(e) {
|
|
if (!called) {
|
|
called = true;
|
|
var trace = canAttach(e) ? e : new Error(e + "");
|
|
if (originalPromise !== void 0) {
|
|
originalPromise._attachExtraTrace(trace);
|
|
}
|
|
resolver.promise._reject(e, trace);
|
|
}
|
|
}
|
|
return resolver.promise;
|
|
|
|
function Promise$_resolveFromThenable(y) {
|
|
if (called) return;
|
|
called = true;
|
|
|
|
if (x === y) {
|
|
var e = Promise._makeSelfResolutionError();
|
|
if (originalPromise !== void 0) {
|
|
originalPromise._attachExtraTrace(e);
|
|
}
|
|
resolver.promise._reject(e, void 0);
|
|
return;
|
|
}
|
|
resolver.resolve(y);
|
|
}
|
|
|
|
function Promise$_rejectFromThenable(r) {
|
|
if (called) return;
|
|
called = true;
|
|
var trace = canAttach(r) ? r : new Error(r + "");
|
|
if (originalPromise !== void 0) {
|
|
originalPromise._attachExtraTrace(trace);
|
|
}
|
|
resolver.promise._reject(r, trace);
|
|
}
|
|
|
|
function Promise$_progressFromThenable(v) {
|
|
if (called) return;
|
|
var promise = resolver.promise;
|
|
if (typeof promise._progress === "function") {
|
|
promise._progress(v);
|
|
}
|
|
}
|
|
}
|
|
|
|
Promise._cast = Promise$_Cast;
|
|
};
|
|
|
|
},{"./errors.js":80,"./util.js":108}],107:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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 global = _dereq_("./global.js");
|
|
var setTimeout = function(fn, ms) {
|
|
var $_len = arguments.length;var args = new Array($_len - 2); for(var $_i = 2; $_i < $_len; ++$_i) {args[$_i - 2] = arguments[$_i];}
|
|
global.setTimeout(function(){
|
|
fn.apply(void 0, args);
|
|
}, ms);
|
|
};
|
|
|
|
module.exports = function(Promise, INTERNAL) {
|
|
var util = _dereq_("./util.js");
|
|
var errors = _dereq_("./errors.js");
|
|
var apiRejection = _dereq_("./errors_api_rejection")(Promise);
|
|
var TimeoutError = Promise.TimeoutError;
|
|
|
|
var afterTimeout = function Promise$_afterTimeout(promise, message, ms) {
|
|
if (!promise.isPending()) return;
|
|
if (typeof message !== "string") {
|
|
message = "operation timed out after" + " " + ms + " ms"
|
|
}
|
|
var err = new TimeoutError(message);
|
|
errors.markAsOriginatingFromRejection(err);
|
|
promise._attachExtraTrace(err);
|
|
promise._rejectUnchecked(err);
|
|
};
|
|
|
|
var afterDelay = function Promise$_afterDelay(value, promise) {
|
|
promise._fulfill(value);
|
|
};
|
|
|
|
var delay = Promise.delay = function Promise$Delay(value, ms) {
|
|
if (ms === void 0) {
|
|
ms = value;
|
|
value = void 0;
|
|
}
|
|
ms = +ms;
|
|
var maybePromise = Promise._cast(value, void 0);
|
|
var promise = new Promise(INTERNAL);
|
|
|
|
if (maybePromise instanceof Promise) {
|
|
if (maybePromise._isBound()) {
|
|
promise._setBoundTo(maybePromise._boundTo);
|
|
}
|
|
if (maybePromise._cancellable()) {
|
|
promise._setCancellable();
|
|
promise._cancellationParent = maybePromise;
|
|
}
|
|
promise._setTrace(maybePromise);
|
|
promise._follow(maybePromise);
|
|
return promise.then(function(value) {
|
|
return Promise.delay(value, ms);
|
|
});
|
|
}
|
|
else {
|
|
promise._setTrace(void 0);
|
|
setTimeout(afterDelay, ms, value, promise);
|
|
}
|
|
return promise;
|
|
};
|
|
|
|
Promise.prototype.delay = function Promise$delay(ms) {
|
|
return delay(this, ms);
|
|
};
|
|
|
|
Promise.prototype.timeout = function Promise$timeout(ms, message) {
|
|
ms = +ms;
|
|
|
|
var ret = new Promise(INTERNAL);
|
|
ret._setTrace(this);
|
|
|
|
if (this._isBound()) ret._setBoundTo(this._boundTo);
|
|
if (this._cancellable()) {
|
|
ret._setCancellable();
|
|
ret._cancellationParent = this;
|
|
}
|
|
ret._follow(this);
|
|
setTimeout(afterTimeout, ms, ret, message, ms);
|
|
return ret;
|
|
};
|
|
|
|
};
|
|
|
|
},{"./errors.js":80,"./errors_api_rejection":81,"./global.js":86,"./util.js":108}],108:[function(_dereq_,module,exports){
|
|
/**
|
|
* Copyright (c) 2014 Petka Antonov
|
|
*
|
|
* 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:</p>
|
|
*
|
|
* 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 global = _dereq_("./global.js");
|
|
var es5 = _dereq_("./es5.js");
|
|
var haveGetters = (function(){
|
|
try {
|
|
var o = {};
|
|
es5.defineProperty(o, "f", {
|
|
get: function () {
|
|
return 3;
|
|
}
|
|
});
|
|
return o.f === 3;
|
|
}
|
|
catch (e) {
|
|
return false;
|
|
}
|
|
|
|
})();
|
|
|
|
var canEvaluate = (function() {
|
|
if (typeof window !== "undefined" && window !== null &&
|
|
typeof window.document !== "undefined" &&
|
|
typeof navigator !== "undefined" && navigator !== null &&
|
|
typeof navigator.appName === "string" &&
|
|
window === global) {
|
|
return false;
|
|
}
|
|
return true;
|
|
})();
|
|
|
|
function deprecated(msg) {
|
|
if (typeof console !== "undefined" && console !== null &&
|
|
typeof console.warn === "function") {
|
|
console.warn("Bluebird: " + msg);
|
|
}
|
|
}
|
|
|
|
var errorObj = {e: {}};
|
|
function tryCatch1(fn, receiver, arg) {
|
|
try {
|
|
return fn.call(receiver, arg);
|
|
}
|
|
catch (e) {
|
|
errorObj.e = e;
|
|
return errorObj;
|
|
}
|
|
}
|
|
|
|
function tryCatch2(fn, receiver, arg, arg2) {
|
|
try {
|
|
return fn.call(receiver, arg, arg2);
|
|
}
|
|
catch (e) {
|
|
errorObj.e = e;
|
|
return errorObj;
|
|
}
|
|
}
|
|
|
|
function tryCatchApply(fn, args, receiver) {
|
|
try {
|
|
return fn.apply(receiver, args);
|
|
}
|
|
catch (e) {
|
|
errorObj.e = e;
|
|
return errorObj;
|
|
}
|
|
}
|
|
|
|
var inherits = function(Child, Parent) {
|
|
var hasProp = {}.hasOwnProperty;
|
|
|
|
function T() {
|
|
this.constructor = Child;
|
|
this.constructor$ = Parent;
|
|
for (var propertyName in Parent.prototype) {
|
|
if (hasProp.call(Parent.prototype, propertyName) &&
|
|
propertyName.charAt(propertyName.length-1) !== "$"
|
|
) {
|
|
this[propertyName + "$"] = Parent.prototype[propertyName];
|
|
}
|
|
}
|
|
}
|
|
T.prototype = Parent.prototype;
|
|
Child.prototype = new T();
|
|
return Child.prototype;
|
|
};
|
|
|
|
function asString(val) {
|
|
return typeof val === "string" ? val : ("" + val);
|
|
}
|
|
|
|
function isPrimitive(val) {
|
|
return val == null || val === true || val === false ||
|
|
typeof val === "string" || typeof val === "number";
|
|
|
|
}
|
|
|
|
function isObject(value) {
|
|
return !isPrimitive(value);
|
|
}
|
|
|
|
function maybeWrapAsError(maybeError) {
|
|
if (!isPrimitive(maybeError)) return maybeError;
|
|
|
|
return new Error(asString(maybeError));
|
|
}
|
|
|
|
function withAppended(target, appendee) {
|
|
var len = target.length;
|
|
var ret = new Array(len + 1);
|
|
var i;
|
|
for (i = 0; i < len; ++i) {
|
|
ret[i] = target[i];
|
|
}
|
|
ret[i] = appendee;
|
|
return ret;
|
|
}
|
|
|
|
|
|
function notEnumerableProp(obj, name, value) {
|
|
if (isPrimitive(obj)) return obj;
|
|
var descriptor = {
|
|
value: value,
|
|
configurable: true,
|
|
enumerable: false,
|
|
writable: true
|
|
};
|
|
es5.defineProperty(obj, name, descriptor);
|
|
return obj;
|
|
}
|
|
|
|
|
|
var wrapsPrimitiveReceiver = (function() {
|
|
return this !== "string";
|
|
}).call("string");
|
|
|
|
function thrower(r) {
|
|
throw r;
|
|
}
|
|
|
|
|
|
function toFastProperties(obj) {
|
|
/*jshint -W027*/
|
|
function f() {}
|
|
f.prototype = obj;
|
|
return f;
|
|
eval(obj);
|
|
}
|
|
|
|
var ret = {
|
|
thrower: thrower,
|
|
isArray: es5.isArray,
|
|
haveGetters: haveGetters,
|
|
notEnumerableProp: notEnumerableProp,
|
|
isPrimitive: isPrimitive,
|
|
isObject: isObject,
|
|
canEvaluate: canEvaluate,
|
|
deprecated: deprecated,
|
|
errorObj: errorObj,
|
|
tryCatch1: tryCatch1,
|
|
tryCatch2: tryCatch2,
|
|
tryCatchApply: tryCatchApply,
|
|
inherits: inherits,
|
|
withAppended: withAppended,
|
|
asString: asString,
|
|
maybeWrapAsError: maybeWrapAsError,
|
|
wrapsPrimitiveReceiver: wrapsPrimitiveReceiver,
|
|
toFastProperties: toFastProperties
|
|
};
|
|
|
|
module.exports = ret;
|
|
|
|
},{"./es5.js":82,"./global.js":86}],109:[function(_dereq_,module,exports){
|
|
|
|
/**
|
|
* Module dependencies.
|
|
*/
|
|
|
|
var global = (function() { return this; })();
|
|
|
|
/**
|
|
* WebSocket constructor.
|
|
*/
|
|
|
|
var WebSocket = global.WebSocket || global.MozWebSocket;
|
|
|
|
/**
|
|
* Module exports.
|
|
*/
|
|
|
|
module.exports = WebSocket ? ws : null;
|
|
|
|
/**
|
|
* WebSocket constructor.
|
|
*
|
|
* The third `opts` options object gets ignored in web browsers, since it's
|
|
* non-standard, and throws a TypeError if passed to the constructor.
|
|
* See: https://github.com/einaros/ws/issues/227
|
|
*
|
|
* @param {String} uri
|
|
* @param {Array} protocols (optional)
|
|
* @param {Object) opts (optional)
|
|
* @api public
|
|
*/
|
|
|
|
function ws(uri, protocols, opts) {
|
|
var instance;
|
|
if (protocols) {
|
|
instance = new WebSocket(uri, protocols);
|
|
} else {
|
|
instance = new WebSocket(uri);
|
|
}
|
|
return instance;
|
|
}
|
|
|
|
if (WebSocket) ws.prototype = WebSocket.prototype;
|
|
|
|
},{}],110:[function(_dereq_,module,exports){
|
|
module.exports = _dereq_('./lib/hypertimer');
|
|
|
|
},{"./lib/hypertimer":111}],111:[function(_dereq_,module,exports){
|
|
var util = _dereq_('./util');
|
|
|
|
// enum for type of timeout
|
|
var TYPE = {
|
|
TIMEOUT: 0,
|
|
INTERVAL: 1,
|
|
TRIGGER: 2
|
|
};
|
|
|
|
var DISCRETE = 'discrete';
|
|
|
|
/**
|
|
* Create a new hypertimer
|
|
* @param {Object} [options] The following options are available:
|
|
* rate: number | 'discrete'
|
|
* The rate of speed of hyper time with
|
|
* respect to real-time in milliseconds
|
|
* per millisecond. Rate must be a
|
|
* positive number, or 'discrete' to
|
|
* run in discrete time (jumping from
|
|
* event to event). By default, rate is 1.
|
|
* deterministic: boolean
|
|
* If true (default), simultaneous events
|
|
* are executed in a deterministic order.
|
|
*/
|
|
function hypertimer(options) {
|
|
// options
|
|
var rate = 1; // number of milliseconds per milliseconds
|
|
var deterministic = true; // run simultaneous events in a deterministic order
|
|
|
|
// properties
|
|
var running = false; // true when running
|
|
var realTime = null; // timestamp. the moment in real-time when hyperTime was set
|
|
var hyperTime = null; // timestamp. the start time in hyper-time
|
|
var timeouts = []; // array with all running timeouts
|
|
var current = {}; // the timeouts currently in progress (callback is being executed)
|
|
var timeoutId = null; // currently running timer
|
|
var idSeq = 0; // counter for unique timeout id's
|
|
|
|
// exported timer object with public functions and variables
|
|
var timer = {};
|
|
|
|
/**
|
|
* Change configuration options of the hypertimer, or retrieve current
|
|
* configuration.
|
|
* @param {Object} [options] The following options are available:
|
|
* rate: number | 'discrete'
|
|
* The rate of speed of hyper time with
|
|
* respect to real-time in milliseconds
|
|
* per millisecond. Rate must be a
|
|
* positive number, or 'discrete' to
|
|
* run in discrete time (jumping from
|
|
* event to event). By default, rate is 1.
|
|
* deterministic: boolean
|
|
* If true (default), simultaneous events
|
|
* are executed in a deterministic order.
|
|
* @return {Object} Returns the applied configuration
|
|
*/
|
|
timer.config = function(options) {
|
|
if (options) {
|
|
if ('rate' in options) {
|
|
var newRate = (options.rate === DISCRETE) ? DISCRETE : Number(options.rate);
|
|
if (newRate !== DISCRETE && (isNaN(newRate) || newRate <= 0)) {
|
|
throw new TypeError('rate must be a positive number or the string "discrete"');
|
|
}
|
|
hyperTime = timer.now();
|
|
realTime = util.nowReal();
|
|
rate = newRate;
|
|
}
|
|
if ('deterministic' in options) {
|
|
deterministic = options.deterministic ? true : false;
|
|
}
|
|
}
|
|
|
|
// reschedule running timeouts
|
|
_schedule();
|
|
|
|
// return a copy of the configuration options
|
|
return {
|
|
rate: rate,
|
|
deterministic: deterministic
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Set the time of the timer. To get the current time, use getTime() or now().
|
|
* @param {number | Date} time The time in hyper-time.
|
|
*/
|
|
timer.setTime = function (time) {
|
|
if (time instanceof Date) {
|
|
hyperTime = time.valueOf();
|
|
}
|
|
else {
|
|
var newTime = Number(time);
|
|
if (isNaN(newTime)) {
|
|
throw new TypeError('time must be a Date or number');
|
|
}
|
|
hyperTime = newTime;
|
|
}
|
|
|
|
// reschedule running timeouts
|
|
_schedule();
|
|
};
|
|
|
|
/**
|
|
* Returns the current time of the timer as a number.
|
|
* See also getTime().
|
|
* @return {number} The time
|
|
*/
|
|
timer.now = function () {
|
|
if (rate === DISCRETE) {
|
|
return hyperTime;
|
|
}
|
|
else {
|
|
if (running) {
|
|
// TODO: implement performance.now() / process.hrtime(time) for high precision calculation of time interval
|
|
var realInterval = util.nowReal() - realTime;
|
|
var hyperInterval = realInterval * rate;
|
|
return hyperTime + hyperInterval;
|
|
}
|
|
else {
|
|
return hyperTime;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Continue the timer.
|
|
*/
|
|
timer['continue'] = function() {
|
|
realTime = util.nowReal();
|
|
running = true;
|
|
|
|
// reschedule running timeouts
|
|
_schedule();
|
|
};
|
|
|
|
/**
|
|
* Pause the timer. The timer can be continued again with `continue()`
|
|
*/
|
|
timer.pause = function() {
|
|
hyperTime = timer.now();
|
|
realTime = null;
|
|
running = false;
|
|
|
|
// reschedule running timeouts (pauses them)
|
|
_schedule();
|
|
};
|
|
|
|
/**
|
|
* Returns the current time of the timer as Date.
|
|
* See also now().
|
|
* @return {Date} The time
|
|
*/
|
|
// rename to getTime
|
|
timer.getTime = function() {
|
|
return new Date(timer.now());
|
|
};
|
|
|
|
/**
|
|
* Get the value of the hypertimer. This function returns the result of getTime().
|
|
* @return {Date} current time
|
|
*/
|
|
timer.valueOf = timer.getTime;
|
|
|
|
/**
|
|
* Return a string representation of the current hyper-time.
|
|
* @returns {string} String representation
|
|
*/
|
|
timer.toString = function () {
|
|
return timer.getTime().toString();
|
|
};
|
|
|
|
/**
|
|
* Set a timeout, which is triggered when the timeout occurs in hyper-time.
|
|
* See also setTrigger.
|
|
* @param {Function} callback Function executed when delay is exceeded.
|
|
* @param {number} delay The delay in milliseconds. When the delay is
|
|
* smaller or equal to zero, the callback is
|
|
* triggered immediately.
|
|
* @return {number} Returns a timeoutId which can be used to cancel the
|
|
* timeout using clearTimeout().
|
|
*/
|
|
timer.setTimeout = function(callback, delay) {
|
|
var id = idSeq++;
|
|
var timestamp = timer.now() + delay;
|
|
if (isNaN(timestamp)) {
|
|
throw new TypeError('delay must be a number');
|
|
}
|
|
|
|
// add a new timeout to the queue
|
|
_queueTimeout({
|
|
id: id,
|
|
type: TYPE.TIMEOUT,
|
|
time: timestamp,
|
|
callback: callback
|
|
});
|
|
|
|
// reschedule the timeouts
|
|
_schedule();
|
|
|
|
return id;
|
|
};
|
|
|
|
/**
|
|
* Set a trigger, which is triggered when the timeout occurs in hyper-time.
|
|
* See also getTimeout.
|
|
* @param {Function} callback Function executed when timeout occurs.
|
|
* @param {Date | number} time An absolute moment in time (Date) when the
|
|
* callback will be triggered. When the date is
|
|
* a Date in the past, the callback is triggered
|
|
* immediately.
|
|
* @return {number} Returns a triggerId which can be used to cancel the
|
|
* trigger using clearTrigger().
|
|
*/
|
|
timer.setTrigger = function (callback, time) {
|
|
var id = idSeq++;
|
|
var timestamp = Number(time);
|
|
if (isNaN(timestamp)) {
|
|
throw new TypeError('time must be a Date or number');
|
|
}
|
|
|
|
// add a new timeout to the queue
|
|
_queueTimeout({
|
|
id: id,
|
|
type: TYPE.TRIGGER,
|
|
time: timestamp,
|
|
callback: callback
|
|
});
|
|
|
|
// reschedule the timeouts
|
|
_schedule();
|
|
|
|
return id;
|
|
};
|
|
|
|
|
|
/**
|
|
* Trigger a callback every interval. Optionally, a start date can be provided
|
|
* to specify the first time the callback must be triggered.
|
|
* See also setTimeout and setTrigger.
|
|
* @param {Function} callback Function executed when delay is exceeded.
|
|
* @param {number} interval Interval in milliseconds. When interval
|
|
* is smaller than zero or is infinity, the
|
|
* interval will be set to zero and triggered
|
|
* with a maximum rate.
|
|
* @param {Date | number} [firstTime] An absolute moment in time (Date) when the
|
|
* callback will be triggered the first time.
|
|
* By default, firstTime = now() + interval.
|
|
* @return {number} Returns a intervalId which can be used to cancel the
|
|
* trigger using clearInterval().
|
|
*/
|
|
timer.setInterval = function(callback, interval, firstTime) {
|
|
var id = idSeq++;
|
|
|
|
var _interval = Number(interval);
|
|
if (isNaN(_interval)) {
|
|
throw new TypeError('interval must be a number');
|
|
}
|
|
if (_interval < 0 || !isFinite(_interval)) {
|
|
_interval = 0;
|
|
}
|
|
|
|
var timestamp;
|
|
if (firstTime != undefined) {
|
|
timestamp = Number(firstTime);
|
|
if (isNaN(timestamp)) {
|
|
throw new TypeError('firstTime must be a Date or number');
|
|
}
|
|
}
|
|
else {
|
|
// firstTime is undefined or null
|
|
timestamp = (timer.now() + _interval);
|
|
}
|
|
|
|
// add a new timeout to the queue
|
|
_queueTimeout({
|
|
id: id,
|
|
type: TYPE.INTERVAL,
|
|
interval: _interval,
|
|
time: timestamp,
|
|
firstTime: timestamp,
|
|
occurrence: 0,
|
|
callback: callback
|
|
});
|
|
|
|
// reschedule the timeouts
|
|
_schedule();
|
|
|
|
return id;
|
|
};
|
|
|
|
/**
|
|
* Cancel a timeout
|
|
* @param {number} timeoutId The id of a timeout
|
|
*/
|
|
timer.clearTimeout = function(timeoutId) {
|
|
// test whether timeout is currently being executed
|
|
if (current[timeoutId]) {
|
|
delete current[timeoutId];
|
|
return;
|
|
}
|
|
|
|
// find the timeout in the queue
|
|
for (var i = 0; i < timeouts.length; i++) {
|
|
if (timeouts[i].id === timeoutId) {
|
|
// remove this timeout from the queue
|
|
timeouts.splice(i, 1);
|
|
|
|
// reschedule timeouts
|
|
_schedule();
|
|
break;
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Cancel a trigger
|
|
* @param {number} triggerId The id of a trigger
|
|
*/
|
|
timer.clearTrigger = timer.clearTimeout;
|
|
|
|
timer.clearInterval = timer.clearTimeout;
|
|
|
|
/**
|
|
* Returns a list with the id's of all timeouts
|
|
* @returns {number[]} Timeout id's
|
|
*/
|
|
timer.list = function () {
|
|
return timeouts.map(function (timeout) {
|
|
return timeout.id;
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Clear all timeouts
|
|
*/
|
|
timer.clear = function () {
|
|
// empty the queue
|
|
current = {};
|
|
timeouts = [];
|
|
|
|
// reschedule
|
|
_schedule();
|
|
};
|
|
|
|
/**
|
|
* Add a timeout to the queue. After the queue has been changed, the queue
|
|
* must be rescheduled by executing _reschedule()
|
|
* @param {{id: number, type: number, time: number, callback: Function}} timeout
|
|
* @private
|
|
*/
|
|
function _queueTimeout(timeout) {
|
|
// insert the new timeout at the right place in the array, sorted by time
|
|
if (timeouts.length > 0) {
|
|
var i = timeouts.length - 1;
|
|
while (i >= 0 && timeouts[i].time > timeout.time) {
|
|
i--;
|
|
}
|
|
|
|
// insert the new timeout in the queue. Note that the timeout is
|
|
// inserted *after* existing timeouts with the exact *same* time,
|
|
// so the order in which they are executed is deterministic
|
|
timeouts.splice(i + 1, 0, timeout);
|
|
}
|
|
else {
|
|
// queue is empty, append the new timeout
|
|
timeouts.push(timeout);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Execute a timeout
|
|
* @param {{id: number, type: number, time: number, callback: function}} timeout
|
|
* @param {function} [callback]
|
|
* The callback is executed when the timeout's callback is
|
|
* finished. Called without parameters
|
|
* @private
|
|
*/
|
|
function _execTimeout(timeout, callback) {
|
|
// store the timeout in the queue with timeouts in progress
|
|
// it can be cleared when a clearTimeout is executed inside the callback
|
|
current[timeout.id] = timeout;
|
|
|
|
function finish() {
|
|
// in case of an interval we have to reschedule on next cycle
|
|
// interval must not be cleared while executing the callback
|
|
if (timeout.type === TYPE.INTERVAL && current[timeout.id]) {
|
|
timeout.occurrence++;
|
|
timeout.time = timeout.firstTime + timeout.occurrence * timeout.interval;
|
|
_queueTimeout(timeout);
|
|
}
|
|
|
|
// remove the timeout from the queue with timeouts in progress
|
|
delete current[timeout.id];
|
|
|
|
if (typeof callback === 'function') callback();
|
|
}
|
|
|
|
// execute the callback
|
|
try {
|
|
if (timeout.callback.length == 0) {
|
|
// synchronous timeout, like `timer.setTimeout(function () {...}, delay)`
|
|
timeout.callback();
|
|
finish();
|
|
} else {
|
|
// asynchronous timeout, like `timer.setTimeout(function (done) {...; done(); }, delay)`
|
|
timeout.callback(finish);
|
|
}
|
|
} catch (err) {
|
|
// silently ignore errors thrown by the callback
|
|
finish();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove all timeouts occurring before or on the provided time from the
|
|
* queue and return them.
|
|
* @param {number} time A timestamp
|
|
* @returns {Array} returns an array containing all expired timeouts
|
|
* @private
|
|
*/
|
|
function _getExpiredTimeouts(time) {
|
|
var i = 0;
|
|
while (i < timeouts.length && ((timeouts[i].time <= time) || !isFinite(timeouts[i].time))) {
|
|
i++;
|
|
}
|
|
var expired = timeouts.splice(0, i);
|
|
|
|
if (deterministic == false) {
|
|
// the array with expired timeouts is in deterministic order
|
|
// shuffle them
|
|
util.shuffle(expired);
|
|
}
|
|
|
|
return expired;
|
|
}
|
|
|
|
/**
|
|
* Reschedule all queued timeouts
|
|
* @private
|
|
*/
|
|
function _schedule() {
|
|
// do not _schedule when there are timeouts in progress
|
|
// this can be the case with async timeouts in discrete time.
|
|
// _schedule will be executed again when all async timeouts are finished.
|
|
if (rate === DISCRETE && Object.keys(current).length > 0) {
|
|
return;
|
|
}
|
|
|
|
var next = timeouts[0];
|
|
|
|
// cancel timer when running
|
|
if (timeoutId) {
|
|
clearTimeout(timeoutId);
|
|
timeoutId = null;
|
|
}
|
|
|
|
if (running && next) {
|
|
// schedule next timeout
|
|
var time = next.time;
|
|
var delay = time - timer.now();
|
|
var realDelay = (rate === DISCRETE) ? 0 : delay / rate;
|
|
|
|
function onTimeout() {
|
|
// when running in discrete time, update the hyperTime to the time
|
|
// of the current event
|
|
if (rate === DISCRETE) {
|
|
hyperTime = time;
|
|
}
|
|
|
|
// grab all expired timeouts from the queue
|
|
var expired = _getExpiredTimeouts(time);
|
|
// note: expired.length can never be zero (on every change of the queue, we reschedule)
|
|
|
|
// execute all expired timeouts
|
|
if (rate === DISCRETE) {
|
|
// in discrete time, we execute all expired timeouts serially,
|
|
// and wait for their completion in order to guarantee deterministic
|
|
// order of execution
|
|
function next() {
|
|
var timeout = expired.shift();
|
|
if (timeout) {
|
|
_execTimeout(timeout, next);
|
|
}
|
|
else {
|
|
// schedule the next round
|
|
_schedule();
|
|
}
|
|
}
|
|
next();
|
|
}
|
|
else {
|
|
// in continuous time, we fire all timeouts in parallel,
|
|
// and don't await their completion (they can do async operations)
|
|
expired.forEach(_execTimeout);
|
|
|
|
// schedule the next round
|
|
_schedule();
|
|
}
|
|
}
|
|
|
|
timeoutId = setTimeout(onTimeout, realDelay);
|
|
}
|
|
}
|
|
|
|
Object.defineProperty(timer, 'running', {
|
|
get: function () {
|
|
return running;
|
|
}
|
|
});
|
|
|
|
timer.config(options); // apply options
|
|
timer.setTime(util.nowReal()); // set time as current real time
|
|
timer.continue(); // start the timer
|
|
|
|
return timer;
|
|
}
|
|
|
|
module.exports = hypertimer;
|
|
|
|
},{"./util":112}],112:[function(_dereq_,module,exports){
|
|
|
|
/* istanbul ignore else */
|
|
if (typeof Date.now === 'function') {
|
|
/**
|
|
* Helper function to get the current time
|
|
* @return {number} Current time
|
|
*/
|
|
exports.nowReal = function () {
|
|
return Date.now();
|
|
}
|
|
}
|
|
else {
|
|
/**
|
|
* Helper function to get the current time
|
|
* @return {number} Current time
|
|
*/
|
|
exports.nowReal = function () {
|
|
return new Date().valueOf();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Shuffle an array
|
|
*
|
|
* + Jonas Raoni Soares Silva
|
|
* @ http://jsfromhell.com/array/shuffle [v1.0]
|
|
*
|
|
* @param {Array} o Array to be shuffled
|
|
* @returns {Array} Returns the shuffled array
|
|
*/
|
|
exports.shuffle = function (o){
|
|
for(var j, x, i = o.length; i; j = Math.floor(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
|
|
return o;
|
|
};
|
|
|
|
},{}],113:[function(_dereq_,module,exports){
|
|
(function (Buffer){
|
|
// uuid.js
|
|
//
|
|
// Copyright (c) 2010-2012 Robert Kieffer
|
|
// MIT License - http://opensource.org/licenses/mit-license.php
|
|
|
|
(function() {
|
|
var _global = this;
|
|
|
|
// Unique ID creation requires a high quality random # generator. We feature
|
|
// detect to determine the best RNG source, normalizing to a function that
|
|
// returns 128-bits of randomness, since that's what's usually required
|
|
var _rng;
|
|
|
|
// Node.js crypto-based RNG - http://nodejs.org/docs/v0.6.2/api/crypto.html
|
|
//
|
|
// Moderately fast, high quality
|
|
if (typeof(_dereq_) == 'function') {
|
|
try {
|
|
var _rb = _dereq_('crypto').randomBytes;
|
|
_rng = _rb && function() {return _rb(16);};
|
|
} catch(e) {}
|
|
}
|
|
|
|
if (!_rng && _global.crypto && crypto.getRandomValues) {
|
|
// WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto
|
|
//
|
|
// Moderately fast, high quality
|
|
var _rnds8 = new Uint8Array(16);
|
|
_rng = function whatwgRNG() {
|
|
crypto.getRandomValues(_rnds8);
|
|
return _rnds8;
|
|
};
|
|
}
|
|
|
|
if (!_rng) {
|
|
// Math.random()-based (RNG)
|
|
//
|
|
// If all else fails, use Math.random(). It's fast, but is of unspecified
|
|
// quality.
|
|
var _rnds = new Array(16);
|
|
_rng = function() {
|
|
for (var i = 0, r; i < 16; i++) {
|
|
if ((i & 0x03) === 0) r = Math.random() * 0x100000000;
|
|
_rnds[i] = r >>> ((i & 0x03) << 3) & 0xff;
|
|
}
|
|
|
|
return _rnds;
|
|
};
|
|
}
|
|
|
|
// Buffer class to use
|
|
var BufferClass = typeof(Buffer) == 'function' ? Buffer : Array;
|
|
|
|
// Maps for number <-> hex string conversion
|
|
var _byteToHex = [];
|
|
var _hexToByte = {};
|
|
for (var i = 0; i < 256; i++) {
|
|
_byteToHex[i] = (i + 0x100).toString(16).substr(1);
|
|
_hexToByte[_byteToHex[i]] = i;
|
|
}
|
|
|
|
// **`parse()` - Parse a UUID into it's component bytes**
|
|
function parse(s, buf, offset) {
|
|
var i = (buf && offset) || 0, ii = 0;
|
|
|
|
buf = buf || [];
|
|
s.toLowerCase().replace(/[0-9a-f]{2}/g, function(oct) {
|
|
if (ii < 16) { // Don't overflow!
|
|
buf[i + ii++] = _hexToByte[oct];
|
|
}
|
|
});
|
|
|
|
// Zero out remaining bytes if string was short
|
|
while (ii < 16) {
|
|
buf[i + ii++] = 0;
|
|
}
|
|
|
|
return buf;
|
|
}
|
|
|
|
// **`unparse()` - Convert UUID byte array (ala parse()) into a string**
|
|
function unparse(buf, offset) {
|
|
var i = offset || 0, bth = _byteToHex;
|
|
return bth[buf[i++]] + bth[buf[i++]] +
|
|
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
bth[buf[i++]] + bth[buf[i++]] + '-' +
|
|
bth[buf[i++]] + bth[buf[i++]] +
|
|
bth[buf[i++]] + bth[buf[i++]] +
|
|
bth[buf[i++]] + bth[buf[i++]];
|
|
}
|
|
|
|
// **`v1()` - Generate time-based UUID**
|
|
//
|
|
// Inspired by https://github.com/LiosK/UUID.js
|
|
// and http://docs.python.org/library/uuid.html
|
|
|
|
// random #'s we need to init node and clockseq
|
|
var _seedBytes = _rng();
|
|
|
|
// Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
|
|
var _nodeId = [
|
|
_seedBytes[0] | 0x01,
|
|
_seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5]
|
|
];
|
|
|
|
// Per 4.2.2, randomize (14 bit) clockseq
|
|
var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff;
|
|
|
|
// Previous uuid creation time
|
|
var _lastMSecs = 0, _lastNSecs = 0;
|
|
|
|
// See https://github.com/broofa/node-uuid for API details
|
|
function v1(options, buf, offset) {
|
|
var i = buf && offset || 0;
|
|
var b = buf || [];
|
|
|
|
options = options || {};
|
|
|
|
var clockseq = options.clockseq != null ? options.clockseq : _clockseq;
|
|
|
|
// UUID timestamps are 100 nano-second units since the Gregorian epoch,
|
|
// (1582-10-15 00:00). JSNumbers aren't precise enough for this, so
|
|
// time is handled internally as 'msecs' (integer milliseconds) and 'nsecs'
|
|
// (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00.
|
|
var msecs = options.msecs != null ? options.msecs : new Date().getTime();
|
|
|
|
// Per 4.2.1.2, use count of uuid's generated during the current clock
|
|
// cycle to simulate higher resolution clock
|
|
var nsecs = options.nsecs != null ? options.nsecs : _lastNSecs + 1;
|
|
|
|
// Time since last uuid creation (in msecs)
|
|
var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs)/10000;
|
|
|
|
// Per 4.2.1.2, Bump clockseq on clock regression
|
|
if (dt < 0 && options.clockseq == null) {
|
|
clockseq = clockseq + 1 & 0x3fff;
|
|
}
|
|
|
|
// Reset nsecs if clock regresses (new clockseq) or we've moved onto a new
|
|
// time interval
|
|
if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) {
|
|
nsecs = 0;
|
|
}
|
|
|
|
// Per 4.2.1.2 Throw error if too many uuids are requested
|
|
if (nsecs >= 10000) {
|
|
throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec');
|
|
}
|
|
|
|
_lastMSecs = msecs;
|
|
_lastNSecs = nsecs;
|
|
_clockseq = clockseq;
|
|
|
|
// Per 4.1.4 - Convert from unix epoch to Gregorian epoch
|
|
msecs += 12219292800000;
|
|
|
|
// `time_low`
|
|
var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000;
|
|
b[i++] = tl >>> 24 & 0xff;
|
|
b[i++] = tl >>> 16 & 0xff;
|
|
b[i++] = tl >>> 8 & 0xff;
|
|
b[i++] = tl & 0xff;
|
|
|
|
// `time_mid`
|
|
var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff;
|
|
b[i++] = tmh >>> 8 & 0xff;
|
|
b[i++] = tmh & 0xff;
|
|
|
|
// `time_high_and_version`
|
|
b[i++] = tmh >>> 24 & 0xf | 0x10; // include version
|
|
b[i++] = tmh >>> 16 & 0xff;
|
|
|
|
// `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant)
|
|
b[i++] = clockseq >>> 8 | 0x80;
|
|
|
|
// `clock_seq_low`
|
|
b[i++] = clockseq & 0xff;
|
|
|
|
// `node`
|
|
var node = options.node || _nodeId;
|
|
for (var n = 0; n < 6; n++) {
|
|
b[i + n] = node[n];
|
|
}
|
|
|
|
return buf ? buf : unparse(b);
|
|
}
|
|
|
|
// **`v4()` - Generate random UUID**
|
|
|
|
// See https://github.com/broofa/node-uuid for API details
|
|
function v4(options, buf, offset) {
|
|
// Deprecated - 'format' argument, as supported in v1.2
|
|
var i = buf && offset || 0;
|
|
|
|
if (typeof(options) == 'string') {
|
|
buf = options == 'binary' ? new BufferClass(16) : null;
|
|
options = null;
|
|
}
|
|
options = options || {};
|
|
|
|
var rnds = options.random || (options.rng || _rng)();
|
|
|
|
// Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
|
|
rnds[6] = (rnds[6] & 0x0f) | 0x40;
|
|
rnds[8] = (rnds[8] & 0x3f) | 0x80;
|
|
|
|
// Copy bytes to buffer, if provided
|
|
if (buf) {
|
|
for (var ii = 0; ii < 16; ii++) {
|
|
buf[i + ii] = rnds[ii];
|
|
}
|
|
}
|
|
|
|
return buf || unparse(rnds);
|
|
}
|
|
|
|
// Export public API
|
|
var uuid = v4;
|
|
uuid.v1 = v1;
|
|
uuid.v4 = v4;
|
|
uuid.parse = parse;
|
|
uuid.unparse = unparse;
|
|
uuid.BufferClass = BufferClass;
|
|
|
|
if (typeof define === 'function' && define.amd) {
|
|
// Publish as AMD module
|
|
define(function() {return uuid;});
|
|
} else if (typeof(module) != 'undefined' && module.exports) {
|
|
// Publish as node.js module
|
|
module.exports = uuid;
|
|
} else {
|
|
// Publish as global (in browsers)
|
|
var _previousRoot = _global.uuid;
|
|
|
|
// **`noConflict()` - (browser only) to reset global 'uuid' var**
|
|
uuid.noConflict = function() {
|
|
_global.uuid = _previousRoot;
|
|
return uuid;
|
|
};
|
|
|
|
_global.uuid = uuid;
|
|
}
|
|
}).call(this);
|
|
|
|
}).call(this,_dereq_("buffer").Buffer)
|
|
},{"buffer":128,"crypto":132}],114:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
module.exports = _dereq_('./lib/core.js')
|
|
_dereq_('./lib/done.js')
|
|
_dereq_('./lib/es6-extensions.js')
|
|
_dereq_('./lib/node-extensions.js')
|
|
},{"./lib/core.js":115,"./lib/done.js":116,"./lib/es6-extensions.js":117,"./lib/node-extensions.js":118}],115:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var asap = _dereq_('asap')
|
|
|
|
module.exports = Promise;
|
|
function Promise(fn) {
|
|
if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new')
|
|
if (typeof fn !== 'function') throw new TypeError('not a function')
|
|
var state = null
|
|
var value = null
|
|
var deferreds = []
|
|
var self = this
|
|
|
|
this.then = function(onFulfilled, onRejected) {
|
|
return new self.constructor(function(resolve, reject) {
|
|
handle(new Handler(onFulfilled, onRejected, resolve, reject))
|
|
})
|
|
}
|
|
|
|
function handle(deferred) {
|
|
if (state === null) {
|
|
deferreds.push(deferred)
|
|
return
|
|
}
|
|
asap(function() {
|
|
var cb = state ? deferred.onFulfilled : deferred.onRejected
|
|
if (cb === null) {
|
|
(state ? deferred.resolve : deferred.reject)(value)
|
|
return
|
|
}
|
|
var ret
|
|
try {
|
|
ret = cb(value)
|
|
}
|
|
catch (e) {
|
|
deferred.reject(e)
|
|
return
|
|
}
|
|
deferred.resolve(ret)
|
|
})
|
|
}
|
|
|
|
function resolve(newValue) {
|
|
try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
|
|
if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.')
|
|
if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
|
|
var then = newValue.then
|
|
if (typeof then === 'function') {
|
|
doResolve(then.bind(newValue), resolve, reject)
|
|
return
|
|
}
|
|
}
|
|
state = true
|
|
value = newValue
|
|
finale()
|
|
} catch (e) { reject(e) }
|
|
}
|
|
|
|
function reject(newValue) {
|
|
state = false
|
|
value = newValue
|
|
finale()
|
|
}
|
|
|
|
function finale() {
|
|
for (var i = 0, len = deferreds.length; i < len; i++)
|
|
handle(deferreds[i])
|
|
deferreds = null
|
|
}
|
|
|
|
doResolve(fn, resolve, reject)
|
|
}
|
|
|
|
|
|
function Handler(onFulfilled, onRejected, resolve, reject){
|
|
this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null
|
|
this.onRejected = typeof onRejected === 'function' ? onRejected : null
|
|
this.resolve = resolve
|
|
this.reject = reject
|
|
}
|
|
|
|
/**
|
|
* Take a potentially misbehaving resolver function and make sure
|
|
* onFulfilled and onRejected are only called once.
|
|
*
|
|
* Makes no guarantees about asynchrony.
|
|
*/
|
|
function doResolve(fn, onFulfilled, onRejected) {
|
|
var done = false;
|
|
try {
|
|
fn(function (value) {
|
|
if (done) return
|
|
done = true
|
|
onFulfilled(value)
|
|
}, function (reason) {
|
|
if (done) return
|
|
done = true
|
|
onRejected(reason)
|
|
})
|
|
} catch (ex) {
|
|
if (done) return
|
|
done = true
|
|
onRejected(ex)
|
|
}
|
|
}
|
|
|
|
},{"asap":119}],116:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
var Promise = _dereq_('./core.js')
|
|
var asap = _dereq_('asap')
|
|
|
|
module.exports = Promise
|
|
Promise.prototype.done = function (onFulfilled, onRejected) {
|
|
var self = arguments.length ? this.then.apply(this, arguments) : this
|
|
self.then(null, function (err) {
|
|
asap(function () {
|
|
throw err
|
|
})
|
|
})
|
|
}
|
|
},{"./core.js":115,"asap":119}],117:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
//This file contains the ES6 extensions to the core Promises/A+ API
|
|
|
|
var Promise = _dereq_('./core.js')
|
|
var asap = _dereq_('asap')
|
|
|
|
module.exports = Promise
|
|
|
|
/* Static Functions */
|
|
|
|
function ValuePromise(value) {
|
|
this.then = function (onFulfilled) {
|
|
if (typeof onFulfilled !== 'function') return this
|
|
return new Promise(function (resolve, reject) {
|
|
asap(function () {
|
|
try {
|
|
resolve(onFulfilled(value))
|
|
} catch (ex) {
|
|
reject(ex);
|
|
}
|
|
})
|
|
})
|
|
}
|
|
}
|
|
ValuePromise.prototype = Promise.prototype
|
|
|
|
var TRUE = new ValuePromise(true)
|
|
var FALSE = new ValuePromise(false)
|
|
var NULL = new ValuePromise(null)
|
|
var UNDEFINED = new ValuePromise(undefined)
|
|
var ZERO = new ValuePromise(0)
|
|
var EMPTYSTRING = new ValuePromise('')
|
|
|
|
Promise.resolve = function (value) {
|
|
if (value instanceof Promise) return value
|
|
|
|
if (value === null) return NULL
|
|
if (value === undefined) return UNDEFINED
|
|
if (value === true) return TRUE
|
|
if (value === false) return FALSE
|
|
if (value === 0) return ZERO
|
|
if (value === '') return EMPTYSTRING
|
|
|
|
if (typeof value === 'object' || typeof value === 'function') {
|
|
try {
|
|
var then = value.then
|
|
if (typeof then === 'function') {
|
|
return new Promise(then.bind(value))
|
|
}
|
|
} catch (ex) {
|
|
return new Promise(function (resolve, reject) {
|
|
reject(ex)
|
|
})
|
|
}
|
|
}
|
|
|
|
return new ValuePromise(value)
|
|
}
|
|
|
|
Promise.all = function (arr) {
|
|
var args = Array.prototype.slice.call(arr)
|
|
|
|
return new Promise(function (resolve, reject) {
|
|
if (args.length === 0) return resolve([])
|
|
var remaining = args.length
|
|
function res(i, val) {
|
|
try {
|
|
if (val && (typeof val === 'object' || typeof val === 'function')) {
|
|
var then = val.then
|
|
if (typeof then === 'function') {
|
|
then.call(val, function (val) { res(i, val) }, reject)
|
|
return
|
|
}
|
|
}
|
|
args[i] = val
|
|
if (--remaining === 0) {
|
|
resolve(args);
|
|
}
|
|
} catch (ex) {
|
|
reject(ex)
|
|
}
|
|
}
|
|
for (var i = 0; i < args.length; i++) {
|
|
res(i, args[i])
|
|
}
|
|
})
|
|
}
|
|
|
|
Promise.reject = function (value) {
|
|
return new Promise(function (resolve, reject) {
|
|
reject(value);
|
|
});
|
|
}
|
|
|
|
Promise.race = function (values) {
|
|
return new Promise(function (resolve, reject) {
|
|
values.forEach(function(value){
|
|
Promise.resolve(value).then(resolve, reject);
|
|
})
|
|
});
|
|
}
|
|
|
|
/* Prototype Methods */
|
|
|
|
Promise.prototype['catch'] = function (onRejected) {
|
|
return this.then(null, onRejected);
|
|
}
|
|
|
|
},{"./core.js":115,"asap":119}],118:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
//This file contains then/promise specific extensions that are only useful for node.js interop
|
|
|
|
var Promise = _dereq_('./core.js')
|
|
var asap = _dereq_('asap')
|
|
|
|
module.exports = Promise
|
|
|
|
/* Static Functions */
|
|
|
|
Promise.denodeify = function (fn, argumentCount) {
|
|
argumentCount = argumentCount || Infinity
|
|
return function () {
|
|
var self = this
|
|
var args = Array.prototype.slice.call(arguments)
|
|
return new Promise(function (resolve, reject) {
|
|
while (args.length && args.length > argumentCount) {
|
|
args.pop()
|
|
}
|
|
args.push(function (err, res) {
|
|
if (err) reject(err)
|
|
else resolve(res)
|
|
})
|
|
fn.apply(self, args)
|
|
})
|
|
}
|
|
}
|
|
Promise.nodeify = function (fn) {
|
|
return function () {
|
|
var args = Array.prototype.slice.call(arguments)
|
|
var callback = typeof args[args.length - 1] === 'function' ? args.pop() : null
|
|
var ctx = this
|
|
try {
|
|
return fn.apply(this, arguments).nodeify(callback, ctx)
|
|
} catch (ex) {
|
|
if (callback === null || typeof callback == 'undefined') {
|
|
return new Promise(function (resolve, reject) { reject(ex) })
|
|
} else {
|
|
asap(function () {
|
|
callback.call(ctx, ex)
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Promise.prototype.nodeify = function (callback, ctx) {
|
|
if (typeof callback != 'function') return this
|
|
|
|
this.then(function (value) {
|
|
asap(function () {
|
|
callback.call(ctx, null, value)
|
|
})
|
|
}, function (err) {
|
|
asap(function () {
|
|
callback.call(ctx, err)
|
|
})
|
|
})
|
|
}
|
|
|
|
},{"./core.js":115,"asap":119}],119:[function(_dereq_,module,exports){
|
|
(function (process){
|
|
|
|
// Use the fastest possible means to execute a task in a future turn
|
|
// of the event loop.
|
|
|
|
// linked list of tasks (single, with head node)
|
|
var head = {task: void 0, next: null};
|
|
var tail = head;
|
|
var flushing = false;
|
|
var requestFlush = void 0;
|
|
var isNodeJS = false;
|
|
|
|
function flush() {
|
|
/* jshint loopfunc: true */
|
|
|
|
while (head.next) {
|
|
head = head.next;
|
|
var task = head.task;
|
|
head.task = void 0;
|
|
var domain = head.domain;
|
|
|
|
if (domain) {
|
|
head.domain = void 0;
|
|
domain.enter();
|
|
}
|
|
|
|
try {
|
|
task();
|
|
|
|
} catch (e) {
|
|
if (isNodeJS) {
|
|
// In node, uncaught exceptions are considered fatal errors.
|
|
// Re-throw them synchronously to interrupt flushing!
|
|
|
|
// Ensure continuation if the uncaught exception is suppressed
|
|
// listening "uncaughtException" events (as domains does).
|
|
// Continue in next event to avoid tick recursion.
|
|
if (domain) {
|
|
domain.exit();
|
|
}
|
|
setTimeout(flush, 0);
|
|
if (domain) {
|
|
domain.enter();
|
|
}
|
|
|
|
throw e;
|
|
|
|
} else {
|
|
// In browsers, uncaught exceptions are not fatal.
|
|
// Re-throw them asynchronously to avoid slow-downs.
|
|
setTimeout(function() {
|
|
throw e;
|
|
}, 0);
|
|
}
|
|
}
|
|
|
|
if (domain) {
|
|
domain.exit();
|
|
}
|
|
}
|
|
|
|
flushing = false;
|
|
}
|
|
|
|
if (typeof process !== "undefined" && process.nextTick) {
|
|
// Node.js before 0.9. Note that some fake-Node environments, like the
|
|
// Mocha test runner, introduce a `process` global without a `nextTick`.
|
|
isNodeJS = true;
|
|
|
|
requestFlush = function () {
|
|
process.nextTick(flush);
|
|
};
|
|
|
|
} else if (typeof setImmediate === "function") {
|
|
// In IE10, Node.js 0.9+, or https://github.com/NobleJS/setImmediate
|
|
if (typeof window !== "undefined") {
|
|
requestFlush = setImmediate.bind(window, flush);
|
|
} else {
|
|
requestFlush = function () {
|
|
setImmediate(flush);
|
|
};
|
|
}
|
|
|
|
} else if (typeof MessageChannel !== "undefined") {
|
|
// modern browsers
|
|
// http://www.nonblocking.io/2011/06/windownexttick.html
|
|
var channel = new MessageChannel();
|
|
channel.port1.onmessage = flush;
|
|
requestFlush = function () {
|
|
channel.port2.postMessage(0);
|
|
};
|
|
|
|
} else {
|
|
// old browsers
|
|
requestFlush = function () {
|
|
setTimeout(flush, 0);
|
|
};
|
|
}
|
|
|
|
function asap(task) {
|
|
tail = tail.next = {
|
|
task: task,
|
|
domain: isNodeJS && process.domain,
|
|
next: null
|
|
};
|
|
|
|
if (!flushing) {
|
|
flushing = true;
|
|
requestFlush();
|
|
}
|
|
};
|
|
|
|
module.exports = asap;
|
|
|
|
|
|
}).call(this,_dereq_("C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"))
|
|
},{"C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":144}],120:[function(_dereq_,module,exports){
|
|
module.exports=_dereq_(62)
|
|
},{"./lib/agent":122}],121:[function(_dereq_,module,exports){
|
|
module.exports=_dereq_(63)
|
|
},{"C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":144,"events":137,"http":138,"net":127,"url":157,"util":159}],122:[function(_dereq_,module,exports){
|
|
module.exports=_dereq_(64)
|
|
},{"./_http_agent":121,"C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":144,"http":138,"https":142,"util":159}],123:[function(_dereq_,module,exports){
|
|
module.exports=_dereq_(65)
|
|
},{"agentkeepalive":120,"buffer":128,"crypto":132,"http":138,"https":142}],124:[function(_dereq_,module,exports){
|
|
(function (global){
|
|
'use strict';
|
|
|
|
var width = 256;// each RC4 output is 0 <= x < 256
|
|
var chunks = 6;// at least six RC4 outputs for each double
|
|
var digits = 52;// there are 52 significant digits in a double
|
|
var pool = [];// pool: entropy pool starts empty
|
|
var GLOBAL = typeof global === 'undefined' ? window : global;
|
|
|
|
//
|
|
// The following constants are related to IEEE 754 limits.
|
|
//
|
|
var startdenom = Math.pow(width, chunks),
|
|
significance = Math.pow(2, digits),
|
|
overflow = significance * 2,
|
|
mask = width - 1;
|
|
|
|
|
|
var oldRandom = Math.random;
|
|
|
|
//
|
|
// seedrandom()
|
|
// This is the seedrandom function described above.
|
|
//
|
|
module.exports = function(seed, options) {
|
|
if (options && options.global === true) {
|
|
options.global = false;
|
|
Math.random = module.exports(seed, options);
|
|
options.global = true;
|
|
return Math.random;
|
|
}
|
|
var use_entropy = (options && options.entropy) || false;
|
|
var key = [];
|
|
|
|
// Flatten the seed string or build one from local entropy if needed.
|
|
var shortseed = mixkey(flatten(
|
|
use_entropy ? [seed, tostring(pool)] :
|
|
0 in arguments ? seed : autoseed(), 3), key);
|
|
|
|
// Use the seed to initialize an ARC4 generator.
|
|
var arc4 = new ARC4(key);
|
|
|
|
// Mix the randomness into accumulated entropy.
|
|
mixkey(tostring(arc4.S), pool);
|
|
|
|
// Override Math.random
|
|
|
|
// This function returns a random double in [0, 1) that contains
|
|
// randomness in every bit of the mantissa of the IEEE 754 value.
|
|
|
|
return function() { // Closure to return a random double:
|
|
var n = arc4.g(chunks), // Start with a numerator n < 2 ^ 48
|
|
d = startdenom, // and denominator d = 2 ^ 48.
|
|
x = 0; // and no 'extra last byte'.
|
|
while (n < significance) { // Fill up all significant digits by
|
|
n = (n + x) * width; // shifting numerator and
|
|
d *= width; // denominator and generating a
|
|
x = arc4.g(1); // new least-significant-byte.
|
|
}
|
|
while (n >= overflow) { // To avoid rounding up, before adding
|
|
n /= 2; // last byte, shift everything
|
|
d /= 2; // right using integer Math until
|
|
x >>>= 1; // we have exactly the desired bits.
|
|
}
|
|
return (n + x) / d; // Form the number within [0, 1).
|
|
};
|
|
};
|
|
|
|
module.exports.resetGlobal = function () {
|
|
Math.random = oldRandom;
|
|
};
|
|
|
|
//
|
|
// ARC4
|
|
//
|
|
// An ARC4 implementation. The constructor takes a key in the form of
|
|
// an array of at most (width) integers that should be 0 <= x < (width).
|
|
//
|
|
// The g(count) method returns a pseudorandom integer that concatenates
|
|
// the next (count) outputs from ARC4. Its return value is a number x
|
|
// that is in the range 0 <= x < (width ^ count).
|
|
//
|
|
/** @constructor */
|
|
function ARC4(key) {
|
|
var t, keylen = key.length,
|
|
me = this, i = 0, j = me.i = me.j = 0, s = me.S = [];
|
|
|
|
// The empty key [] is treated as [0].
|
|
if (!keylen) { key = [keylen++]; }
|
|
|
|
// Set up S using the standard key scheduling algorithm.
|
|
while (i < width) {
|
|
s[i] = i++;
|
|
}
|
|
for (i = 0; i < width; i++) {
|
|
s[i] = s[j = mask & (j + key[i % keylen] + (t = s[i]))];
|
|
s[j] = t;
|
|
}
|
|
|
|
// The "g" method returns the next (count) outputs as one number.
|
|
(me.g = function(count) {
|
|
// Using instance members instead of closure state nearly doubles speed.
|
|
var t, r = 0,
|
|
i = me.i, j = me.j, s = me.S;
|
|
while (count--) {
|
|
t = s[i = mask & (i + 1)];
|
|
r = r * width + s[mask & ((s[i] = s[j = mask & (j + t)]) + (s[j] = t))];
|
|
}
|
|
me.i = i; me.j = j;
|
|
return r;
|
|
// For robust unpredictability discard an initial batch of values.
|
|
// See http://www.rsa.com/rsalabs/node.asp?id=2009
|
|
})(width);
|
|
}
|
|
|
|
//
|
|
// flatten()
|
|
// Converts an object tree to nested arrays of strings.
|
|
//
|
|
function flatten(obj, depth) {
|
|
var result = [], typ = (typeof obj)[0], prop;
|
|
if (depth && typ == 'o') {
|
|
for (prop in obj) {
|
|
try { result.push(flatten(obj[prop], depth - 1)); } catch (e) {}
|
|
}
|
|
}
|
|
return (result.length ? result : typ == 's' ? obj : obj + '\0');
|
|
}
|
|
|
|
//
|
|
// mixkey()
|
|
// Mixes a string seed into a key that is an array of integers, and
|
|
// returns a shortened string seed that is equivalent to the result key.
|
|
//
|
|
function mixkey(seed, key) {
|
|
var stringseed = seed + '', smear, j = 0;
|
|
while (j < stringseed.length) {
|
|
key[mask & j] =
|
|
mask & ((smear ^= key[mask & j] * 19) + stringseed.charCodeAt(j++));
|
|
}
|
|
return tostring(key);
|
|
}
|
|
|
|
//
|
|
// autoseed()
|
|
// Returns an object for autoseeding, using window.crypto if available.
|
|
//
|
|
/** @param {Uint8Array=} seed */
|
|
function autoseed(seed) {
|
|
try {
|
|
GLOBAL.crypto.getRandomValues(seed = new Uint8Array(width));
|
|
return tostring(seed);
|
|
} catch (e) {
|
|
return [+new Date, GLOBAL, GLOBAL.navigator && GLOBAL.navigator.plugins,
|
|
GLOBAL.screen, tostring(pool)];
|
|
}
|
|
}
|
|
|
|
//
|
|
// tostring()
|
|
// Converts an array of charcodes to a string
|
|
//
|
|
function tostring(a) {
|
|
return String.fromCharCode.apply(0, a);
|
|
}
|
|
|
|
//
|
|
// When seedrandom.js is loaded, we immediately mix a few bits
|
|
// from the built-in RNG into the entropy pool. Because we do
|
|
// not want to intefere with determinstic PRNG state later,
|
|
// seedrandom will not call Math.random on its own again after
|
|
// initialization.
|
|
//
|
|
mixkey(Math.random(), pool);
|
|
|
|
}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
|
},{}],125:[function(_dereq_,module,exports){
|
|
|
|
exports = module.exports = function() {
|
|
var ret = '', value;
|
|
for (var i = 0; i < 32; i++) {
|
|
value = exports.random() * 16 | 0;
|
|
// Insert the hypens
|
|
if (i > 4 && i < 21 && ! (i % 4)) {
|
|
ret += '-';
|
|
}
|
|
// Add the next random character
|
|
ret += (
|
|
(i === 12) ? 4 : (
|
|
(i === 16) ? (value & 3 | 8) : value
|
|
)
|
|
).toString(16);
|
|
}
|
|
return ret;
|
|
};
|
|
|
|
var uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
exports.isUUID = function(uuid) {
|
|
return uuidRegex.test(uuid);
|
|
};
|
|
|
|
exports.random = function() {
|
|
return Math.random();
|
|
};
|
|
|
|
|
|
},{}],126:[function(_dereq_,module,exports){
|
|
module.exports=_dereq_(109)
|
|
},{}],127:[function(_dereq_,module,exports){
|
|
|
|
},{}],128:[function(_dereq_,module,exports){
|
|
/*!
|
|
* The buffer module from node.js, for the browser.
|
|
*
|
|
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
|
|
* @license MIT
|
|
*/
|
|
|
|
var base64 = _dereq_('base64-js')
|
|
var ieee754 = _dereq_('ieee754')
|
|
|
|
exports.Buffer = Buffer
|
|
exports.SlowBuffer = Buffer
|
|
exports.INSPECT_MAX_BYTES = 50
|
|
Buffer.poolSize = 8192
|
|
|
|
/**
|
|
* If `Buffer._useTypedArrays`:
|
|
* === true Use Uint8Array implementation (fastest)
|
|
* === false Use Object implementation (compatible down to IE6)
|
|
*/
|
|
Buffer._useTypedArrays = (function () {
|
|
// Detect if browser supports Typed Arrays. Supported browsers are IE 10+, Firefox 4+,
|
|
// Chrome 7+, Safari 5.1+, Opera 11.6+, iOS 4.2+. If the browser does not support adding
|
|
// properties to `Uint8Array` instances, then that's the same as no `Uint8Array` support
|
|
// because we need to be able to add all the node Buffer API methods. This is an issue
|
|
// in Firefox 4-29. Now fixed: https://bugzilla.mozilla.org/show_bug.cgi?id=695438
|
|
try {
|
|
var buf = new ArrayBuffer(0)
|
|
var arr = new Uint8Array(buf)
|
|
arr.foo = function () { return 42 }
|
|
return 42 === arr.foo() &&
|
|
typeof arr.subarray === 'function' // Chrome 9-10 lack `subarray`
|
|
} catch (e) {
|
|
return false
|
|
}
|
|
})()
|
|
|
|
/**
|
|
* Class: Buffer
|
|
* =============
|
|
*
|
|
* The Buffer constructor returns instances of `Uint8Array` that are augmented
|
|
* with function properties for all the node `Buffer` API functions. We use
|
|
* `Uint8Array` so that square bracket notation works as expected -- it returns
|
|
* a single octet.
|
|
*
|
|
* By augmenting the instances, we can avoid modifying the `Uint8Array`
|
|
* prototype.
|
|
*/
|
|
function Buffer (subject, encoding, noZero) {
|
|
if (!(this instanceof Buffer))
|
|
return new Buffer(subject, encoding, noZero)
|
|
|
|
var type = typeof subject
|
|
|
|
// Workaround: node's base64 implementation allows for non-padded strings
|
|
// while base64-js does not.
|
|
if (encoding === 'base64' && type === 'string') {
|
|
subject = stringtrim(subject)
|
|
while (subject.length % 4 !== 0) {
|
|
subject = subject + '='
|
|
}
|
|
}
|
|
|
|
// Find the length
|
|
var length
|
|
if (type === 'number')
|
|
length = coerce(subject)
|
|
else if (type === 'string')
|
|
length = Buffer.byteLength(subject, encoding)
|
|
else if (type === 'object')
|
|
length = coerce(subject.length) // assume that object is array-like
|
|
else
|
|
throw new Error('First argument needs to be a number, array or string.')
|
|
|
|
var buf
|
|
if (Buffer._useTypedArrays) {
|
|
// Preferred: Return an augmented `Uint8Array` instance for best performance
|
|
buf = Buffer._augment(new Uint8Array(length))
|
|
} else {
|
|
// Fallback: Return THIS instance of Buffer (created by `new`)
|
|
buf = this
|
|
buf.length = length
|
|
buf._isBuffer = true
|
|
}
|
|
|
|
var i
|
|
if (Buffer._useTypedArrays && typeof subject.byteLength === 'number') {
|
|
// Speed optimization -- use set if we're copying from a typed array
|
|
buf._set(subject)
|
|
} else if (isArrayish(subject)) {
|
|
// Treat array-ish objects as a byte array
|
|
for (i = 0; i < length; i++) {
|
|
if (Buffer.isBuffer(subject))
|
|
buf[i] = subject.readUInt8(i)
|
|
else
|
|
buf[i] = subject[i]
|
|
}
|
|
} else if (type === 'string') {
|
|
buf.write(subject, 0, encoding)
|
|
} else if (type === 'number' && !Buffer._useTypedArrays && !noZero) {
|
|
for (i = 0; i < length; i++) {
|
|
buf[i] = 0
|
|
}
|
|
}
|
|
|
|
return buf
|
|
}
|
|
|
|
// STATIC METHODS
|
|
// ==============
|
|
|
|
Buffer.isEncoding = function (encoding) {
|
|
switch (String(encoding).toLowerCase()) {
|
|
case 'hex':
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
case 'ascii':
|
|
case 'binary':
|
|
case 'base64':
|
|
case 'raw':
|
|
case 'ucs2':
|
|
case 'ucs-2':
|
|
case 'utf16le':
|
|
case 'utf-16le':
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
Buffer.isBuffer = function (b) {
|
|
return !!(b !== null && b !== undefined && b._isBuffer)
|
|
}
|
|
|
|
Buffer.byteLength = function (str, encoding) {
|
|
var ret
|
|
str = str + ''
|
|
switch (encoding || 'utf8') {
|
|
case 'hex':
|
|
ret = str.length / 2
|
|
break
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
ret = utf8ToBytes(str).length
|
|
break
|
|
case 'ascii':
|
|
case 'binary':
|
|
case 'raw':
|
|
ret = str.length
|
|
break
|
|
case 'base64':
|
|
ret = base64ToBytes(str).length
|
|
break
|
|
case 'ucs2':
|
|
case 'ucs-2':
|
|
case 'utf16le':
|
|
case 'utf-16le':
|
|
ret = str.length * 2
|
|
break
|
|
default:
|
|
throw new Error('Unknown encoding')
|
|
}
|
|
return ret
|
|
}
|
|
|
|
Buffer.concat = function (list, totalLength) {
|
|
assert(isArray(list), 'Usage: Buffer.concat(list, [totalLength])\n' +
|
|
'list should be an Array.')
|
|
|
|
if (list.length === 0) {
|
|
return new Buffer(0)
|
|
} else if (list.length === 1) {
|
|
return list[0]
|
|
}
|
|
|
|
var i
|
|
if (typeof totalLength !== 'number') {
|
|
totalLength = 0
|
|
for (i = 0; i < list.length; i++) {
|
|
totalLength += list[i].length
|
|
}
|
|
}
|
|
|
|
var buf = new Buffer(totalLength)
|
|
var pos = 0
|
|
for (i = 0; i < list.length; i++) {
|
|
var item = list[i]
|
|
item.copy(buf, pos)
|
|
pos += item.length
|
|
}
|
|
return buf
|
|
}
|
|
|
|
// BUFFER INSTANCE METHODS
|
|
// =======================
|
|
|
|
function _hexWrite (buf, string, offset, length) {
|
|
offset = Number(offset) || 0
|
|
var remaining = buf.length - offset
|
|
if (!length) {
|
|
length = remaining
|
|
} else {
|
|
length = Number(length)
|
|
if (length > remaining) {
|
|
length = remaining
|
|
}
|
|
}
|
|
|
|
// must be an even number of digits
|
|
var strLen = string.length
|
|
assert(strLen % 2 === 0, 'Invalid hex string')
|
|
|
|
if (length > strLen / 2) {
|
|
length = strLen / 2
|
|
}
|
|
for (var i = 0; i < length; i++) {
|
|
var byte = parseInt(string.substr(i * 2, 2), 16)
|
|
assert(!isNaN(byte), 'Invalid hex string')
|
|
buf[offset + i] = byte
|
|
}
|
|
Buffer._charsWritten = i * 2
|
|
return i
|
|
}
|
|
|
|
function _utf8Write (buf, string, offset, length) {
|
|
var charsWritten = Buffer._charsWritten =
|
|
blitBuffer(utf8ToBytes(string), buf, offset, length)
|
|
return charsWritten
|
|
}
|
|
|
|
function _asciiWrite (buf, string, offset, length) {
|
|
var charsWritten = Buffer._charsWritten =
|
|
blitBuffer(asciiToBytes(string), buf, offset, length)
|
|
return charsWritten
|
|
}
|
|
|
|
function _binaryWrite (buf, string, offset, length) {
|
|
return _asciiWrite(buf, string, offset, length)
|
|
}
|
|
|
|
function _base64Write (buf, string, offset, length) {
|
|
var charsWritten = Buffer._charsWritten =
|
|
blitBuffer(base64ToBytes(string), buf, offset, length)
|
|
return charsWritten
|
|
}
|
|
|
|
function _utf16leWrite (buf, string, offset, length) {
|
|
var charsWritten = Buffer._charsWritten =
|
|
blitBuffer(utf16leToBytes(string), buf, offset, length)
|
|
return charsWritten
|
|
}
|
|
|
|
Buffer.prototype.write = function (string, offset, length, encoding) {
|
|
// Support both (string, offset, length, encoding)
|
|
// and the legacy (string, encoding, offset, length)
|
|
if (isFinite(offset)) {
|
|
if (!isFinite(length)) {
|
|
encoding = length
|
|
length = undefined
|
|
}
|
|
} else { // legacy
|
|
var swap = encoding
|
|
encoding = offset
|
|
offset = length
|
|
length = swap
|
|
}
|
|
|
|
offset = Number(offset) || 0
|
|
var remaining = this.length - offset
|
|
if (!length) {
|
|
length = remaining
|
|
} else {
|
|
length = Number(length)
|
|
if (length > remaining) {
|
|
length = remaining
|
|
}
|
|
}
|
|
encoding = String(encoding || 'utf8').toLowerCase()
|
|
|
|
var ret
|
|
switch (encoding) {
|
|
case 'hex':
|
|
ret = _hexWrite(this, string, offset, length)
|
|
break
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
ret = _utf8Write(this, string, offset, length)
|
|
break
|
|
case 'ascii':
|
|
ret = _asciiWrite(this, string, offset, length)
|
|
break
|
|
case 'binary':
|
|
ret = _binaryWrite(this, string, offset, length)
|
|
break
|
|
case 'base64':
|
|
ret = _base64Write(this, string, offset, length)
|
|
break
|
|
case 'ucs2':
|
|
case 'ucs-2':
|
|
case 'utf16le':
|
|
case 'utf-16le':
|
|
ret = _utf16leWrite(this, string, offset, length)
|
|
break
|
|
default:
|
|
throw new Error('Unknown encoding')
|
|
}
|
|
return ret
|
|
}
|
|
|
|
Buffer.prototype.toString = function (encoding, start, end) {
|
|
var self = this
|
|
|
|
encoding = String(encoding || 'utf8').toLowerCase()
|
|
start = Number(start) || 0
|
|
end = (end !== undefined)
|
|
? Number(end)
|
|
: end = self.length
|
|
|
|
// Fastpath empty strings
|
|
if (end === start)
|
|
return ''
|
|
|
|
var ret
|
|
switch (encoding) {
|
|
case 'hex':
|
|
ret = _hexSlice(self, start, end)
|
|
break
|
|
case 'utf8':
|
|
case 'utf-8':
|
|
ret = _utf8Slice(self, start, end)
|
|
break
|
|
case 'ascii':
|
|
ret = _asciiSlice(self, start, end)
|
|
break
|
|
case 'binary':
|
|
ret = _binarySlice(self, start, end)
|
|
break
|
|
case 'base64':
|
|
ret = _base64Slice(self, start, end)
|
|
break
|
|
case 'ucs2':
|
|
case 'ucs-2':
|
|
case 'utf16le':
|
|
case 'utf-16le':
|
|
ret = _utf16leSlice(self, start, end)
|
|
break
|
|
default:
|
|
throw new Error('Unknown encoding')
|
|
}
|
|
return ret
|
|
}
|
|
|
|
Buffer.prototype.toJSON = function () {
|
|
return {
|
|
type: 'Buffer',
|
|
data: Array.prototype.slice.call(this._arr || this, 0)
|
|
}
|
|
}
|
|
|
|
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
|
|
Buffer.prototype.copy = function (target, target_start, start, end) {
|
|
var source = this
|
|
|
|
if (!start) start = 0
|
|
if (!end && end !== 0) end = this.length
|
|
if (!target_start) target_start = 0
|
|
|
|
// Copy 0 bytes; we're done
|
|
if (end === start) return
|
|
if (target.length === 0 || source.length === 0) return
|
|
|
|
// Fatal error conditions
|
|
assert(end >= start, 'sourceEnd < sourceStart')
|
|
assert(target_start >= 0 && target_start < target.length,
|
|
'targetStart out of bounds')
|
|
assert(start >= 0 && start < source.length, 'sourceStart out of bounds')
|
|
assert(end >= 0 && end <= source.length, 'sourceEnd out of bounds')
|
|
|
|
// Are we oob?
|
|
if (end > this.length)
|
|
end = this.length
|
|
if (target.length - target_start < end - start)
|
|
end = target.length - target_start + start
|
|
|
|
var len = end - start
|
|
|
|
if (len < 100 || !Buffer._useTypedArrays) {
|
|
for (var i = 0; i < len; i++)
|
|
target[i + target_start] = this[i + start]
|
|
} else {
|
|
target._set(this.subarray(start, start + len), target_start)
|
|
}
|
|
}
|
|
|
|
function _base64Slice (buf, start, end) {
|
|
if (start === 0 && end === buf.length) {
|
|
return base64.fromByteArray(buf)
|
|
} else {
|
|
return base64.fromByteArray(buf.slice(start, end))
|
|
}
|
|
}
|
|
|
|
function _utf8Slice (buf, start, end) {
|
|
var res = ''
|
|
var tmp = ''
|
|
end = Math.min(buf.length, end)
|
|
|
|
for (var i = start; i < end; i++) {
|
|
if (buf[i] <= 0x7F) {
|
|
res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i])
|
|
tmp = ''
|
|
} else {
|
|
tmp += '%' + buf[i].toString(16)
|
|
}
|
|
}
|
|
|
|
return res + decodeUtf8Char(tmp)
|
|
}
|
|
|
|
function _asciiSlice (buf, start, end) {
|
|
var ret = ''
|
|
end = Math.min(buf.length, end)
|
|
|
|
for (var i = start; i < end; i++)
|
|
ret += String.fromCharCode(buf[i])
|
|
return ret
|
|
}
|
|
|
|
function _binarySlice (buf, start, end) {
|
|
return _asciiSlice(buf, start, end)
|
|
}
|
|
|
|
function _hexSlice (buf, start, end) {
|
|
var len = buf.length
|
|
|
|
if (!start || start < 0) start = 0
|
|
if (!end || end < 0 || end > len) end = len
|
|
|
|
var out = ''
|
|
for (var i = start; i < end; i++) {
|
|
out += toHex(buf[i])
|
|
}
|
|
return out
|
|
}
|
|
|
|
function _utf16leSlice (buf, start, end) {
|
|
var bytes = buf.slice(start, end)
|
|
var res = ''
|
|
for (var i = 0; i < bytes.length; i += 2) {
|
|
res += String.fromCharCode(bytes[i] + bytes[i+1] * 256)
|
|
}
|
|
return res
|
|
}
|
|
|
|
Buffer.prototype.slice = function (start, end) {
|
|
var len = this.length
|
|
start = clamp(start, len, 0)
|
|
end = clamp(end, len, len)
|
|
|
|
if (Buffer._useTypedArrays) {
|
|
return Buffer._augment(this.subarray(start, end))
|
|
} else {
|
|
var sliceLen = end - start
|
|
var newBuf = new Buffer(sliceLen, undefined, true)
|
|
for (var i = 0; i < sliceLen; i++) {
|
|
newBuf[i] = this[i + start]
|
|
}
|
|
return newBuf
|
|
}
|
|
}
|
|
|
|
// `get` will be removed in Node 0.13+
|
|
Buffer.prototype.get = function (offset) {
|
|
console.log('.get() is deprecated. Access using array indexes instead.')
|
|
return this.readUInt8(offset)
|
|
}
|
|
|
|
// `set` will be removed in Node 0.13+
|
|
Buffer.prototype.set = function (v, offset) {
|
|
console.log('.set() is deprecated. Access using array indexes instead.')
|
|
return this.writeUInt8(v, offset)
|
|
}
|
|
|
|
Buffer.prototype.readUInt8 = function (offset, noAssert) {
|
|
if (!noAssert) {
|
|
assert(offset !== undefined && offset !== null, 'missing offset')
|
|
assert(offset < this.length, 'Trying to read beyond buffer length')
|
|
}
|
|
|
|
if (offset >= this.length)
|
|
return
|
|
|
|
return this[offset]
|
|
}
|
|
|
|
function _readUInt16 (buf, offset, littleEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
|
|
assert(offset !== undefined && offset !== null, 'missing offset')
|
|
assert(offset + 1 < buf.length, 'Trying to read beyond buffer length')
|
|
}
|
|
|
|
var len = buf.length
|
|
if (offset >= len)
|
|
return
|
|
|
|
var val
|
|
if (littleEndian) {
|
|
val = buf[offset]
|
|
if (offset + 1 < len)
|
|
val |= buf[offset + 1] << 8
|
|
} else {
|
|
val = buf[offset] << 8
|
|
if (offset + 1 < len)
|
|
val |= buf[offset + 1]
|
|
}
|
|
return val
|
|
}
|
|
|
|
Buffer.prototype.readUInt16LE = function (offset, noAssert) {
|
|
return _readUInt16(this, offset, true, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.readUInt16BE = function (offset, noAssert) {
|
|
return _readUInt16(this, offset, false, noAssert)
|
|
}
|
|
|
|
function _readUInt32 (buf, offset, littleEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
|
|
assert(offset !== undefined && offset !== null, 'missing offset')
|
|
assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
|
|
}
|
|
|
|
var len = buf.length
|
|
if (offset >= len)
|
|
return
|
|
|
|
var val
|
|
if (littleEndian) {
|
|
if (offset + 2 < len)
|
|
val = buf[offset + 2] << 16
|
|
if (offset + 1 < len)
|
|
val |= buf[offset + 1] << 8
|
|
val |= buf[offset]
|
|
if (offset + 3 < len)
|
|
val = val + (buf[offset + 3] << 24 >>> 0)
|
|
} else {
|
|
if (offset + 1 < len)
|
|
val = buf[offset + 1] << 16
|
|
if (offset + 2 < len)
|
|
val |= buf[offset + 2] << 8
|
|
if (offset + 3 < len)
|
|
val |= buf[offset + 3]
|
|
val = val + (buf[offset] << 24 >>> 0)
|
|
}
|
|
return val
|
|
}
|
|
|
|
Buffer.prototype.readUInt32LE = function (offset, noAssert) {
|
|
return _readUInt32(this, offset, true, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.readUInt32BE = function (offset, noAssert) {
|
|
return _readUInt32(this, offset, false, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.readInt8 = function (offset, noAssert) {
|
|
if (!noAssert) {
|
|
assert(offset !== undefined && offset !== null,
|
|
'missing offset')
|
|
assert(offset < this.length, 'Trying to read beyond buffer length')
|
|
}
|
|
|
|
if (offset >= this.length)
|
|
return
|
|
|
|
var neg = this[offset] & 0x80
|
|
if (neg)
|
|
return (0xff - this[offset] + 1) * -1
|
|
else
|
|
return this[offset]
|
|
}
|
|
|
|
function _readInt16 (buf, offset, littleEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
|
|
assert(offset !== undefined && offset !== null, 'missing offset')
|
|
assert(offset + 1 < buf.length, 'Trying to read beyond buffer length')
|
|
}
|
|
|
|
var len = buf.length
|
|
if (offset >= len)
|
|
return
|
|
|
|
var val = _readUInt16(buf, offset, littleEndian, true)
|
|
var neg = val & 0x8000
|
|
if (neg)
|
|
return (0xffff - val + 1) * -1
|
|
else
|
|
return val
|
|
}
|
|
|
|
Buffer.prototype.readInt16LE = function (offset, noAssert) {
|
|
return _readInt16(this, offset, true, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.readInt16BE = function (offset, noAssert) {
|
|
return _readInt16(this, offset, false, noAssert)
|
|
}
|
|
|
|
function _readInt32 (buf, offset, littleEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
|
|
assert(offset !== undefined && offset !== null, 'missing offset')
|
|
assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
|
|
}
|
|
|
|
var len = buf.length
|
|
if (offset >= len)
|
|
return
|
|
|
|
var val = _readUInt32(buf, offset, littleEndian, true)
|
|
var neg = val & 0x80000000
|
|
if (neg)
|
|
return (0xffffffff - val + 1) * -1
|
|
else
|
|
return val
|
|
}
|
|
|
|
Buffer.prototype.readInt32LE = function (offset, noAssert) {
|
|
return _readInt32(this, offset, true, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.readInt32BE = function (offset, noAssert) {
|
|
return _readInt32(this, offset, false, noAssert)
|
|
}
|
|
|
|
function _readFloat (buf, offset, littleEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
|
|
assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
|
|
}
|
|
|
|
return ieee754.read(buf, offset, littleEndian, 23, 4)
|
|
}
|
|
|
|
Buffer.prototype.readFloatLE = function (offset, noAssert) {
|
|
return _readFloat(this, offset, true, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.readFloatBE = function (offset, noAssert) {
|
|
return _readFloat(this, offset, false, noAssert)
|
|
}
|
|
|
|
function _readDouble (buf, offset, littleEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
|
|
assert(offset + 7 < buf.length, 'Trying to read beyond buffer length')
|
|
}
|
|
|
|
return ieee754.read(buf, offset, littleEndian, 52, 8)
|
|
}
|
|
|
|
Buffer.prototype.readDoubleLE = function (offset, noAssert) {
|
|
return _readDouble(this, offset, true, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.readDoubleBE = function (offset, noAssert) {
|
|
return _readDouble(this, offset, false, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.writeUInt8 = function (value, offset, noAssert) {
|
|
if (!noAssert) {
|
|
assert(value !== undefined && value !== null, 'missing value')
|
|
assert(offset !== undefined && offset !== null, 'missing offset')
|
|
assert(offset < this.length, 'trying to write beyond buffer length')
|
|
verifuint(value, 0xff)
|
|
}
|
|
|
|
if (offset >= this.length) return
|
|
|
|
this[offset] = value
|
|
}
|
|
|
|
function _writeUInt16 (buf, value, offset, littleEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert(value !== undefined && value !== null, 'missing value')
|
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
|
|
assert(offset !== undefined && offset !== null, 'missing offset')
|
|
assert(offset + 1 < buf.length, 'trying to write beyond buffer length')
|
|
verifuint(value, 0xffff)
|
|
}
|
|
|
|
var len = buf.length
|
|
if (offset >= len)
|
|
return
|
|
|
|
for (var i = 0, j = Math.min(len - offset, 2); i < j; i++) {
|
|
buf[offset + i] =
|
|
(value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
|
|
(littleEndian ? i : 1 - i) * 8
|
|
}
|
|
}
|
|
|
|
Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) {
|
|
_writeUInt16(this, value, offset, true, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) {
|
|
_writeUInt16(this, value, offset, false, noAssert)
|
|
}
|
|
|
|
function _writeUInt32 (buf, value, offset, littleEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert(value !== undefined && value !== null, 'missing value')
|
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
|
|
assert(offset !== undefined && offset !== null, 'missing offset')
|
|
assert(offset + 3 < buf.length, 'trying to write beyond buffer length')
|
|
verifuint(value, 0xffffffff)
|
|
}
|
|
|
|
var len = buf.length
|
|
if (offset >= len)
|
|
return
|
|
|
|
for (var i = 0, j = Math.min(len - offset, 4); i < j; i++) {
|
|
buf[offset + i] =
|
|
(value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
|
|
}
|
|
}
|
|
|
|
Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) {
|
|
_writeUInt32(this, value, offset, true, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) {
|
|
_writeUInt32(this, value, offset, false, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.writeInt8 = function (value, offset, noAssert) {
|
|
if (!noAssert) {
|
|
assert(value !== undefined && value !== null, 'missing value')
|
|
assert(offset !== undefined && offset !== null, 'missing offset')
|
|
assert(offset < this.length, 'Trying to write beyond buffer length')
|
|
verifsint(value, 0x7f, -0x80)
|
|
}
|
|
|
|
if (offset >= this.length)
|
|
return
|
|
|
|
if (value >= 0)
|
|
this.writeUInt8(value, offset, noAssert)
|
|
else
|
|
this.writeUInt8(0xff + value + 1, offset, noAssert)
|
|
}
|
|
|
|
function _writeInt16 (buf, value, offset, littleEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert(value !== undefined && value !== null, 'missing value')
|
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
|
|
assert(offset !== undefined && offset !== null, 'missing offset')
|
|
assert(offset + 1 < buf.length, 'Trying to write beyond buffer length')
|
|
verifsint(value, 0x7fff, -0x8000)
|
|
}
|
|
|
|
var len = buf.length
|
|
if (offset >= len)
|
|
return
|
|
|
|
if (value >= 0)
|
|
_writeUInt16(buf, value, offset, littleEndian, noAssert)
|
|
else
|
|
_writeUInt16(buf, 0xffff + value + 1, offset, littleEndian, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.writeInt16LE = function (value, offset, noAssert) {
|
|
_writeInt16(this, value, offset, true, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.writeInt16BE = function (value, offset, noAssert) {
|
|
_writeInt16(this, value, offset, false, noAssert)
|
|
}
|
|
|
|
function _writeInt32 (buf, value, offset, littleEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert(value !== undefined && value !== null, 'missing value')
|
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
|
|
assert(offset !== undefined && offset !== null, 'missing offset')
|
|
assert(offset + 3 < buf.length, 'Trying to write beyond buffer length')
|
|
verifsint(value, 0x7fffffff, -0x80000000)
|
|
}
|
|
|
|
var len = buf.length
|
|
if (offset >= len)
|
|
return
|
|
|
|
if (value >= 0)
|
|
_writeUInt32(buf, value, offset, littleEndian, noAssert)
|
|
else
|
|
_writeUInt32(buf, 0xffffffff + value + 1, offset, littleEndian, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.writeInt32LE = function (value, offset, noAssert) {
|
|
_writeInt32(this, value, offset, true, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.writeInt32BE = function (value, offset, noAssert) {
|
|
_writeInt32(this, value, offset, false, noAssert)
|
|
}
|
|
|
|
function _writeFloat (buf, value, offset, littleEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert(value !== undefined && value !== null, 'missing value')
|
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
|
|
assert(offset !== undefined && offset !== null, 'missing offset')
|
|
assert(offset + 3 < buf.length, 'Trying to write beyond buffer length')
|
|
verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38)
|
|
}
|
|
|
|
var len = buf.length
|
|
if (offset >= len)
|
|
return
|
|
|
|
ieee754.write(buf, value, offset, littleEndian, 23, 4)
|
|
}
|
|
|
|
Buffer.prototype.writeFloatLE = function (value, offset, noAssert) {
|
|
_writeFloat(this, value, offset, true, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.writeFloatBE = function (value, offset, noAssert) {
|
|
_writeFloat(this, value, offset, false, noAssert)
|
|
}
|
|
|
|
function _writeDouble (buf, value, offset, littleEndian, noAssert) {
|
|
if (!noAssert) {
|
|
assert(value !== undefined && value !== null, 'missing value')
|
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
|
|
assert(offset !== undefined && offset !== null, 'missing offset')
|
|
assert(offset + 7 < buf.length,
|
|
'Trying to write beyond buffer length')
|
|
verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308)
|
|
}
|
|
|
|
var len = buf.length
|
|
if (offset >= len)
|
|
return
|
|
|
|
ieee754.write(buf, value, offset, littleEndian, 52, 8)
|
|
}
|
|
|
|
Buffer.prototype.writeDoubleLE = function (value, offset, noAssert) {
|
|
_writeDouble(this, value, offset, true, noAssert)
|
|
}
|
|
|
|
Buffer.prototype.writeDoubleBE = function (value, offset, noAssert) {
|
|
_writeDouble(this, value, offset, false, noAssert)
|
|
}
|
|
|
|
// fill(value, start=0, end=buffer.length)
|
|
Buffer.prototype.fill = function (value, start, end) {
|
|
if (!value) value = 0
|
|
if (!start) start = 0
|
|
if (!end) end = this.length
|
|
|
|
if (typeof value === 'string') {
|
|
value = value.charCodeAt(0)
|
|
}
|
|
|
|
assert(typeof value === 'number' && !isNaN(value), 'value is not a number')
|
|
assert(end >= start, 'end < start')
|
|
|
|
// Fill 0 bytes; we're done
|
|
if (end === start) return
|
|
if (this.length === 0) return
|
|
|
|
assert(start >= 0 && start < this.length, 'start out of bounds')
|
|
assert(end >= 0 && end <= this.length, 'end out of bounds')
|
|
|
|
for (var i = start; i < end; i++) {
|
|
this[i] = value
|
|
}
|
|
}
|
|
|
|
Buffer.prototype.inspect = function () {
|
|
var out = []
|
|
var len = this.length
|
|
for (var i = 0; i < len; i++) {
|
|
out[i] = toHex(this[i])
|
|
if (i === exports.INSPECT_MAX_BYTES) {
|
|
out[i + 1] = '...'
|
|
break
|
|
}
|
|
}
|
|
return '<Buffer ' + out.join(' ') + '>'
|
|
}
|
|
|
|
/**
|
|
* Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.
|
|
* Added in Node 0.12. Only available in browsers that support ArrayBuffer.
|
|
*/
|
|
Buffer.prototype.toArrayBuffer = function () {
|
|
if (typeof Uint8Array !== 'undefined') {
|
|
if (Buffer._useTypedArrays) {
|
|
return (new Buffer(this)).buffer
|
|
} else {
|
|
var buf = new Uint8Array(this.length)
|
|
for (var i = 0, len = buf.length; i < len; i += 1)
|
|
buf[i] = this[i]
|
|
return buf.buffer
|
|
}
|
|
} else {
|
|
throw new Error('Buffer.toArrayBuffer not supported in this browser')
|
|
}
|
|
}
|
|
|
|
// HELPER FUNCTIONS
|
|
// ================
|
|
|
|
function stringtrim (str) {
|
|
if (str.trim) return str.trim()
|
|
return str.replace(/^\s+|\s+$/g, '')
|
|
}
|
|
|
|
var BP = Buffer.prototype
|
|
|
|
/**
|
|
* Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods
|
|
*/
|
|
Buffer._augment = function (arr) {
|
|
arr._isBuffer = true
|
|
|
|
// save reference to original Uint8Array get/set methods before overwriting
|
|
arr._get = arr.get
|
|
arr._set = arr.set
|
|
|
|
// deprecated, will be removed in node 0.13+
|
|
arr.get = BP.get
|
|
arr.set = BP.set
|
|
|
|
arr.write = BP.write
|
|
arr.toString = BP.toString
|
|
arr.toLocaleString = BP.toString
|
|
arr.toJSON = BP.toJSON
|
|
arr.copy = BP.copy
|
|
arr.slice = BP.slice
|
|
arr.readUInt8 = BP.readUInt8
|
|
arr.readUInt16LE = BP.readUInt16LE
|
|
arr.readUInt16BE = BP.readUInt16BE
|
|
arr.readUInt32LE = BP.readUInt32LE
|
|
arr.readUInt32BE = BP.readUInt32BE
|
|
arr.readInt8 = BP.readInt8
|
|
arr.readInt16LE = BP.readInt16LE
|
|
arr.readInt16BE = BP.readInt16BE
|
|
arr.readInt32LE = BP.readInt32LE
|
|
arr.readInt32BE = BP.readInt32BE
|
|
arr.readFloatLE = BP.readFloatLE
|
|
arr.readFloatBE = BP.readFloatBE
|
|
arr.readDoubleLE = BP.readDoubleLE
|
|
arr.readDoubleBE = BP.readDoubleBE
|
|
arr.writeUInt8 = BP.writeUInt8
|
|
arr.writeUInt16LE = BP.writeUInt16LE
|
|
arr.writeUInt16BE = BP.writeUInt16BE
|
|
arr.writeUInt32LE = BP.writeUInt32LE
|
|
arr.writeUInt32BE = BP.writeUInt32BE
|
|
arr.writeInt8 = BP.writeInt8
|
|
arr.writeInt16LE = BP.writeInt16LE
|
|
arr.writeInt16BE = BP.writeInt16BE
|
|
arr.writeInt32LE = BP.writeInt32LE
|
|
arr.writeInt32BE = BP.writeInt32BE
|
|
arr.writeFloatLE = BP.writeFloatLE
|
|
arr.writeFloatBE = BP.writeFloatBE
|
|
arr.writeDoubleLE = BP.writeDoubleLE
|
|
arr.writeDoubleBE = BP.writeDoubleBE
|
|
arr.fill = BP.fill
|
|
arr.inspect = BP.inspect
|
|
arr.toArrayBuffer = BP.toArrayBuffer
|
|
|
|
return arr
|
|
}
|
|
|
|
// slice(start, end)
|
|
function clamp (index, len, defaultValue) {
|
|
if (typeof index !== 'number') return defaultValue
|
|
index = ~~index; // Coerce to integer.
|
|
if (index >= len) return len
|
|
if (index >= 0) return index
|
|
index += len
|
|
if (index >= 0) return index
|
|
return 0
|
|
}
|
|
|
|
function coerce (length) {
|
|
// Coerce length to a number (possibly NaN), round up
|
|
// in case it's fractional (e.g. 123.456) then do a
|
|
// double negate to coerce a NaN to 0. Easy, right?
|
|
length = ~~Math.ceil(+length)
|
|
return length < 0 ? 0 : length
|
|
}
|
|
|
|
function isArray (subject) {
|
|
return (Array.isArray || function (subject) {
|
|
return Object.prototype.toString.call(subject) === '[object Array]'
|
|
})(subject)
|
|
}
|
|
|
|
function isArrayish (subject) {
|
|
return isArray(subject) || Buffer.isBuffer(subject) ||
|
|
subject && typeof subject === 'object' &&
|
|
typeof subject.length === 'number'
|
|
}
|
|
|
|
function toHex (n) {
|
|
if (n < 16) return '0' + n.toString(16)
|
|
return n.toString(16)
|
|
}
|
|
|
|
function utf8ToBytes (str) {
|
|
var byteArray = []
|
|
for (var i = 0; i < str.length; i++) {
|
|
var b = str.charCodeAt(i)
|
|
if (b <= 0x7F)
|
|
byteArray.push(str.charCodeAt(i))
|
|
else {
|
|
var start = i
|
|
if (b >= 0xD800 && b <= 0xDFFF) i++
|
|
var h = encodeURIComponent(str.slice(start, i+1)).substr(1).split('%')
|
|
for (var j = 0; j < h.length; j++)
|
|
byteArray.push(parseInt(h[j], 16))
|
|
}
|
|
}
|
|
return byteArray
|
|
}
|
|
|
|
function asciiToBytes (str) {
|
|
var byteArray = []
|
|
for (var i = 0; i < str.length; i++) {
|
|
// Node's code seems to be doing this and not & 0x7F..
|
|
byteArray.push(str.charCodeAt(i) & 0xFF)
|
|
}
|
|
return byteArray
|
|
}
|
|
|
|
function utf16leToBytes (str) {
|
|
var c, hi, lo
|
|
var byteArray = []
|
|
for (var i = 0; i < str.length; i++) {
|
|
c = str.charCodeAt(i)
|
|
hi = c >> 8
|
|
lo = c % 256
|
|
byteArray.push(lo)
|
|
byteArray.push(hi)
|
|
}
|
|
|
|
return byteArray
|
|
}
|
|
|
|
function base64ToBytes (str) {
|
|
return base64.toByteArray(str)
|
|
}
|
|
|
|
function blitBuffer (src, dst, offset, length) {
|
|
var pos
|
|
for (var i = 0; i < length; i++) {
|
|
if ((i + offset >= dst.length) || (i >= src.length))
|
|
break
|
|
dst[i + offset] = src[i]
|
|
}
|
|
return i
|
|
}
|
|
|
|
function decodeUtf8Char (str) {
|
|
try {
|
|
return decodeURIComponent(str)
|
|
} catch (err) {
|
|
return String.fromCharCode(0xFFFD) // UTF 8 invalid char
|
|
}
|
|
}
|
|
|
|
/*
|
|
* We have to make sure that the value is a valid integer. This means that it
|
|
* is non-negative. It has no fractional component and that it does not
|
|
* exceed the maximum allowed value.
|
|
*/
|
|
function verifuint (value, max) {
|
|
assert(typeof value === 'number', 'cannot write a non-number as a number')
|
|
assert(value >= 0, 'specified a negative value for writing an unsigned value')
|
|
assert(value <= max, 'value is larger than maximum value for type')
|
|
assert(Math.floor(value) === value, 'value has a fractional component')
|
|
}
|
|
|
|
function verifsint (value, max, min) {
|
|
assert(typeof value === 'number', 'cannot write a non-number as a number')
|
|
assert(value <= max, 'value larger than maximum allowed value')
|
|
assert(value >= min, 'value smaller than minimum allowed value')
|
|
assert(Math.floor(value) === value, 'value has a fractional component')
|
|
}
|
|
|
|
function verifIEEE754 (value, max, min) {
|
|
assert(typeof value === 'number', 'cannot write a non-number as a number')
|
|
assert(value <= max, 'value larger than maximum allowed value')
|
|
assert(value >= min, 'value smaller than minimum allowed value')
|
|
}
|
|
|
|
function assert (test, message) {
|
|
if (!test) throw new Error(message || 'Failed assertion')
|
|
}
|
|
|
|
},{"base64-js":129,"ieee754":130}],129:[function(_dereq_,module,exports){
|
|
var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
|
|
;(function (exports) {
|
|
'use strict';
|
|
|
|
var Arr = (typeof Uint8Array !== 'undefined')
|
|
? Uint8Array
|
|
: Array
|
|
|
|
var ZERO = '0'.charCodeAt(0)
|
|
var PLUS = '+'.charCodeAt(0)
|
|
var SLASH = '/'.charCodeAt(0)
|
|
var NUMBER = '0'.charCodeAt(0)
|
|
var LOWER = 'a'.charCodeAt(0)
|
|
var UPPER = 'A'.charCodeAt(0)
|
|
|
|
function decode (elt) {
|
|
var code = elt.charCodeAt(0)
|
|
if (code === PLUS)
|
|
return 62 // '+'
|
|
if (code === SLASH)
|
|
return 63 // '/'
|
|
if (code < NUMBER)
|
|
return -1 //no match
|
|
if (code < NUMBER + 10)
|
|
return code - NUMBER + 26 + 26
|
|
if (code < UPPER + 26)
|
|
return code - UPPER
|
|
if (code < LOWER + 26)
|
|
return code - LOWER + 26
|
|
}
|
|
|
|
function b64ToByteArray (b64) {
|
|
var i, j, l, tmp, placeHolders, arr
|
|
|
|
if (b64.length % 4 > 0) {
|
|
throw new Error('Invalid string. Length must be a multiple of 4')
|
|
}
|
|
|
|
// the number of equal signs (place holders)
|
|
// if there are two placeholders, than the two characters before it
|
|
// represent one byte
|
|
// if there is only one, then the three characters before it represent 2 bytes
|
|
// this is just a cheap hack to not do indexOf twice
|
|
var len = b64.length
|
|
placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0
|
|
|
|
// base64 is 4/3 + up to two characters of the original data
|
|
arr = new Arr(b64.length * 3 / 4 - placeHolders)
|
|
|
|
// if there are placeholders, only get up to the last complete 4 chars
|
|
l = placeHolders > 0 ? b64.length - 4 : b64.length
|
|
|
|
var L = 0
|
|
|
|
function push (v) {
|
|
arr[L++] = v
|
|
}
|
|
|
|
for (i = 0, j = 0; i < l; i += 4, j += 3) {
|
|
tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3))
|
|
push((tmp & 0xFF0000) >> 16)
|
|
push((tmp & 0xFF00) >> 8)
|
|
push(tmp & 0xFF)
|
|
}
|
|
|
|
if (placeHolders === 2) {
|
|
tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4)
|
|
push(tmp & 0xFF)
|
|
} else if (placeHolders === 1) {
|
|
tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2)
|
|
push((tmp >> 8) & 0xFF)
|
|
push(tmp & 0xFF)
|
|
}
|
|
|
|
return arr
|
|
}
|
|
|
|
function uint8ToBase64 (uint8) {
|
|
var i,
|
|
extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes
|
|
output = "",
|
|
temp, length
|
|
|
|
function encode (num) {
|
|
return lookup.charAt(num)
|
|
}
|
|
|
|
function tripletToBase64 (num) {
|
|
return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F)
|
|
}
|
|
|
|
// go through the array every three bytes, we'll deal with trailing stuff later
|
|
for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) {
|
|
temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
|
|
output += tripletToBase64(temp)
|
|
}
|
|
|
|
// pad the end with zeros, but make sure to not forget the extra bytes
|
|
switch (extraBytes) {
|
|
case 1:
|
|
temp = uint8[uint8.length - 1]
|
|
output += encode(temp >> 2)
|
|
output += encode((temp << 4) & 0x3F)
|
|
output += '=='
|
|
break
|
|
case 2:
|
|
temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1])
|
|
output += encode(temp >> 10)
|
|
output += encode((temp >> 4) & 0x3F)
|
|
output += encode((temp << 2) & 0x3F)
|
|
output += '='
|
|
break
|
|
}
|
|
|
|
return output
|
|
}
|
|
|
|
module.exports.toByteArray = b64ToByteArray
|
|
module.exports.fromByteArray = uint8ToBase64
|
|
}())
|
|
|
|
},{}],130:[function(_dereq_,module,exports){
|
|
exports.read = function(buffer, offset, isLE, mLen, nBytes) {
|
|
var e, m,
|
|
eLen = nBytes * 8 - mLen - 1,
|
|
eMax = (1 << eLen) - 1,
|
|
eBias = eMax >> 1,
|
|
nBits = -7,
|
|
i = isLE ? (nBytes - 1) : 0,
|
|
d = isLE ? -1 : 1,
|
|
s = buffer[offset + i];
|
|
|
|
i += d;
|
|
|
|
e = s & ((1 << (-nBits)) - 1);
|
|
s >>= (-nBits);
|
|
nBits += eLen;
|
|
for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8);
|
|
|
|
m = e & ((1 << (-nBits)) - 1);
|
|
e >>= (-nBits);
|
|
nBits += mLen;
|
|
for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8);
|
|
|
|
if (e === 0) {
|
|
e = 1 - eBias;
|
|
} else if (e === eMax) {
|
|
return m ? NaN : ((s ? -1 : 1) * Infinity);
|
|
} else {
|
|
m = m + Math.pow(2, mLen);
|
|
e = e - eBias;
|
|
}
|
|
return (s ? -1 : 1) * m * Math.pow(2, e - mLen);
|
|
};
|
|
|
|
exports.write = function(buffer, value, offset, isLE, mLen, nBytes) {
|
|
var e, m, c,
|
|
eLen = nBytes * 8 - mLen - 1,
|
|
eMax = (1 << eLen) - 1,
|
|
eBias = eMax >> 1,
|
|
rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0),
|
|
i = isLE ? 0 : (nBytes - 1),
|
|
d = isLE ? 1 : -1,
|
|
s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0;
|
|
|
|
value = Math.abs(value);
|
|
|
|
if (isNaN(value) || value === Infinity) {
|
|
m = isNaN(value) ? 1 : 0;
|
|
e = eMax;
|
|
} else {
|
|
e = Math.floor(Math.log(value) / Math.LN2);
|
|
if (value * (c = Math.pow(2, -e)) < 1) {
|
|
e--;
|
|
c *= 2;
|
|
}
|
|
if (e + eBias >= 1) {
|
|
value += rt / c;
|
|
} else {
|
|
value += rt * Math.pow(2, 1 - eBias);
|
|
}
|
|
if (value * c >= 2) {
|
|
e++;
|
|
c /= 2;
|
|
}
|
|
|
|
if (e + eBias >= eMax) {
|
|
m = 0;
|
|
e = eMax;
|
|
} else if (e + eBias >= 1) {
|
|
m = (value * c - 1) * Math.pow(2, mLen);
|
|
e = e + eBias;
|
|
} else {
|
|
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen);
|
|
e = 0;
|
|
}
|
|
}
|
|
|
|
for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8);
|
|
|
|
e = (e << mLen) | m;
|
|
eLen += mLen;
|
|
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8);
|
|
|
|
buffer[offset + i - d] |= s * 128;
|
|
};
|
|
|
|
},{}],131:[function(_dereq_,module,exports){
|
|
var Buffer = _dereq_('buffer').Buffer;
|
|
var intSize = 4;
|
|
var zeroBuffer = new Buffer(intSize); zeroBuffer.fill(0);
|
|
var chrsz = 8;
|
|
|
|
function toArray(buf, bigEndian) {
|
|
if ((buf.length % intSize) !== 0) {
|
|
var len = buf.length + (intSize - (buf.length % intSize));
|
|
buf = Buffer.concat([buf, zeroBuffer], len);
|
|
}
|
|
|
|
var arr = [];
|
|
var fn = bigEndian ? buf.readInt32BE : buf.readInt32LE;
|
|
for (var i = 0; i < buf.length; i += intSize) {
|
|
arr.push(fn.call(buf, i));
|
|
}
|
|
return arr;
|
|
}
|
|
|
|
function toBuffer(arr, size, bigEndian) {
|
|
var buf = new Buffer(size);
|
|
var fn = bigEndian ? buf.writeInt32BE : buf.writeInt32LE;
|
|
for (var i = 0; i < arr.length; i++) {
|
|
fn.call(buf, arr[i], i * 4, true);
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
function hash(buf, fn, hashSize, bigEndian) {
|
|
if (!Buffer.isBuffer(buf)) buf = new Buffer(buf);
|
|
var arr = fn(toArray(buf, bigEndian), buf.length * chrsz);
|
|
return toBuffer(arr, hashSize, bigEndian);
|
|
}
|
|
|
|
module.exports = { hash: hash };
|
|
|
|
},{"buffer":128}],132:[function(_dereq_,module,exports){
|
|
var Buffer = _dereq_('buffer').Buffer
|
|
var sha = _dereq_('./sha')
|
|
var sha256 = _dereq_('./sha256')
|
|
var rng = _dereq_('./rng')
|
|
var md5 = _dereq_('./md5')
|
|
|
|
var algorithms = {
|
|
sha1: sha,
|
|
sha256: sha256,
|
|
md5: md5
|
|
}
|
|
|
|
var blocksize = 64
|
|
var zeroBuffer = new Buffer(blocksize); zeroBuffer.fill(0)
|
|
function hmac(fn, key, data) {
|
|
if(!Buffer.isBuffer(key)) key = new Buffer(key)
|
|
if(!Buffer.isBuffer(data)) data = new Buffer(data)
|
|
|
|
if(key.length > blocksize) {
|
|
key = fn(key)
|
|
} else if(key.length < blocksize) {
|
|
key = Buffer.concat([key, zeroBuffer], blocksize)
|
|
}
|
|
|
|
var ipad = new Buffer(blocksize), opad = new Buffer(blocksize)
|
|
for(var i = 0; i < blocksize; i++) {
|
|
ipad[i] = key[i] ^ 0x36
|
|
opad[i] = key[i] ^ 0x5C
|
|
}
|
|
|
|
var hash = fn(Buffer.concat([ipad, data]))
|
|
return fn(Buffer.concat([opad, hash]))
|
|
}
|
|
|
|
function hash(alg, key) {
|
|
alg = alg || 'sha1'
|
|
var fn = algorithms[alg]
|
|
var bufs = []
|
|
var length = 0
|
|
if(!fn) error('algorithm:', alg, 'is not yet supported')
|
|
return {
|
|
update: function (data) {
|
|
if(!Buffer.isBuffer(data)) data = new Buffer(data)
|
|
|
|
bufs.push(data)
|
|
length += data.length
|
|
return this
|
|
},
|
|
digest: function (enc) {
|
|
var buf = Buffer.concat(bufs)
|
|
var r = key ? hmac(fn, key, buf) : fn(buf)
|
|
bufs = null
|
|
return enc ? r.toString(enc) : r
|
|
}
|
|
}
|
|
}
|
|
|
|
function error () {
|
|
var m = [].slice.call(arguments).join(' ')
|
|
throw new Error([
|
|
m,
|
|
'we accept pull requests',
|
|
'http://github.com/dominictarr/crypto-browserify'
|
|
].join('\n'))
|
|
}
|
|
|
|
exports.createHash = function (alg) { return hash(alg) }
|
|
exports.createHmac = function (alg, key) { return hash(alg, key) }
|
|
exports.randomBytes = function(size, callback) {
|
|
if (callback && callback.call) {
|
|
try {
|
|
callback.call(this, undefined, new Buffer(rng(size)))
|
|
} catch (err) { callback(err) }
|
|
} else {
|
|
return new Buffer(rng(size))
|
|
}
|
|
}
|
|
|
|
function each(a, f) {
|
|
for(var i in a)
|
|
f(a[i], i)
|
|
}
|
|
|
|
// the least I can do is make error messages for the rest of the node.js/crypto api.
|
|
each(['createCredentials'
|
|
, 'createCipher'
|
|
, 'createCipheriv'
|
|
, 'createDecipher'
|
|
, 'createDecipheriv'
|
|
, 'createSign'
|
|
, 'createVerify'
|
|
, 'createDiffieHellman'
|
|
, 'pbkdf2'], function (name) {
|
|
exports[name] = function () {
|
|
error('sorry,', name, 'is not implemented yet')
|
|
}
|
|
})
|
|
|
|
},{"./md5":133,"./rng":134,"./sha":135,"./sha256":136,"buffer":128}],133:[function(_dereq_,module,exports){
|
|
/*
|
|
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
|
|
* Digest Algorithm, as defined in RFC 1321.
|
|
* Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
|
|
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
|
* Distributed under the BSD License
|
|
* See http://pajhome.org.uk/crypt/md5 for more info.
|
|
*/
|
|
|
|
var helpers = _dereq_('./helpers');
|
|
|
|
/*
|
|
* Perform a simple self-test to see if the VM is working
|
|
*/
|
|
function md5_vm_test()
|
|
{
|
|
return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
|
|
}
|
|
|
|
/*
|
|
* Calculate the MD5 of an array of little-endian words, and a bit length
|
|
*/
|
|
function core_md5(x, len)
|
|
{
|
|
/* append padding */
|
|
x[len >> 5] |= 0x80 << ((len) % 32);
|
|
x[(((len + 64) >>> 9) << 4) + 14] = len;
|
|
|
|
var a = 1732584193;
|
|
var b = -271733879;
|
|
var c = -1732584194;
|
|
var d = 271733878;
|
|
|
|
for(var i = 0; i < x.length; i += 16)
|
|
{
|
|
var olda = a;
|
|
var oldb = b;
|
|
var oldc = c;
|
|
var oldd = d;
|
|
|
|
a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
|
|
d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
|
|
c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
|
|
b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
|
|
a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
|
|
d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
|
|
c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
|
|
b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
|
|
a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
|
|
d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
|
|
c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
|
|
b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
|
|
a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
|
|
d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
|
|
c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
|
|
b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
|
|
|
|
a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
|
|
d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
|
|
c = md5_gg(c, d, a, b, x[i+11], 14, 643717713);
|
|
b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
|
|
a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
|
|
d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
|
|
c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
|
|
b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
|
|
a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
|
|
d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
|
|
c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
|
|
b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
|
|
a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
|
|
d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
|
|
c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
|
|
b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
|
|
|
|
a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
|
|
d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
|
|
c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
|
|
b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
|
|
a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
|
|
d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
|
|
c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
|
|
b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
|
|
a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
|
|
d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
|
|
c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
|
|
b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
|
|
a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
|
|
d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
|
|
c = md5_hh(c, d, a, b, x[i+15], 16, 530742520);
|
|
b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
|
|
|
|
a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
|
|
d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
|
|
c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
|
|
b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
|
|
a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
|
|
d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
|
|
c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
|
|
b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
|
|
a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
|
|
d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
|
|
c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
|
|
b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
|
|
a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
|
|
d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
|
|
c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
|
|
b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
|
|
|
|
a = safe_add(a, olda);
|
|
b = safe_add(b, oldb);
|
|
c = safe_add(c, oldc);
|
|
d = safe_add(d, oldd);
|
|
}
|
|
return Array(a, b, c, d);
|
|
|
|
}
|
|
|
|
/*
|
|
* These functions implement the four basic operations the algorithm uses.
|
|
*/
|
|
function md5_cmn(q, a, b, x, s, t)
|
|
{
|
|
return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
|
|
}
|
|
function md5_ff(a, b, c, d, x, s, t)
|
|
{
|
|
return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
|
|
}
|
|
function md5_gg(a, b, c, d, x, s, t)
|
|
{
|
|
return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
|
|
}
|
|
function md5_hh(a, b, c, d, x, s, t)
|
|
{
|
|
return md5_cmn(b ^ c ^ d, a, b, x, s, t);
|
|
}
|
|
function md5_ii(a, b, c, d, x, s, t)
|
|
{
|
|
return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
|
|
}
|
|
|
|
/*
|
|
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
|
|
* to work around bugs in some JS interpreters.
|
|
*/
|
|
function safe_add(x, y)
|
|
{
|
|
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
|
|
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
|
return (msw << 16) | (lsw & 0xFFFF);
|
|
}
|
|
|
|
/*
|
|
* Bitwise rotate a 32-bit number to the left.
|
|
*/
|
|
function bit_rol(num, cnt)
|
|
{
|
|
return (num << cnt) | (num >>> (32 - cnt));
|
|
}
|
|
|
|
module.exports = function md5(buf) {
|
|
return helpers.hash(buf, core_md5, 16);
|
|
};
|
|
|
|
},{"./helpers":131}],134:[function(_dereq_,module,exports){
|
|
// Original code adapted from Robert Kieffer.
|
|
// details at https://github.com/broofa/node-uuid
|
|
(function() {
|
|
var _global = this;
|
|
|
|
var mathRNG, whatwgRNG;
|
|
|
|
// NOTE: Math.random() does not guarantee "cryptographic quality"
|
|
mathRNG = function(size) {
|
|
var bytes = new Array(size);
|
|
var r;
|
|
|
|
for (var i = 0, r; i < size; i++) {
|
|
if ((i & 0x03) == 0) r = Math.random() * 0x100000000;
|
|
bytes[i] = r >>> ((i & 0x03) << 3) & 0xff;
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
|
|
if (_global.crypto && crypto.getRandomValues) {
|
|
whatwgRNG = function(size) {
|
|
var bytes = new Uint8Array(size);
|
|
crypto.getRandomValues(bytes);
|
|
return bytes;
|
|
}
|
|
}
|
|
|
|
module.exports = whatwgRNG || mathRNG;
|
|
|
|
}())
|
|
|
|
},{}],135:[function(_dereq_,module,exports){
|
|
/*
|
|
* A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
|
|
* in FIPS PUB 180-1
|
|
* Version 2.1a Copyright Paul Johnston 2000 - 2002.
|
|
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
|
* Distributed under the BSD License
|
|
* See http://pajhome.org.uk/crypt/md5 for details.
|
|
*/
|
|
|
|
var helpers = _dereq_('./helpers');
|
|
|
|
/*
|
|
* Calculate the SHA-1 of an array of big-endian words, and a bit length
|
|
*/
|
|
function core_sha1(x, len)
|
|
{
|
|
/* append padding */
|
|
x[len >> 5] |= 0x80 << (24 - len % 32);
|
|
x[((len + 64 >> 9) << 4) + 15] = len;
|
|
|
|
var w = Array(80);
|
|
var a = 1732584193;
|
|
var b = -271733879;
|
|
var c = -1732584194;
|
|
var d = 271733878;
|
|
var e = -1009589776;
|
|
|
|
for(var i = 0; i < x.length; i += 16)
|
|
{
|
|
var olda = a;
|
|
var oldb = b;
|
|
var oldc = c;
|
|
var oldd = d;
|
|
var olde = e;
|
|
|
|
for(var j = 0; j < 80; j++)
|
|
{
|
|
if(j < 16) w[j] = x[i + j];
|
|
else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
|
|
var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
|
|
safe_add(safe_add(e, w[j]), sha1_kt(j)));
|
|
e = d;
|
|
d = c;
|
|
c = rol(b, 30);
|
|
b = a;
|
|
a = t;
|
|
}
|
|
|
|
a = safe_add(a, olda);
|
|
b = safe_add(b, oldb);
|
|
c = safe_add(c, oldc);
|
|
d = safe_add(d, oldd);
|
|
e = safe_add(e, olde);
|
|
}
|
|
return Array(a, b, c, d, e);
|
|
|
|
}
|
|
|
|
/*
|
|
* Perform the appropriate triplet combination function for the current
|
|
* iteration
|
|
*/
|
|
function sha1_ft(t, b, c, d)
|
|
{
|
|
if(t < 20) return (b & c) | ((~b) & d);
|
|
if(t < 40) return b ^ c ^ d;
|
|
if(t < 60) return (b & c) | (b & d) | (c & d);
|
|
return b ^ c ^ d;
|
|
}
|
|
|
|
/*
|
|
* Determine the appropriate additive constant for the current iteration
|
|
*/
|
|
function sha1_kt(t)
|
|
{
|
|
return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 :
|
|
(t < 60) ? -1894007588 : -899497514;
|
|
}
|
|
|
|
/*
|
|
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
|
|
* to work around bugs in some JS interpreters.
|
|
*/
|
|
function safe_add(x, y)
|
|
{
|
|
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
|
|
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
|
return (msw << 16) | (lsw & 0xFFFF);
|
|
}
|
|
|
|
/*
|
|
* Bitwise rotate a 32-bit number to the left.
|
|
*/
|
|
function rol(num, cnt)
|
|
{
|
|
return (num << cnt) | (num >>> (32 - cnt));
|
|
}
|
|
|
|
module.exports = function sha1(buf) {
|
|
return helpers.hash(buf, core_sha1, 20, true);
|
|
};
|
|
|
|
},{"./helpers":131}],136:[function(_dereq_,module,exports){
|
|
|
|
/**
|
|
* A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
|
|
* in FIPS 180-2
|
|
* Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009.
|
|
* Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
|
|
*
|
|
*/
|
|
|
|
var helpers = _dereq_('./helpers');
|
|
|
|
var safe_add = function(x, y) {
|
|
var lsw = (x & 0xFFFF) + (y & 0xFFFF);
|
|
var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
|
|
return (msw << 16) | (lsw & 0xFFFF);
|
|
};
|
|
|
|
var S = function(X, n) {
|
|
return (X >>> n) | (X << (32 - n));
|
|
};
|
|
|
|
var R = function(X, n) {
|
|
return (X >>> n);
|
|
};
|
|
|
|
var Ch = function(x, y, z) {
|
|
return ((x & y) ^ ((~x) & z));
|
|
};
|
|
|
|
var Maj = function(x, y, z) {
|
|
return ((x & y) ^ (x & z) ^ (y & z));
|
|
};
|
|
|
|
var Sigma0256 = function(x) {
|
|
return (S(x, 2) ^ S(x, 13) ^ S(x, 22));
|
|
};
|
|
|
|
var Sigma1256 = function(x) {
|
|
return (S(x, 6) ^ S(x, 11) ^ S(x, 25));
|
|
};
|
|
|
|
var Gamma0256 = function(x) {
|
|
return (S(x, 7) ^ S(x, 18) ^ R(x, 3));
|
|
};
|
|
|
|
var Gamma1256 = function(x) {
|
|
return (S(x, 17) ^ S(x, 19) ^ R(x, 10));
|
|
};
|
|
|
|
var core_sha256 = function(m, l) {
|
|
var K = new Array(0x428A2F98,0x71374491,0xB5C0FBCF,0xE9B5DBA5,0x3956C25B,0x59F111F1,0x923F82A4,0xAB1C5ED5,0xD807AA98,0x12835B01,0x243185BE,0x550C7DC3,0x72BE5D74,0x80DEB1FE,0x9BDC06A7,0xC19BF174,0xE49B69C1,0xEFBE4786,0xFC19DC6,0x240CA1CC,0x2DE92C6F,0x4A7484AA,0x5CB0A9DC,0x76F988DA,0x983E5152,0xA831C66D,0xB00327C8,0xBF597FC7,0xC6E00BF3,0xD5A79147,0x6CA6351,0x14292967,0x27B70A85,0x2E1B2138,0x4D2C6DFC,0x53380D13,0x650A7354,0x766A0ABB,0x81C2C92E,0x92722C85,0xA2BFE8A1,0xA81A664B,0xC24B8B70,0xC76C51A3,0xD192E819,0xD6990624,0xF40E3585,0x106AA070,0x19A4C116,0x1E376C08,0x2748774C,0x34B0BCB5,0x391C0CB3,0x4ED8AA4A,0x5B9CCA4F,0x682E6FF3,0x748F82EE,0x78A5636F,0x84C87814,0x8CC70208,0x90BEFFFA,0xA4506CEB,0xBEF9A3F7,0xC67178F2);
|
|
var HASH = new Array(0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19);
|
|
var W = new Array(64);
|
|
var a, b, c, d, e, f, g, h, i, j;
|
|
var T1, T2;
|
|
/* append padding */
|
|
m[l >> 5] |= 0x80 << (24 - l % 32);
|
|
m[((l + 64 >> 9) << 4) + 15] = l;
|
|
for (var i = 0; i < m.length; i += 16) {
|
|
a = HASH[0]; b = HASH[1]; c = HASH[2]; d = HASH[3]; e = HASH[4]; f = HASH[5]; g = HASH[6]; h = HASH[7];
|
|
for (var j = 0; j < 64; j++) {
|
|
if (j < 16) {
|
|
W[j] = m[j + i];
|
|
} else {
|
|
W[j] = safe_add(safe_add(safe_add(Gamma1256(W[j - 2]), W[j - 7]), Gamma0256(W[j - 15])), W[j - 16]);
|
|
}
|
|
T1 = safe_add(safe_add(safe_add(safe_add(h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]);
|
|
T2 = safe_add(Sigma0256(a), Maj(a, b, c));
|
|
h = g; g = f; f = e; e = safe_add(d, T1); d = c; c = b; b = a; a = safe_add(T1, T2);
|
|
}
|
|
HASH[0] = safe_add(a, HASH[0]); HASH[1] = safe_add(b, HASH[1]); HASH[2] = safe_add(c, HASH[2]); HASH[3] = safe_add(d, HASH[3]);
|
|
HASH[4] = safe_add(e, HASH[4]); HASH[5] = safe_add(f, HASH[5]); HASH[6] = safe_add(g, HASH[6]); HASH[7] = safe_add(h, HASH[7]);
|
|
}
|
|
return HASH;
|
|
};
|
|
|
|
module.exports = function sha256(buf) {
|
|
return helpers.hash(buf, core_sha256, 32, true);
|
|
};
|
|
|
|
},{"./helpers":131}],137:[function(_dereq_,module,exports){
|
|
// 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.
|
|
|
|
function EventEmitter() {
|
|
this._events = this._events || {};
|
|
this._maxListeners = this._maxListeners || undefined;
|
|
}
|
|
module.exports = EventEmitter;
|
|
|
|
// Backwards-compat with node 0.10.x
|
|
EventEmitter.EventEmitter = EventEmitter;
|
|
|
|
EventEmitter.prototype._events = undefined;
|
|
EventEmitter.prototype._maxListeners = undefined;
|
|
|
|
// By default EventEmitters will print a warning if more than 10 listeners are
|
|
// added to it. This is a useful default which helps finding memory leaks.
|
|
EventEmitter.defaultMaxListeners = 10;
|
|
|
|
// Obviously not all Emitters should be limited to 10. This function allows
|
|
// that to be increased. Set to zero for unlimited.
|
|
EventEmitter.prototype.setMaxListeners = function(n) {
|
|
if (!isNumber(n) || n < 0 || isNaN(n))
|
|
throw TypeError('n must be a positive number');
|
|
this._maxListeners = n;
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.emit = function(type) {
|
|
var er, handler, len, args, i, listeners;
|
|
|
|
if (!this._events)
|
|
this._events = {};
|
|
|
|
// If there is no 'error' event listener then throw.
|
|
if (type === 'error') {
|
|
if (!this._events.error ||
|
|
(isObject(this._events.error) && !this._events.error.length)) {
|
|
er = arguments[1];
|
|
if (er instanceof Error) {
|
|
throw er; // Unhandled 'error' event
|
|
} else {
|
|
throw TypeError('Uncaught, unspecified "error" event.');
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
|
|
handler = this._events[type];
|
|
|
|
if (isUndefined(handler))
|
|
return false;
|
|
|
|
if (isFunction(handler)) {
|
|
switch (arguments.length) {
|
|
// fast cases
|
|
case 1:
|
|
handler.call(this);
|
|
break;
|
|
case 2:
|
|
handler.call(this, arguments[1]);
|
|
break;
|
|
case 3:
|
|
handler.call(this, arguments[1], arguments[2]);
|
|
break;
|
|
// slower
|
|
default:
|
|
len = arguments.length;
|
|
args = new Array(len - 1);
|
|
for (i = 1; i < len; i++)
|
|
args[i - 1] = arguments[i];
|
|
handler.apply(this, args);
|
|
}
|
|
} else if (isObject(handler)) {
|
|
len = arguments.length;
|
|
args = new Array(len - 1);
|
|
for (i = 1; i < len; i++)
|
|
args[i - 1] = arguments[i];
|
|
|
|
listeners = handler.slice();
|
|
len = listeners.length;
|
|
for (i = 0; i < len; i++)
|
|
listeners[i].apply(this, args);
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
EventEmitter.prototype.addListener = function(type, listener) {
|
|
var m;
|
|
|
|
if (!isFunction(listener))
|
|
throw TypeError('listener must be a function');
|
|
|
|
if (!this._events)
|
|
this._events = {};
|
|
|
|
// To avoid recursion in the case that type === "newListener"! Before
|
|
// adding it to the listeners, first emit "newListener".
|
|
if (this._events.newListener)
|
|
this.emit('newListener', type,
|
|
isFunction(listener.listener) ?
|
|
listener.listener : listener);
|
|
|
|
if (!this._events[type])
|
|
// Optimize the case of one listener. Don't need the extra array object.
|
|
this._events[type] = listener;
|
|
else if (isObject(this._events[type]))
|
|
// If we've already got an array, just append.
|
|
this._events[type].push(listener);
|
|
else
|
|
// Adding the second element, need to change to array.
|
|
this._events[type] = [this._events[type], listener];
|
|
|
|
// Check for listener leak
|
|
if (isObject(this._events[type]) && !this._events[type].warned) {
|
|
var m;
|
|
if (!isUndefined(this._maxListeners)) {
|
|
m = this._maxListeners;
|
|
} else {
|
|
m = EventEmitter.defaultMaxListeners;
|
|
}
|
|
|
|
if (m && m > 0 && this._events[type].length > m) {
|
|
this._events[type].warned = true;
|
|
console.error('(node) warning: possible EventEmitter memory ' +
|
|
'leak detected. %d listeners added. ' +
|
|
'Use emitter.setMaxListeners() to increase limit.',
|
|
this._events[type].length);
|
|
console.trace();
|
|
}
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
|
|
|
|
EventEmitter.prototype.once = function(type, listener) {
|
|
if (!isFunction(listener))
|
|
throw TypeError('listener must be a function');
|
|
|
|
var fired = false;
|
|
|
|
function g() {
|
|
this.removeListener(type, g);
|
|
|
|
if (!fired) {
|
|
fired = true;
|
|
listener.apply(this, arguments);
|
|
}
|
|
}
|
|
|
|
g.listener = listener;
|
|
this.on(type, g);
|
|
|
|
return this;
|
|
};
|
|
|
|
// emits a 'removeListener' event iff the listener was removed
|
|
EventEmitter.prototype.removeListener = function(type, listener) {
|
|
var list, position, length, i;
|
|
|
|
if (!isFunction(listener))
|
|
throw TypeError('listener must be a function');
|
|
|
|
if (!this._events || !this._events[type])
|
|
return this;
|
|
|
|
list = this._events[type];
|
|
length = list.length;
|
|
position = -1;
|
|
|
|
if (list === listener ||
|
|
(isFunction(list.listener) && list.listener === listener)) {
|
|
delete this._events[type];
|
|
if (this._events.removeListener)
|
|
this.emit('removeListener', type, listener);
|
|
|
|
} else if (isObject(list)) {
|
|
for (i = length; i-- > 0;) {
|
|
if (list[i] === listener ||
|
|
(list[i].listener && list[i].listener === listener)) {
|
|
position = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (position < 0)
|
|
return this;
|
|
|
|
if (list.length === 1) {
|
|
list.length = 0;
|
|
delete this._events[type];
|
|
} else {
|
|
list.splice(position, 1);
|
|
}
|
|
|
|
if (this._events.removeListener)
|
|
this.emit('removeListener', type, listener);
|
|
}
|
|
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.removeAllListeners = function(type) {
|
|
var key, listeners;
|
|
|
|
if (!this._events)
|
|
return this;
|
|
|
|
// not listening for removeListener, no need to emit
|
|
if (!this._events.removeListener) {
|
|
if (arguments.length === 0)
|
|
this._events = {};
|
|
else if (this._events[type])
|
|
delete this._events[type];
|
|
return this;
|
|
}
|
|
|
|
// emit removeListener for all listeners on all events
|
|
if (arguments.length === 0) {
|
|
for (key in this._events) {
|
|
if (key === 'removeListener') continue;
|
|
this.removeAllListeners(key);
|
|
}
|
|
this.removeAllListeners('removeListener');
|
|
this._events = {};
|
|
return this;
|
|
}
|
|
|
|
listeners = this._events[type];
|
|
|
|
if (isFunction(listeners)) {
|
|
this.removeListener(type, listeners);
|
|
} else {
|
|
// LIFO order
|
|
while (listeners.length)
|
|
this.removeListener(type, listeners[listeners.length - 1]);
|
|
}
|
|
delete this._events[type];
|
|
|
|
return this;
|
|
};
|
|
|
|
EventEmitter.prototype.listeners = function(type) {
|
|
var ret;
|
|
if (!this._events || !this._events[type])
|
|
ret = [];
|
|
else if (isFunction(this._events[type]))
|
|
ret = [this._events[type]];
|
|
else
|
|
ret = this._events[type].slice();
|
|
return ret;
|
|
};
|
|
|
|
EventEmitter.listenerCount = function(emitter, type) {
|
|
var ret;
|
|
if (!emitter._events || !emitter._events[type])
|
|
ret = 0;
|
|
else if (isFunction(emitter._events[type]))
|
|
ret = 1;
|
|
else
|
|
ret = emitter._events[type].length;
|
|
return ret;
|
|
};
|
|
|
|
function isFunction(arg) {
|
|
return typeof arg === 'function';
|
|
}
|
|
|
|
function isNumber(arg) {
|
|
return typeof arg === 'number';
|
|
}
|
|
|
|
function isObject(arg) {
|
|
return typeof arg === 'object' && arg !== null;
|
|
}
|
|
|
|
function isUndefined(arg) {
|
|
return arg === void 0;
|
|
}
|
|
|
|
},{}],138:[function(_dereq_,module,exports){
|
|
var http = module.exports;
|
|
var EventEmitter = _dereq_('events').EventEmitter;
|
|
var Request = _dereq_('./lib/request');
|
|
var url = _dereq_('url')
|
|
|
|
http.request = function (params, cb) {
|
|
if (typeof params === 'string') {
|
|
params = url.parse(params)
|
|
}
|
|
if (!params) params = {};
|
|
if (!params.host && !params.port) {
|
|
params.port = parseInt(window.location.port, 10);
|
|
}
|
|
if (!params.host && params.hostname) {
|
|
params.host = params.hostname;
|
|
}
|
|
|
|
if (!params.scheme) params.scheme = window.location.protocol.split(':')[0];
|
|
if (!params.host) {
|
|
params.host = window.location.hostname || window.location.host;
|
|
}
|
|
if (/:/.test(params.host)) {
|
|
if (!params.port) {
|
|
params.port = params.host.split(':')[1];
|
|
}
|
|
params.host = params.host.split(':')[0];
|
|
}
|
|
if (!params.port) params.port = params.scheme == 'https' ? 443 : 80;
|
|
|
|
var req = new Request(new xhrHttp, params);
|
|
if (cb) req.on('response', cb);
|
|
return req;
|
|
};
|
|
|
|
http.get = function (params, cb) {
|
|
params.method = 'GET';
|
|
var req = http.request(params, cb);
|
|
req.end();
|
|
return req;
|
|
};
|
|
|
|
http.Agent = function () {};
|
|
http.Agent.defaultMaxSockets = 4;
|
|
|
|
var xhrHttp = (function () {
|
|
if (typeof window === 'undefined') {
|
|
throw new Error('no window object present');
|
|
}
|
|
else if (window.XMLHttpRequest) {
|
|
return window.XMLHttpRequest;
|
|
}
|
|
else if (window.ActiveXObject) {
|
|
var axs = [
|
|
'Msxml2.XMLHTTP.6.0',
|
|
'Msxml2.XMLHTTP.3.0',
|
|
'Microsoft.XMLHTTP'
|
|
];
|
|
for (var i = 0; i < axs.length; i++) {
|
|
try {
|
|
var ax = new(window.ActiveXObject)(axs[i]);
|
|
return function () {
|
|
if (ax) {
|
|
var ax_ = ax;
|
|
ax = null;
|
|
return ax_;
|
|
}
|
|
else {
|
|
return new(window.ActiveXObject)(axs[i]);
|
|
}
|
|
};
|
|
}
|
|
catch (e) {}
|
|
}
|
|
throw new Error('ajax not supported in this browser')
|
|
}
|
|
else {
|
|
throw new Error('ajax not supported in this browser');
|
|
}
|
|
})();
|
|
|
|
http.STATUS_CODES = {
|
|
100 : 'Continue',
|
|
101 : 'Switching Protocols',
|
|
102 : 'Processing', // RFC 2518, obsoleted by RFC 4918
|
|
200 : 'OK',
|
|
201 : 'Created',
|
|
202 : 'Accepted',
|
|
203 : 'Non-Authoritative Information',
|
|
204 : 'No Content',
|
|
205 : 'Reset Content',
|
|
206 : 'Partial Content',
|
|
207 : 'Multi-Status', // RFC 4918
|
|
300 : 'Multiple Choices',
|
|
301 : 'Moved Permanently',
|
|
302 : 'Moved Temporarily',
|
|
303 : 'See Other',
|
|
304 : 'Not Modified',
|
|
305 : 'Use Proxy',
|
|
307 : 'Temporary Redirect',
|
|
400 : 'Bad Request',
|
|
401 : 'Unauthorized',
|
|
402 : 'Payment Required',
|
|
403 : 'Forbidden',
|
|
404 : 'Not Found',
|
|
405 : 'Method Not Allowed',
|
|
406 : 'Not Acceptable',
|
|
407 : 'Proxy Authentication Required',
|
|
408 : 'Request Time-out',
|
|
409 : 'Conflict',
|
|
410 : 'Gone',
|
|
411 : 'Length Required',
|
|
412 : 'Precondition Failed',
|
|
413 : 'Request Entity Too Large',
|
|
414 : 'Request-URI Too Large',
|
|
415 : 'Unsupported Media Type',
|
|
416 : 'Requested Range Not Satisfiable',
|
|
417 : 'Expectation Failed',
|
|
418 : 'I\'m a teapot', // RFC 2324
|
|
422 : 'Unprocessable Entity', // RFC 4918
|
|
423 : 'Locked', // RFC 4918
|
|
424 : 'Failed Dependency', // RFC 4918
|
|
425 : 'Unordered Collection', // RFC 4918
|
|
426 : 'Upgrade Required', // RFC 2817
|
|
428 : 'Precondition Required', // RFC 6585
|
|
429 : 'Too Many Requests', // RFC 6585
|
|
431 : 'Request Header Fields Too Large',// RFC 6585
|
|
500 : 'Internal Server Error',
|
|
501 : 'Not Implemented',
|
|
502 : 'Bad Gateway',
|
|
503 : 'Service Unavailable',
|
|
504 : 'Gateway Time-out',
|
|
505 : 'HTTP Version Not Supported',
|
|
506 : 'Variant Also Negotiates', // RFC 2295
|
|
507 : 'Insufficient Storage', // RFC 4918
|
|
509 : 'Bandwidth Limit Exceeded',
|
|
510 : 'Not Extended', // RFC 2774
|
|
511 : 'Network Authentication Required' // RFC 6585
|
|
};
|
|
},{"./lib/request":139,"events":137,"url":157}],139:[function(_dereq_,module,exports){
|
|
var Stream = _dereq_('stream');
|
|
var Response = _dereq_('./response');
|
|
var Base64 = _dereq_('Base64');
|
|
var inherits = _dereq_('inherits');
|
|
|
|
var Request = module.exports = function (xhr, params) {
|
|
var self = this;
|
|
self.writable = true;
|
|
self.xhr = xhr;
|
|
self.body = [];
|
|
|
|
self.uri = (params.scheme || 'http') + '://'
|
|
+ params.host
|
|
+ (params.port ? ':' + params.port : '')
|
|
+ (params.path || '/')
|
|
;
|
|
|
|
if (typeof params.withCredentials === 'undefined') {
|
|
params.withCredentials = true;
|
|
}
|
|
|
|
try { xhr.withCredentials = params.withCredentials }
|
|
catch (e) {}
|
|
|
|
xhr.open(
|
|
params.method || 'GET',
|
|
self.uri,
|
|
true
|
|
);
|
|
|
|
self._headers = {};
|
|
|
|
if (params.headers) {
|
|
var keys = objectKeys(params.headers);
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var key = keys[i];
|
|
if (!self.isSafeRequestHeader(key)) continue;
|
|
var value = params.headers[key];
|
|
self.setHeader(key, value);
|
|
}
|
|
}
|
|
|
|
if (params.auth) {
|
|
//basic auth
|
|
this.setHeader('Authorization', 'Basic ' + Base64.btoa(params.auth));
|
|
}
|
|
|
|
var res = new Response;
|
|
res.on('close', function () {
|
|
self.emit('close');
|
|
});
|
|
|
|
res.on('ready', function () {
|
|
self.emit('response', res);
|
|
});
|
|
|
|
xhr.onreadystatechange = function () {
|
|
// Fix for IE9 bug
|
|
// SCRIPT575: Could not complete the operation due to error c00c023f
|
|
// It happens when a request is aborted, calling the success callback anyway with readyState === 4
|
|
if (xhr.__aborted) return;
|
|
res.handle(xhr);
|
|
};
|
|
};
|
|
|
|
inherits(Request, Stream);
|
|
|
|
Request.prototype.setHeader = function (key, value) {
|
|
this._headers[key.toLowerCase()] = value
|
|
};
|
|
|
|
Request.prototype.getHeader = function (key) {
|
|
return this._headers[key.toLowerCase()]
|
|
};
|
|
|
|
Request.prototype.removeHeader = function (key) {
|
|
delete this._headers[key.toLowerCase()]
|
|
};
|
|
|
|
Request.prototype.write = function (s) {
|
|
this.body.push(s);
|
|
};
|
|
|
|
Request.prototype.destroy = function (s) {
|
|
this.xhr.__aborted = true;
|
|
this.xhr.abort();
|
|
this.emit('close');
|
|
};
|
|
|
|
Request.prototype.end = function (s) {
|
|
if (s !== undefined) this.body.push(s);
|
|
|
|
var keys = objectKeys(this._headers);
|
|
for (var i = 0; i < keys.length; i++) {
|
|
var key = keys[i];
|
|
var value = this._headers[key];
|
|
if (isArray(value)) {
|
|
for (var j = 0; j < value.length; j++) {
|
|
this.xhr.setRequestHeader(key, value[j]);
|
|
}
|
|
}
|
|
else this.xhr.setRequestHeader(key, value)
|
|
}
|
|
|
|
if (this.body.length === 0) {
|
|
this.xhr.send('');
|
|
}
|
|
else if (typeof this.body[0] === 'string') {
|
|
this.xhr.send(this.body.join(''));
|
|
}
|
|
else if (isArray(this.body[0])) {
|
|
var body = [];
|
|
for (var i = 0; i < this.body.length; i++) {
|
|
body.push.apply(body, this.body[i]);
|
|
}
|
|
this.xhr.send(body);
|
|
}
|
|
else if (/Array/.test(Object.prototype.toString.call(this.body[0]))) {
|
|
var len = 0;
|
|
for (var i = 0; i < this.body.length; i++) {
|
|
len += this.body[i].length;
|
|
}
|
|
var body = new(this.body[0].constructor)(len);
|
|
var k = 0;
|
|
|
|
for (var i = 0; i < this.body.length; i++) {
|
|
var b = this.body[i];
|
|
for (var j = 0; j < b.length; j++) {
|
|
body[k++] = b[j];
|
|
}
|
|
}
|
|
this.xhr.send(body);
|
|
}
|
|
else {
|
|
var body = '';
|
|
for (var i = 0; i < this.body.length; i++) {
|
|
body += this.body[i].toString();
|
|
}
|
|
this.xhr.send(body);
|
|
}
|
|
};
|
|
|
|
// Taken from http://dxr.mozilla.org/mozilla/mozilla-central/content/base/src/nsXMLHttpRequest.cpp.html
|
|
Request.unsafeHeaders = [
|
|
"accept-charset",
|
|
"accept-encoding",
|
|
"access-control-request-headers",
|
|
"access-control-request-method",
|
|
"connection",
|
|
"content-length",
|
|
"cookie",
|
|
"cookie2",
|
|
"content-transfer-encoding",
|
|
"date",
|
|
"expect",
|
|
"host",
|
|
"keep-alive",
|
|
"origin",
|
|
"referer",
|
|
"te",
|
|
"trailer",
|
|
"transfer-encoding",
|
|
"upgrade",
|
|
"user-agent",
|
|
"via"
|
|
];
|
|
|
|
Request.prototype.isSafeRequestHeader = function (headerName) {
|
|
if (!headerName) return false;
|
|
return indexOf(Request.unsafeHeaders, headerName.toLowerCase()) === -1;
|
|
};
|
|
|
|
var objectKeys = Object.keys || function (obj) {
|
|
var keys = [];
|
|
for (var key in obj) keys.push(key);
|
|
return keys;
|
|
};
|
|
|
|
var isArray = Array.isArray || function (xs) {
|
|
return Object.prototype.toString.call(xs) === '[object Array]';
|
|
};
|
|
|
|
var indexOf = function (xs, x) {
|
|
if (xs.indexOf) return xs.indexOf(x);
|
|
for (var i = 0; i < xs.length; i++) {
|
|
if (xs[i] === x) return i;
|
|
}
|
|
return -1;
|
|
};
|
|
|
|
},{"./response":140,"Base64":141,"inherits":143,"stream":150}],140:[function(_dereq_,module,exports){
|
|
var Stream = _dereq_('stream');
|
|
var util = _dereq_('util');
|
|
|
|
var Response = module.exports = function (res) {
|
|
this.offset = 0;
|
|
this.readable = true;
|
|
};
|
|
|
|
util.inherits(Response, Stream);
|
|
|
|
var capable = {
|
|
streaming : true,
|
|
status2 : true
|
|
};
|
|
|
|
function parseHeaders (res) {
|
|
var lines = res.getAllResponseHeaders().split(/\r?\n/);
|
|
var headers = {};
|
|
for (var i = 0; i < lines.length; i++) {
|
|
var line = lines[i];
|
|
if (line === '') continue;
|
|
|
|
var m = line.match(/^([^:]+):\s*(.*)/);
|
|
if (m) {
|
|
var key = m[1].toLowerCase(), value = m[2];
|
|
|
|
if (headers[key] !== undefined) {
|
|
|
|
if (isArray(headers[key])) {
|
|
headers[key].push(value);
|
|
}
|
|
else {
|
|
headers[key] = [ headers[key], value ];
|
|
}
|
|
}
|
|
else {
|
|
headers[key] = value;
|
|
}
|
|
}
|
|
else {
|
|
headers[line] = true;
|
|
}
|
|
}
|
|
return headers;
|
|
}
|
|
|
|
Response.prototype.getResponse = function (xhr) {
|
|
var respType = String(xhr.responseType).toLowerCase();
|
|
if (respType === 'blob') return xhr.responseBlob || xhr.response;
|
|
if (respType === 'arraybuffer') return xhr.response;
|
|
return xhr.responseText;
|
|
}
|
|
|
|
Response.prototype.getHeader = function (key) {
|
|
return this.headers[key.toLowerCase()];
|
|
};
|
|
|
|
Response.prototype.handle = function (res) {
|
|
if (res.readyState === 2 && capable.status2) {
|
|
try {
|
|
this.statusCode = res.status;
|
|
this.headers = parseHeaders(res);
|
|
}
|
|
catch (err) {
|
|
capable.status2 = false;
|
|
}
|
|
|
|
if (capable.status2) {
|
|
this.emit('ready');
|
|
}
|
|
}
|
|
else if (capable.streaming && res.readyState === 3) {
|
|
try {
|
|
if (!this.statusCode) {
|
|
this.statusCode = res.status;
|
|
this.headers = parseHeaders(res);
|
|
this.emit('ready');
|
|
}
|
|
}
|
|
catch (err) {}
|
|
|
|
try {
|
|
this._emitData(res);
|
|
}
|
|
catch (err) {
|
|
capable.streaming = false;
|
|
}
|
|
}
|
|
else if (res.readyState === 4) {
|
|
if (!this.statusCode) {
|
|
this.statusCode = res.status;
|
|
this.emit('ready');
|
|
}
|
|
this._emitData(res);
|
|
|
|
if (res.error) {
|
|
this.emit('error', this.getResponse(res));
|
|
}
|
|
else this.emit('end');
|
|
|
|
this.emit('close');
|
|
}
|
|
};
|
|
|
|
Response.prototype._emitData = function (res) {
|
|
var respBody = this.getResponse(res);
|
|
if (respBody.toString().match(/ArrayBuffer/)) {
|
|
this.emit('data', new Uint8Array(respBody, this.offset));
|
|
this.offset = respBody.byteLength;
|
|
return;
|
|
}
|
|
if (respBody.length > this.offset) {
|
|
this.emit('data', respBody.slice(this.offset));
|
|
this.offset = respBody.length;
|
|
}
|
|
};
|
|
|
|
var isArray = Array.isArray || function (xs) {
|
|
return Object.prototype.toString.call(xs) === '[object Array]';
|
|
};
|
|
|
|
},{"stream":150,"util":159}],141:[function(_dereq_,module,exports){
|
|
;(function () {
|
|
|
|
var object = typeof exports != 'undefined' ? exports : this; // #8: web workers
|
|
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
|
|
|
|
function InvalidCharacterError(message) {
|
|
this.message = message;
|
|
}
|
|
InvalidCharacterError.prototype = new Error;
|
|
InvalidCharacterError.prototype.name = 'InvalidCharacterError';
|
|
|
|
// encoder
|
|
// [https://gist.github.com/999166] by [https://github.com/nignag]
|
|
object.btoa || (
|
|
object.btoa = function (input) {
|
|
for (
|
|
// initialize result and counter
|
|
var block, charCode, idx = 0, map = chars, output = '';
|
|
// if the next input index does not exist:
|
|
// change the mapping table to "="
|
|
// check if d has no fractional digits
|
|
input.charAt(idx | 0) || (map = '=', idx % 1);
|
|
// "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8
|
|
output += map.charAt(63 & block >> 8 - idx % 1 * 8)
|
|
) {
|
|
charCode = input.charCodeAt(idx += 3/4);
|
|
if (charCode > 0xFF) {
|
|
throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");
|
|
}
|
|
block = block << 8 | charCode;
|
|
}
|
|
return output;
|
|
});
|
|
|
|
// decoder
|
|
// [https://gist.github.com/1020396] by [https://github.com/atk]
|
|
object.atob || (
|
|
object.atob = function (input) {
|
|
input = input.replace(/=+$/, '');
|
|
if (input.length % 4 == 1) {
|
|
throw new InvalidCharacterError("'atob' failed: The string to be decoded is not correctly encoded.");
|
|
}
|
|
for (
|
|
// initialize result and counters
|
|
var bc = 0, bs, buffer, idx = 0, output = '';
|
|
// get next character
|
|
buffer = input.charAt(idx++);
|
|
// character found in table? initialize bit storage and add its ascii value;
|
|
~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
|
|
// and if not first of each 4 characters,
|
|
// convert the first 8 bits to one ascii character
|
|
bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
|
|
) {
|
|
// try to find character in table (0-63, not found => -1)
|
|
buffer = chars.indexOf(buffer);
|
|
}
|
|
return output;
|
|
});
|
|
|
|
}());
|
|
|
|
},{}],142:[function(_dereq_,module,exports){
|
|
var http = _dereq_('http');
|
|
|
|
var https = module.exports;
|
|
|
|
for (var key in http) {
|
|
if (http.hasOwnProperty(key)) https[key] = http[key];
|
|
};
|
|
|
|
https.request = function (params, cb) {
|
|
if (!params) params = {};
|
|
params.scheme = 'https';
|
|
return http.request.call(this, params, cb);
|
|
}
|
|
|
|
},{"http":138}],143:[function(_dereq_,module,exports){
|
|
if (typeof Object.create === 'function') {
|
|
// implementation from standard node.js 'util' module
|
|
module.exports = function inherits(ctor, superCtor) {
|
|
ctor.super_ = superCtor
|
|
ctor.prototype = Object.create(superCtor.prototype, {
|
|
constructor: {
|
|
value: ctor,
|
|
enumerable: false,
|
|
writable: true,
|
|
configurable: true
|
|
}
|
|
});
|
|
};
|
|
} else {
|
|
// old school shim for old browsers
|
|
module.exports = function inherits(ctor, superCtor) {
|
|
ctor.super_ = superCtor
|
|
var TempCtor = function () {}
|
|
TempCtor.prototype = superCtor.prototype
|
|
ctor.prototype = new TempCtor()
|
|
ctor.prototype.constructor = ctor
|
|
}
|
|
}
|
|
|
|
},{}],144:[function(_dereq_,module,exports){
|
|
// shim for using process in browser
|
|
|
|
var process = module.exports = {};
|
|
|
|
process.nextTick = (function () {
|
|
var canSetImmediate = typeof window !== 'undefined'
|
|
&& window.setImmediate;
|
|
var canPost = typeof window !== 'undefined'
|
|
&& window.postMessage && window.addEventListener
|
|
;
|
|
|
|
if (canSetImmediate) {
|
|
return function (f) { return window.setImmediate(f) };
|
|
}
|
|
|
|
if (canPost) {
|
|
var queue = [];
|
|
window.addEventListener('message', function (ev) {
|
|
var source = ev.source;
|
|
if ((source === window || source === null) && ev.data === 'process-tick') {
|
|
ev.stopPropagation();
|
|
if (queue.length > 0) {
|
|
var fn = queue.shift();
|
|
fn();
|
|
}
|
|
}
|
|
}, true);
|
|
|
|
return function nextTick(fn) {
|
|
queue.push(fn);
|
|
window.postMessage('process-tick', '*');
|
|
};
|
|
}
|
|
|
|
return function nextTick(fn) {
|
|
setTimeout(fn, 0);
|
|
};
|
|
})();
|
|
|
|
process.title = 'browser';
|
|
process.browser = true;
|
|
process.env = {};
|
|
process.argv = [];
|
|
|
|
function noop() {}
|
|
|
|
process.on = noop;
|
|
process.once = noop;
|
|
process.off = noop;
|
|
process.emit = noop;
|
|
|
|
process.binding = function (name) {
|
|
throw new Error('process.binding is not supported');
|
|
}
|
|
|
|
// TODO(shtylman)
|
|
process.cwd = function () { return '/' };
|
|
process.chdir = function (dir) {
|
|
throw new Error('process.chdir is not supported');
|
|
};
|
|
|
|
},{}],145:[function(_dereq_,module,exports){
|
|
(function (global){
|
|
/*! http://mths.be/punycode v1.2.4 by @mathias */
|
|
;(function(root) {
|
|
|
|
/** Detect free variables */
|
|
var freeExports = typeof exports == 'object' && exports;
|
|
var freeModule = typeof module == 'object' && module &&
|
|
module.exports == freeExports && module;
|
|
var freeGlobal = typeof global == 'object' && global;
|
|
if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
|
|
root = freeGlobal;
|
|
}
|
|
|
|
/**
|
|
* The `punycode` object.
|
|
* @name punycode
|
|
* @type Object
|
|
*/
|
|
var punycode,
|
|
|
|
/** Highest positive signed 32-bit float value */
|
|
maxInt = 2147483647, // aka. 0x7FFFFFFF or 2^31-1
|
|
|
|
/** Bootstring parameters */
|
|
base = 36,
|
|
tMin = 1,
|
|
tMax = 26,
|
|
skew = 38,
|
|
damp = 700,
|
|
initialBias = 72,
|
|
initialN = 128, // 0x80
|
|
delimiter = '-', // '\x2D'
|
|
|
|
/** Regular expressions */
|
|
regexPunycode = /^xn--/,
|
|
regexNonASCII = /[^ -~]/, // unprintable ASCII chars + non-ASCII chars
|
|
regexSeparators = /\x2E|\u3002|\uFF0E|\uFF61/g, // RFC 3490 separators
|
|
|
|
/** Error messages */
|
|
errors = {
|
|
'overflow': 'Overflow: input needs wider integers to process',
|
|
'not-basic': 'Illegal input >= 0x80 (not a basic code point)',
|
|
'invalid-input': 'Invalid input'
|
|
},
|
|
|
|
/** Convenience shortcuts */
|
|
baseMinusTMin = base - tMin,
|
|
floor = Math.floor,
|
|
stringFromCharCode = String.fromCharCode,
|
|
|
|
/** Temporary variable */
|
|
key;
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/**
|
|
* A generic error utility function.
|
|
* @private
|
|
* @param {String} type The error type.
|
|
* @returns {Error} Throws a `RangeError` with the applicable error message.
|
|
*/
|
|
function error(type) {
|
|
throw RangeError(errors[type]);
|
|
}
|
|
|
|
/**
|
|
* A generic `Array#map` utility function.
|
|
* @private
|
|
* @param {Array} array The array to iterate over.
|
|
* @param {Function} callback The function that gets called for every array
|
|
* item.
|
|
* @returns {Array} A new array of values returned by the callback function.
|
|
*/
|
|
function map(array, fn) {
|
|
var length = array.length;
|
|
while (length--) {
|
|
array[length] = fn(array[length]);
|
|
}
|
|
return array;
|
|
}
|
|
|
|
/**
|
|
* A simple `Array#map`-like wrapper to work with domain name strings.
|
|
* @private
|
|
* @param {String} domain The domain name.
|
|
* @param {Function} callback The function that gets called for every
|
|
* character.
|
|
* @returns {Array} A new string of characters returned by the callback
|
|
* function.
|
|
*/
|
|
function mapDomain(string, fn) {
|
|
return map(string.split(regexSeparators), fn).join('.');
|
|
}
|
|
|
|
/**
|
|
* Creates an array containing the numeric code points of each Unicode
|
|
* character in the string. While JavaScript uses UCS-2 internally,
|
|
* this function will convert a pair of surrogate halves (each of which
|
|
* UCS-2 exposes as separate characters) into a single code point,
|
|
* matching UTF-16.
|
|
* @see `punycode.ucs2.encode`
|
|
* @see <http://mathiasbynens.be/notes/javascript-encoding>
|
|
* @memberOf punycode.ucs2
|
|
* @name decode
|
|
* @param {String} string The Unicode input string (UCS-2).
|
|
* @returns {Array} The new array of code points.
|
|
*/
|
|
function ucs2decode(string) {
|
|
var output = [],
|
|
counter = 0,
|
|
length = string.length,
|
|
value,
|
|
extra;
|
|
while (counter < length) {
|
|
value = string.charCodeAt(counter++);
|
|
if (value >= 0xD800 && value <= 0xDBFF && counter < length) {
|
|
// high surrogate, and there is a next character
|
|
extra = string.charCodeAt(counter++);
|
|
if ((extra & 0xFC00) == 0xDC00) { // low surrogate
|
|
output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000);
|
|
} else {
|
|
// unmatched surrogate; only append this code unit, in case the next
|
|
// code unit is the high surrogate of a surrogate pair
|
|
output.push(value);
|
|
counter--;
|
|
}
|
|
} else {
|
|
output.push(value);
|
|
}
|
|
}
|
|
return output;
|
|
}
|
|
|
|
/**
|
|
* Creates a string based on an array of numeric code points.
|
|
* @see `punycode.ucs2.decode`
|
|
* @memberOf punycode.ucs2
|
|
* @name encode
|
|
* @param {Array} codePoints The array of numeric code points.
|
|
* @returns {String} The new Unicode string (UCS-2).
|
|
*/
|
|
function ucs2encode(array) {
|
|
return map(array, function(value) {
|
|
var output = '';
|
|
if (value > 0xFFFF) {
|
|
value -= 0x10000;
|
|
output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
|
|
value = 0xDC00 | value & 0x3FF;
|
|
}
|
|
output += stringFromCharCode(value);
|
|
return output;
|
|
}).join('');
|
|
}
|
|
|
|
/**
|
|
* Converts a basic code point into a digit/integer.
|
|
* @see `digitToBasic()`
|
|
* @private
|
|
* @param {Number} codePoint The basic numeric code point value.
|
|
* @returns {Number} The numeric value of a basic code point (for use in
|
|
* representing integers) in the range `0` to `base - 1`, or `base` if
|
|
* the code point does not represent a value.
|
|
*/
|
|
function basicToDigit(codePoint) {
|
|
if (codePoint - 48 < 10) {
|
|
return codePoint - 22;
|
|
}
|
|
if (codePoint - 65 < 26) {
|
|
return codePoint - 65;
|
|
}
|
|
if (codePoint - 97 < 26) {
|
|
return codePoint - 97;
|
|
}
|
|
return base;
|
|
}
|
|
|
|
/**
|
|
* Converts a digit/integer into a basic code point.
|
|
* @see `basicToDigit()`
|
|
* @private
|
|
* @param {Number} digit The numeric value of a basic code point.
|
|
* @returns {Number} The basic code point whose value (when used for
|
|
* representing integers) is `digit`, which needs to be in the range
|
|
* `0` to `base - 1`. If `flag` is non-zero, the uppercase form is
|
|
* used; else, the lowercase form is used. The behavior is undefined
|
|
* if `flag` is non-zero and `digit` has no uppercase form.
|
|
*/
|
|
function digitToBasic(digit, flag) {
|
|
// 0..25 map to ASCII a..z or A..Z
|
|
// 26..35 map to ASCII 0..9
|
|
return digit + 22 + 75 * (digit < 26) - ((flag != 0) << 5);
|
|
}
|
|
|
|
/**
|
|
* Bias adaptation function as per section 3.4 of RFC 3492.
|
|
* http://tools.ietf.org/html/rfc3492#section-3.4
|
|
* @private
|
|
*/
|
|
function adapt(delta, numPoints, firstTime) {
|
|
var k = 0;
|
|
delta = firstTime ? floor(delta / damp) : delta >> 1;
|
|
delta += floor(delta / numPoints);
|
|
for (/* no initialization */; delta > baseMinusTMin * tMax >> 1; k += base) {
|
|
delta = floor(delta / baseMinusTMin);
|
|
}
|
|
return floor(k + (baseMinusTMin + 1) * delta / (delta + skew));
|
|
}
|
|
|
|
/**
|
|
* Converts a Punycode string of ASCII-only symbols to a string of Unicode
|
|
* symbols.
|
|
* @memberOf punycode
|
|
* @param {String} input The Punycode string of ASCII-only symbols.
|
|
* @returns {String} The resulting string of Unicode symbols.
|
|
*/
|
|
function decode(input) {
|
|
// Don't use UCS-2
|
|
var output = [],
|
|
inputLength = input.length,
|
|
out,
|
|
i = 0,
|
|
n = initialN,
|
|
bias = initialBias,
|
|
basic,
|
|
j,
|
|
index,
|
|
oldi,
|
|
w,
|
|
k,
|
|
digit,
|
|
t,
|
|
/** Cached calculation results */
|
|
baseMinusT;
|
|
|
|
// Handle the basic code points: let `basic` be the number of input code
|
|
// points before the last delimiter, or `0` if there is none, then copy
|
|
// the first basic code points to the output.
|
|
|
|
basic = input.lastIndexOf(delimiter);
|
|
if (basic < 0) {
|
|
basic = 0;
|
|
}
|
|
|
|
for (j = 0; j < basic; ++j) {
|
|
// if it's not a basic code point
|
|
if (input.charCodeAt(j) >= 0x80) {
|
|
error('not-basic');
|
|
}
|
|
output.push(input.charCodeAt(j));
|
|
}
|
|
|
|
// Main decoding loop: start just after the last delimiter if any basic code
|
|
// points were copied; start at the beginning otherwise.
|
|
|
|
for (index = basic > 0 ? basic + 1 : 0; index < inputLength; /* no final expression */) {
|
|
|
|
// `index` is the index of the next character to be consumed.
|
|
// Decode a generalized variable-length integer into `delta`,
|
|
// which gets added to `i`. The overflow checking is easier
|
|
// if we increase `i` as we go, then subtract off its starting
|
|
// value at the end to obtain `delta`.
|
|
for (oldi = i, w = 1, k = base; /* no condition */; k += base) {
|
|
|
|
if (index >= inputLength) {
|
|
error('invalid-input');
|
|
}
|
|
|
|
digit = basicToDigit(input.charCodeAt(index++));
|
|
|
|
if (digit >= base || digit > floor((maxInt - i) / w)) {
|
|
error('overflow');
|
|
}
|
|
|
|
i += digit * w;
|
|
t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
|
|
|
|
if (digit < t) {
|
|
break;
|
|
}
|
|
|
|
baseMinusT = base - t;
|
|
if (w > floor(maxInt / baseMinusT)) {
|
|
error('overflow');
|
|
}
|
|
|
|
w *= baseMinusT;
|
|
|
|
}
|
|
|
|
out = output.length + 1;
|
|
bias = adapt(i - oldi, out, oldi == 0);
|
|
|
|
// `i` was supposed to wrap around from `out` to `0`,
|
|
// incrementing `n` each time, so we'll fix that now:
|
|
if (floor(i / out) > maxInt - n) {
|
|
error('overflow');
|
|
}
|
|
|
|
n += floor(i / out);
|
|
i %= out;
|
|
|
|
// Insert `n` at position `i` of the output
|
|
output.splice(i++, 0, n);
|
|
|
|
}
|
|
|
|
return ucs2encode(output);
|
|
}
|
|
|
|
/**
|
|
* Converts a string of Unicode symbols to a Punycode string of ASCII-only
|
|
* symbols.
|
|
* @memberOf punycode
|
|
* @param {String} input The string of Unicode symbols.
|
|
* @returns {String} The resulting Punycode string of ASCII-only symbols.
|
|
*/
|
|
function encode(input) {
|
|
var n,
|
|
delta,
|
|
handledCPCount,
|
|
basicLength,
|
|
bias,
|
|
j,
|
|
m,
|
|
q,
|
|
k,
|
|
t,
|
|
currentValue,
|
|
output = [],
|
|
/** `inputLength` will hold the number of code points in `input`. */
|
|
inputLength,
|
|
/** Cached calculation results */
|
|
handledCPCountPlusOne,
|
|
baseMinusT,
|
|
qMinusT;
|
|
|
|
// Convert the input in UCS-2 to Unicode
|
|
input = ucs2decode(input);
|
|
|
|
// Cache the length
|
|
inputLength = input.length;
|
|
|
|
// Initialize the state
|
|
n = initialN;
|
|
delta = 0;
|
|
bias = initialBias;
|
|
|
|
// Handle the basic code points
|
|
for (j = 0; j < inputLength; ++j) {
|
|
currentValue = input[j];
|
|
if (currentValue < 0x80) {
|
|
output.push(stringFromCharCode(currentValue));
|
|
}
|
|
}
|
|
|
|
handledCPCount = basicLength = output.length;
|
|
|
|
// `handledCPCount` is the number of code points that have been handled;
|
|
// `basicLength` is the number of basic code points.
|
|
|
|
// Finish the basic string - if it is not empty - with a delimiter
|
|
if (basicLength) {
|
|
output.push(delimiter);
|
|
}
|
|
|
|
// Main encoding loop:
|
|
while (handledCPCount < inputLength) {
|
|
|
|
// All non-basic code points < n have been handled already. Find the next
|
|
// larger one:
|
|
for (m = maxInt, j = 0; j < inputLength; ++j) {
|
|
currentValue = input[j];
|
|
if (currentValue >= n && currentValue < m) {
|
|
m = currentValue;
|
|
}
|
|
}
|
|
|
|
// Increase `delta` enough to advance the decoder's <n,i> state to <m,0>,
|
|
// but guard against overflow
|
|
handledCPCountPlusOne = handledCPCount + 1;
|
|
if (m - n > floor((maxInt - delta) / handledCPCountPlusOne)) {
|
|
error('overflow');
|
|
}
|
|
|
|
delta += (m - n) * handledCPCountPlusOne;
|
|
n = m;
|
|
|
|
for (j = 0; j < inputLength; ++j) {
|
|
currentValue = input[j];
|
|
|
|
if (currentValue < n && ++delta > maxInt) {
|
|
error('overflow');
|
|
}
|
|
|
|
if (currentValue == n) {
|
|
// Represent delta as a generalized variable-length integer
|
|
for (q = delta, k = base; /* no condition */; k += base) {
|
|
t = k <= bias ? tMin : (k >= bias + tMax ? tMax : k - bias);
|
|
if (q < t) {
|
|
break;
|
|
}
|
|
qMinusT = q - t;
|
|
baseMinusT = base - t;
|
|
output.push(
|
|
stringFromCharCode(digitToBasic(t + qMinusT % baseMinusT, 0))
|
|
);
|
|
q = floor(qMinusT / baseMinusT);
|
|
}
|
|
|
|
output.push(stringFromCharCode(digitToBasic(q, 0)));
|
|
bias = adapt(delta, handledCPCountPlusOne, handledCPCount == basicLength);
|
|
delta = 0;
|
|
++handledCPCount;
|
|
}
|
|
}
|
|
|
|
++delta;
|
|
++n;
|
|
|
|
}
|
|
return output.join('');
|
|
}
|
|
|
|
/**
|
|
* Converts a Punycode string representing a domain name to Unicode. Only the
|
|
* Punycoded parts of the domain name will be converted, i.e. it doesn't
|
|
* matter if you call it on a string that has already been converted to
|
|
* Unicode.
|
|
* @memberOf punycode
|
|
* @param {String} domain The Punycode domain name to convert to Unicode.
|
|
* @returns {String} The Unicode representation of the given Punycode
|
|
* string.
|
|
*/
|
|
function toUnicode(domain) {
|
|
return mapDomain(domain, function(string) {
|
|
return regexPunycode.test(string)
|
|
? decode(string.slice(4).toLowerCase())
|
|
: string;
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Converts a Unicode string representing a domain name to Punycode. Only the
|
|
* non-ASCII parts of the domain name will be converted, i.e. it doesn't
|
|
* matter if you call it with a domain that's already in ASCII.
|
|
* @memberOf punycode
|
|
* @param {String} domain The domain name to convert, as a Unicode string.
|
|
* @returns {String} The Punycode representation of the given domain name.
|
|
*/
|
|
function toASCII(domain) {
|
|
return mapDomain(domain, function(string) {
|
|
return regexNonASCII.test(string)
|
|
? 'xn--' + encode(string)
|
|
: string;
|
|
});
|
|
}
|
|
|
|
/*--------------------------------------------------------------------------*/
|
|
|
|
/** Define the public API */
|
|
punycode = {
|
|
/**
|
|
* A string representing the current Punycode.js version number.
|
|
* @memberOf punycode
|
|
* @type String
|
|
*/
|
|
'version': '1.2.4',
|
|
/**
|
|
* An object of methods to convert from JavaScript's internal character
|
|
* representation (UCS-2) to Unicode code points, and back.
|
|
* @see <http://mathiasbynens.be/notes/javascript-encoding>
|
|
* @memberOf punycode
|
|
* @type Object
|
|
*/
|
|
'ucs2': {
|
|
'decode': ucs2decode,
|
|
'encode': ucs2encode
|
|
},
|
|
'decode': decode,
|
|
'encode': encode,
|
|
'toASCII': toASCII,
|
|
'toUnicode': toUnicode
|
|
};
|
|
|
|
/** Expose `punycode` */
|
|
// Some AMD build optimizers, like r.js, check for specific condition patterns
|
|
// like the following:
|
|
if (
|
|
typeof define == 'function' &&
|
|
typeof define.amd == 'object' &&
|
|
define.amd
|
|
) {
|
|
define('punycode', function() {
|
|
return punycode;
|
|
});
|
|
} else if (freeExports && !freeExports.nodeType) {
|
|
if (freeModule) { // in Node.js or RingoJS v0.8.0+
|
|
freeModule.exports = punycode;
|
|
} else { // in Narwhal or RingoJS v0.7.0-
|
|
for (key in punycode) {
|
|
punycode.hasOwnProperty(key) && (freeExports[key] = punycode[key]);
|
|
}
|
|
}
|
|
} else { // in Rhino or a web browser
|
|
root.punycode = punycode;
|
|
}
|
|
|
|
}(this));
|
|
|
|
}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
|
},{}],146:[function(_dereq_,module,exports){
|
|
// 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.
|
|
|
|
'use strict';
|
|
|
|
// If obj.hasOwnProperty has been overridden, then calling
|
|
// obj.hasOwnProperty(prop) will break.
|
|
// See: https://github.com/joyent/node/issues/1707
|
|
function hasOwnProperty(obj, prop) {
|
|
return Object.prototype.hasOwnProperty.call(obj, prop);
|
|
}
|
|
|
|
module.exports = function(qs, sep, eq, options) {
|
|
sep = sep || '&';
|
|
eq = eq || '=';
|
|
var obj = {};
|
|
|
|
if (typeof qs !== 'string' || qs.length === 0) {
|
|
return obj;
|
|
}
|
|
|
|
var regexp = /\+/g;
|
|
qs = qs.split(sep);
|
|
|
|
var maxKeys = 1000;
|
|
if (options && typeof options.maxKeys === 'number') {
|
|
maxKeys = options.maxKeys;
|
|
}
|
|
|
|
var len = qs.length;
|
|
// maxKeys <= 0 means that we should not limit keys count
|
|
if (maxKeys > 0 && len > maxKeys) {
|
|
len = maxKeys;
|
|
}
|
|
|
|
for (var i = 0; i < len; ++i) {
|
|
var x = qs[i].replace(regexp, '%20'),
|
|
idx = x.indexOf(eq),
|
|
kstr, vstr, k, v;
|
|
|
|
if (idx >= 0) {
|
|
kstr = x.substr(0, idx);
|
|
vstr = x.substr(idx + 1);
|
|
} else {
|
|
kstr = x;
|
|
vstr = '';
|
|
}
|
|
|
|
k = decodeURIComponent(kstr);
|
|
v = decodeURIComponent(vstr);
|
|
|
|
if (!hasOwnProperty(obj, k)) {
|
|
obj[k] = v;
|
|
} else if (isArray(obj[k])) {
|
|
obj[k].push(v);
|
|
} else {
|
|
obj[k] = [obj[k], v];
|
|
}
|
|
}
|
|
|
|
return obj;
|
|
};
|
|
|
|
var isArray = Array.isArray || function (xs) {
|
|
return Object.prototype.toString.call(xs) === '[object Array]';
|
|
};
|
|
|
|
},{}],147:[function(_dereq_,module,exports){
|
|
// 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.
|
|
|
|
'use strict';
|
|
|
|
var stringifyPrimitive = function(v) {
|
|
switch (typeof v) {
|
|
case 'string':
|
|
return v;
|
|
|
|
case 'boolean':
|
|
return v ? 'true' : 'false';
|
|
|
|
case 'number':
|
|
return isFinite(v) ? v : '';
|
|
|
|
default:
|
|
return '';
|
|
}
|
|
};
|
|
|
|
module.exports = function(obj, sep, eq, name) {
|
|
sep = sep || '&';
|
|
eq = eq || '=';
|
|
if (obj === null) {
|
|
obj = undefined;
|
|
}
|
|
|
|
if (typeof obj === 'object') {
|
|
return map(objectKeys(obj), function(k) {
|
|
var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
|
|
if (isArray(obj[k])) {
|
|
return obj[k].map(function(v) {
|
|
return ks + encodeURIComponent(stringifyPrimitive(v));
|
|
}).join(sep);
|
|
} else {
|
|
return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
|
|
}
|
|
}).join(sep);
|
|
|
|
}
|
|
|
|
if (!name) return '';
|
|
return encodeURIComponent(stringifyPrimitive(name)) + eq +
|
|
encodeURIComponent(stringifyPrimitive(obj));
|
|
};
|
|
|
|
var isArray = Array.isArray || function (xs) {
|
|
return Object.prototype.toString.call(xs) === '[object Array]';
|
|
};
|
|
|
|
function map (xs, f) {
|
|
if (xs.map) return xs.map(f);
|
|
var res = [];
|
|
for (var i = 0; i < xs.length; i++) {
|
|
res.push(f(xs[i], i));
|
|
}
|
|
return res;
|
|
}
|
|
|
|
var objectKeys = Object.keys || function (obj) {
|
|
var res = [];
|
|
for (var key in obj) {
|
|
if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key);
|
|
}
|
|
return res;
|
|
};
|
|
|
|
},{}],148:[function(_dereq_,module,exports){
|
|
'use strict';
|
|
|
|
exports.decode = exports.parse = _dereq_('./decode');
|
|
exports.encode = exports.stringify = _dereq_('./encode');
|
|
|
|
},{"./decode":146,"./encode":147}],149:[function(_dereq_,module,exports){
|
|
// 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.
|
|
|
|
// a duplex stream is just a stream that is both readable and writable.
|
|
// Since JS doesn't have multiple prototypal inheritance, this class
|
|
// prototypally inherits from Readable, and then parasitically from
|
|
// Writable.
|
|
|
|
module.exports = Duplex;
|
|
var inherits = _dereq_('inherits');
|
|
var setImmediate = _dereq_('process/browser.js').nextTick;
|
|
var Readable = _dereq_('./readable.js');
|
|
var Writable = _dereq_('./writable.js');
|
|
|
|
inherits(Duplex, Readable);
|
|
|
|
Duplex.prototype.write = Writable.prototype.write;
|
|
Duplex.prototype.end = Writable.prototype.end;
|
|
Duplex.prototype._write = Writable.prototype._write;
|
|
|
|
function Duplex(options) {
|
|
if (!(this instanceof Duplex))
|
|
return new Duplex(options);
|
|
|
|
Readable.call(this, options);
|
|
Writable.call(this, options);
|
|
|
|
if (options && options.readable === false)
|
|
this.readable = false;
|
|
|
|
if (options && options.writable === false)
|
|
this.writable = false;
|
|
|
|
this.allowHalfOpen = true;
|
|
if (options && options.allowHalfOpen === false)
|
|
this.allowHalfOpen = false;
|
|
|
|
this.once('end', onend);
|
|
}
|
|
|
|
// the no-half-open enforcer
|
|
function onend() {
|
|
// if we allow half-open state, or if the writable side ended,
|
|
// then we're ok.
|
|
if (this.allowHalfOpen || this._writableState.ended)
|
|
return;
|
|
|
|
// no more data can be written.
|
|
// But allow more writes to happen in this tick.
|
|
var self = this;
|
|
setImmediate(function () {
|
|
self.end();
|
|
});
|
|
}
|
|
|
|
},{"./readable.js":153,"./writable.js":155,"inherits":143,"process/browser.js":151}],150:[function(_dereq_,module,exports){
|
|
// 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.
|
|
|
|
module.exports = Stream;
|
|
|
|
var EE = _dereq_('events').EventEmitter;
|
|
var inherits = _dereq_('inherits');
|
|
|
|
inherits(Stream, EE);
|
|
Stream.Readable = _dereq_('./readable.js');
|
|
Stream.Writable = _dereq_('./writable.js');
|
|
Stream.Duplex = _dereq_('./duplex.js');
|
|
Stream.Transform = _dereq_('./transform.js');
|
|
Stream.PassThrough = _dereq_('./passthrough.js');
|
|
|
|
// Backwards-compat with node 0.4.x
|
|
Stream.Stream = Stream;
|
|
|
|
|
|
|
|
// old-style streams. Note that the pipe method (the only relevant
|
|
// part of this class) is overridden in the Readable class.
|
|
|
|
function Stream() {
|
|
EE.call(this);
|
|
}
|
|
|
|
Stream.prototype.pipe = function(dest, options) {
|
|
var source = this;
|
|
|
|
function ondata(chunk) {
|
|
if (dest.writable) {
|
|
if (false === dest.write(chunk) && source.pause) {
|
|
source.pause();
|
|
}
|
|
}
|
|
}
|
|
|
|
source.on('data', ondata);
|
|
|
|
function ondrain() {
|
|
if (source.readable && source.resume) {
|
|
source.resume();
|
|
}
|
|
}
|
|
|
|
dest.on('drain', ondrain);
|
|
|
|
// If the 'end' option is not supplied, dest.end() will be called when
|
|
// source gets the 'end' or 'close' events. Only dest.end() once.
|
|
if (!dest._isStdio && (!options || options.end !== false)) {
|
|
source.on('end', onend);
|
|
source.on('close', onclose);
|
|
}
|
|
|
|
var didOnEnd = false;
|
|
function onend() {
|
|
if (didOnEnd) return;
|
|
didOnEnd = true;
|
|
|
|
dest.end();
|
|
}
|
|
|
|
|
|
function onclose() {
|
|
if (didOnEnd) return;
|
|
didOnEnd = true;
|
|
|
|
if (typeof dest.destroy === 'function') dest.destroy();
|
|
}
|
|
|
|
// don't leave dangling pipes when there are errors.
|
|
function onerror(er) {
|
|
cleanup();
|
|
if (EE.listenerCount(this, 'error') === 0) {
|
|
throw er; // Unhandled stream error in pipe.
|
|
}
|
|
}
|
|
|
|
source.on('error', onerror);
|
|
dest.on('error', onerror);
|
|
|
|
// remove all the event listeners that were added.
|
|
function cleanup() {
|
|
source.removeListener('data', ondata);
|
|
dest.removeListener('drain', ondrain);
|
|
|
|
source.removeListener('end', onend);
|
|
source.removeListener('close', onclose);
|
|
|
|
source.removeListener('error', onerror);
|
|
dest.removeListener('error', onerror);
|
|
|
|
source.removeListener('end', cleanup);
|
|
source.removeListener('close', cleanup);
|
|
|
|
dest.removeListener('close', cleanup);
|
|
}
|
|
|
|
source.on('end', cleanup);
|
|
source.on('close', cleanup);
|
|
|
|
dest.on('close', cleanup);
|
|
|
|
dest.emit('pipe', source);
|
|
|
|
// Allow for unix-like usage: A.pipe(B).pipe(C)
|
|
return dest;
|
|
};
|
|
|
|
},{"./duplex.js":149,"./passthrough.js":152,"./readable.js":153,"./transform.js":154,"./writable.js":155,"events":137,"inherits":143}],151:[function(_dereq_,module,exports){
|
|
// shim for using process in browser
|
|
|
|
var process = module.exports = {};
|
|
|
|
process.nextTick = (function () {
|
|
var canSetImmediate = typeof window !== 'undefined'
|
|
&& window.setImmediate;
|
|
var canPost = typeof window !== 'undefined'
|
|
&& window.postMessage && window.addEventListener
|
|
;
|
|
|
|
if (canSetImmediate) {
|
|
return function (f) { return window.setImmediate(f) };
|
|
}
|
|
|
|
if (canPost) {
|
|
var queue = [];
|
|
window.addEventListener('message', function (ev) {
|
|
var source = ev.source;
|
|
if ((source === window || source === null) && ev.data === 'process-tick') {
|
|
ev.stopPropagation();
|
|
if (queue.length > 0) {
|
|
var fn = queue.shift();
|
|
fn();
|
|
}
|
|
}
|
|
}, true);
|
|
|
|
return function nextTick(fn) {
|
|
queue.push(fn);
|
|
window.postMessage('process-tick', '*');
|
|
};
|
|
}
|
|
|
|
return function nextTick(fn) {
|
|
setTimeout(fn, 0);
|
|
};
|
|
})();
|
|
|
|
process.title = 'browser';
|
|
process.browser = true;
|
|
process.env = {};
|
|
process.argv = [];
|
|
|
|
process.binding = function (name) {
|
|
throw new Error('process.binding is not supported');
|
|
}
|
|
|
|
// TODO(shtylman)
|
|
process.cwd = function () { return '/' };
|
|
process.chdir = function (dir) {
|
|
throw new Error('process.chdir is not supported');
|
|
};
|
|
|
|
},{}],152:[function(_dereq_,module,exports){
|
|
// 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.
|
|
|
|
// a passthrough stream.
|
|
// basically just the most minimal sort of Transform stream.
|
|
// Every written chunk gets output as-is.
|
|
|
|
module.exports = PassThrough;
|
|
|
|
var Transform = _dereq_('./transform.js');
|
|
var inherits = _dereq_('inherits');
|
|
inherits(PassThrough, Transform);
|
|
|
|
function PassThrough(options) {
|
|
if (!(this instanceof PassThrough))
|
|
return new PassThrough(options);
|
|
|
|
Transform.call(this, options);
|
|
}
|
|
|
|
PassThrough.prototype._transform = function(chunk, encoding, cb) {
|
|
cb(null, chunk);
|
|
};
|
|
|
|
},{"./transform.js":154,"inherits":143}],153:[function(_dereq_,module,exports){
|
|
(function (process){
|
|
// 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.
|
|
|
|
module.exports = Readable;
|
|
Readable.ReadableState = ReadableState;
|
|
|
|
var EE = _dereq_('events').EventEmitter;
|
|
var Stream = _dereq_('./index.js');
|
|
var Buffer = _dereq_('buffer').Buffer;
|
|
var setImmediate = _dereq_('process/browser.js').nextTick;
|
|
var StringDecoder;
|
|
|
|
var inherits = _dereq_('inherits');
|
|
inherits(Readable, Stream);
|
|
|
|
function ReadableState(options, stream) {
|
|
options = options || {};
|
|
|
|
// the point at which it stops calling _read() to fill the buffer
|
|
// Note: 0 is a valid value, means "don't call _read preemptively ever"
|
|
var hwm = options.highWaterMark;
|
|
this.highWaterMark = (hwm || hwm === 0) ? hwm : 16 * 1024;
|
|
|
|
// cast to ints.
|
|
this.highWaterMark = ~~this.highWaterMark;
|
|
|
|
this.buffer = [];
|
|
this.length = 0;
|
|
this.pipes = null;
|
|
this.pipesCount = 0;
|
|
this.flowing = false;
|
|
this.ended = false;
|
|
this.endEmitted = false;
|
|
this.reading = false;
|
|
|
|
// In streams that never have any data, and do push(null) right away,
|
|
// the consumer can miss the 'end' event if they do some I/O before
|
|
// consuming the stream. So, we don't emit('end') until some reading
|
|
// happens.
|
|
this.calledRead = false;
|
|
|
|
// a flag to be able to tell if the onwrite cb is called immediately,
|
|
// or on a later tick. We set this to true at first, becuase any
|
|
// actions that shouldn't happen until "later" should generally also
|
|
// not happen before the first write call.
|
|
this.sync = true;
|
|
|
|
// whenever we return null, then we set a flag to say
|
|
// that we're awaiting a 'readable' event emission.
|
|
this.needReadable = false;
|
|
this.emittedReadable = false;
|
|
this.readableListening = false;
|
|
|
|
|
|
// object stream flag. Used to make read(n) ignore n and to
|
|
// make all the buffer merging and length checks go away
|
|
this.objectMode = !!options.objectMode;
|
|
|
|
// Crypto is kind of old and crusty. Historically, its default string
|
|
// encoding is 'binary' so we have to make this configurable.
|
|
// Everything else in the universe uses 'utf8', though.
|
|
this.defaultEncoding = options.defaultEncoding || 'utf8';
|
|
|
|
// when piping, we only care about 'readable' events that happen
|
|
// after read()ing all the bytes and not getting any pushback.
|
|
this.ranOut = false;
|
|
|
|
// the number of writers that are awaiting a drain event in .pipe()s
|
|
this.awaitDrain = 0;
|
|
|
|
// if true, a maybeReadMore has been scheduled
|
|
this.readingMore = false;
|
|
|
|
this.decoder = null;
|
|
this.encoding = null;
|
|
if (options.encoding) {
|
|
if (!StringDecoder)
|
|
StringDecoder = _dereq_('string_decoder').StringDecoder;
|
|
this.decoder = new StringDecoder(options.encoding);
|
|
this.encoding = options.encoding;
|
|
}
|
|
}
|
|
|
|
function Readable(options) {
|
|
if (!(this instanceof Readable))
|
|
return new Readable(options);
|
|
|
|
this._readableState = new ReadableState(options, this);
|
|
|
|
// legacy
|
|
this.readable = true;
|
|
|
|
Stream.call(this);
|
|
}
|
|
|
|
// Manually shove something into the read() buffer.
|
|
// This returns true if the highWaterMark has not been hit yet,
|
|
// similar to how Writable.write() returns true if you should
|
|
// write() some more.
|
|
Readable.prototype.push = function(chunk, encoding) {
|
|
var state = this._readableState;
|
|
|
|
if (typeof chunk === 'string' && !state.objectMode) {
|
|
encoding = encoding || state.defaultEncoding;
|
|
if (encoding !== state.encoding) {
|
|
chunk = new Buffer(chunk, encoding);
|
|
encoding = '';
|
|
}
|
|
}
|
|
|
|
return readableAddChunk(this, state, chunk, encoding, false);
|
|
};
|
|
|
|
// Unshift should *always* be something directly out of read()
|
|
Readable.prototype.unshift = function(chunk) {
|
|
var state = this._readableState;
|
|
return readableAddChunk(this, state, chunk, '', true);
|
|
};
|
|
|
|
function readableAddChunk(stream, state, chunk, encoding, addToFront) {
|
|
var er = chunkInvalid(state, chunk);
|
|
if (er) {
|
|
stream.emit('error', er);
|
|
} else if (chunk === null || chunk === undefined) {
|
|
state.reading = false;
|
|
if (!state.ended)
|
|
onEofChunk(stream, state);
|
|
} else if (state.objectMode || chunk && chunk.length > 0) {
|
|
if (state.ended && !addToFront) {
|
|
var e = new Error('stream.push() after EOF');
|
|
stream.emit('error', e);
|
|
} else if (state.endEmitted && addToFront) {
|
|
var e = new Error('stream.unshift() after end event');
|
|
stream.emit('error', e);
|
|
} else {
|
|
if (state.decoder && !addToFront && !encoding)
|
|
chunk = state.decoder.write(chunk);
|
|
|
|
// update the buffer info.
|
|
state.length += state.objectMode ? 1 : chunk.length;
|
|
if (addToFront) {
|
|
state.buffer.unshift(chunk);
|
|
} else {
|
|
state.reading = false;
|
|
state.buffer.push(chunk);
|
|
}
|
|
|
|
if (state.needReadable)
|
|
emitReadable(stream);
|
|
|
|
maybeReadMore(stream, state);
|
|
}
|
|
} else if (!addToFront) {
|
|
state.reading = false;
|
|
}
|
|
|
|
return needMoreData(state);
|
|
}
|
|
|
|
|
|
|
|
// if it's past the high water mark, we can push in some more.
|
|
// Also, if we have no data yet, we can stand some
|
|
// more bytes. This is to work around cases where hwm=0,
|
|
// such as the repl. Also, if the push() triggered a
|
|
// readable event, and the user called read(largeNumber) such that
|
|
// needReadable was set, then we ought to push more, so that another
|
|
// 'readable' event will be triggered.
|
|
function needMoreData(state) {
|
|
return !state.ended &&
|
|
(state.needReadable ||
|
|
state.length < state.highWaterMark ||
|
|
state.length === 0);
|
|
}
|
|
|
|
// backwards compatibility.
|
|
Readable.prototype.setEncoding = function(enc) {
|
|
if (!StringDecoder)
|
|
StringDecoder = _dereq_('string_decoder').StringDecoder;
|
|
this._readableState.decoder = new StringDecoder(enc);
|
|
this._readableState.encoding = enc;
|
|
};
|
|
|
|
// Don't raise the hwm > 128MB
|
|
var MAX_HWM = 0x800000;
|
|
function roundUpToNextPowerOf2(n) {
|
|
if (n >= MAX_HWM) {
|
|
n = MAX_HWM;
|
|
} else {
|
|
// Get the next highest power of 2
|
|
n--;
|
|
for (var p = 1; p < 32; p <<= 1) n |= n >> p;
|
|
n++;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
function howMuchToRead(n, state) {
|
|
if (state.length === 0 && state.ended)
|
|
return 0;
|
|
|
|
if (state.objectMode)
|
|
return n === 0 ? 0 : 1;
|
|
|
|
if (isNaN(n) || n === null) {
|
|
// only flow one buffer at a time
|
|
if (state.flowing && state.buffer.length)
|
|
return state.buffer[0].length;
|
|
else
|
|
return state.length;
|
|
}
|
|
|
|
if (n <= 0)
|
|
return 0;
|
|
|
|
// If we're asking for more than the target buffer level,
|
|
// then raise the water mark. Bump up to the next highest
|
|
// power of 2, to prevent increasing it excessively in tiny
|
|
// amounts.
|
|
if (n > state.highWaterMark)
|
|
state.highWaterMark = roundUpToNextPowerOf2(n);
|
|
|
|
// don't have that much. return null, unless we've ended.
|
|
if (n > state.length) {
|
|
if (!state.ended) {
|
|
state.needReadable = true;
|
|
return 0;
|
|
} else
|
|
return state.length;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
// you can override either this method, or the async _read(n) below.
|
|
Readable.prototype.read = function(n) {
|
|
var state = this._readableState;
|
|
state.calledRead = true;
|
|
var nOrig = n;
|
|
|
|
if (typeof n !== 'number' || n > 0)
|
|
state.emittedReadable = false;
|
|
|
|
// if we're doing read(0) to trigger a readable event, but we
|
|
// already have a bunch of data in the buffer, then just trigger
|
|
// the 'readable' event and move on.
|
|
if (n === 0 &&
|
|
state.needReadable &&
|
|
(state.length >= state.highWaterMark || state.ended)) {
|
|
emitReadable(this);
|
|
return null;
|
|
}
|
|
|
|
n = howMuchToRead(n, state);
|
|
|
|
// if we've ended, and we're now clear, then finish it up.
|
|
if (n === 0 && state.ended) {
|
|
if (state.length === 0)
|
|
endReadable(this);
|
|
return null;
|
|
}
|
|
|
|
// All the actual chunk generation logic needs to be
|
|
// *below* the call to _read. The reason is that in certain
|
|
// synthetic stream cases, such as passthrough streams, _read
|
|
// may be a completely synchronous operation which may change
|
|
// the state of the read buffer, providing enough data when
|
|
// before there was *not* enough.
|
|
//
|
|
// So, the steps are:
|
|
// 1. Figure out what the state of things will be after we do
|
|
// a read from the buffer.
|
|
//
|
|
// 2. If that resulting state will trigger a _read, then call _read.
|
|
// Note that this may be asynchronous, or synchronous. Yes, it is
|
|
// deeply ugly to write APIs this way, but that still doesn't mean
|
|
// that the Readable class should behave improperly, as streams are
|
|
// designed to be sync/async agnostic.
|
|
// Take note if the _read call is sync or async (ie, if the read call
|
|
// has returned yet), so that we know whether or not it's safe to emit
|
|
// 'readable' etc.
|
|
//
|
|
// 3. Actually pull the requested chunks out of the buffer and return.
|
|
|
|
// if we need a readable event, then we need to do some reading.
|
|
var doRead = state.needReadable;
|
|
|
|
// if we currently have less than the highWaterMark, then also read some
|
|
if (state.length - n <= state.highWaterMark)
|
|
doRead = true;
|
|
|
|
// however, if we've ended, then there's no point, and if we're already
|
|
// reading, then it's unnecessary.
|
|
if (state.ended || state.reading)
|
|
doRead = false;
|
|
|
|
if (doRead) {
|
|
state.reading = true;
|
|
state.sync = true;
|
|
// if the length is currently zero, then we *need* a readable event.
|
|
if (state.length === 0)
|
|
state.needReadable = true;
|
|
// call internal read method
|
|
this._read(state.highWaterMark);
|
|
state.sync = false;
|
|
}
|
|
|
|
// If _read called its callback synchronously, then `reading`
|
|
// will be false, and we need to re-evaluate how much data we
|
|
// can return to the user.
|
|
if (doRead && !state.reading)
|
|
n = howMuchToRead(nOrig, state);
|
|
|
|
var ret;
|
|
if (n > 0)
|
|
ret = fromList(n, state);
|
|
else
|
|
ret = null;
|
|
|
|
if (ret === null) {
|
|
state.needReadable = true;
|
|
n = 0;
|
|
}
|
|
|
|
state.length -= n;
|
|
|
|
// If we have nothing in the buffer, then we want to know
|
|
// as soon as we *do* get something into the buffer.
|
|
if (state.length === 0 && !state.ended)
|
|
state.needReadable = true;
|
|
|
|
// If we happened to read() exactly the remaining amount in the
|
|
// buffer, and the EOF has been seen at this point, then make sure
|
|
// that we emit 'end' on the very next tick.
|
|
if (state.ended && !state.endEmitted && state.length === 0)
|
|
endReadable(this);
|
|
|
|
return ret;
|
|
};
|
|
|
|
function chunkInvalid(state, chunk) {
|
|
var er = null;
|
|
if (!Buffer.isBuffer(chunk) &&
|
|
'string' !== typeof chunk &&
|
|
chunk !== null &&
|
|
chunk !== undefined &&
|
|
!state.objectMode &&
|
|
!er) {
|
|
er = new TypeError('Invalid non-string/buffer chunk');
|
|
}
|
|
return er;
|
|
}
|
|
|
|
|
|
function onEofChunk(stream, state) {
|
|
if (state.decoder && !state.ended) {
|
|
var chunk = state.decoder.end();
|
|
if (chunk && chunk.length) {
|
|
state.buffer.push(chunk);
|
|
state.length += state.objectMode ? 1 : chunk.length;
|
|
}
|
|
}
|
|
state.ended = true;
|
|
|
|
// if we've ended and we have some data left, then emit
|
|
// 'readable' now to make sure it gets picked up.
|
|
if (state.length > 0)
|
|
emitReadable(stream);
|
|
else
|
|
endReadable(stream);
|
|
}
|
|
|
|
// Don't emit readable right away in sync mode, because this can trigger
|
|
// another read() call => stack overflow. This way, it might trigger
|
|
// a nextTick recursion warning, but that's not so bad.
|
|
function emitReadable(stream) {
|
|
var state = stream._readableState;
|
|
state.needReadable = false;
|
|
if (state.emittedReadable)
|
|
return;
|
|
|
|
state.emittedReadable = true;
|
|
if (state.sync)
|
|
setImmediate(function() {
|
|
emitReadable_(stream);
|
|
});
|
|
else
|
|
emitReadable_(stream);
|
|
}
|
|
|
|
function emitReadable_(stream) {
|
|
stream.emit('readable');
|
|
}
|
|
|
|
|
|
// at this point, the user has presumably seen the 'readable' event,
|
|
// and called read() to consume some data. that may have triggered
|
|
// in turn another _read(n) call, in which case reading = true if
|
|
// it's in progress.
|
|
// However, if we're not ended, or reading, and the length < hwm,
|
|
// then go ahead and try to read some more preemptively.
|
|
function maybeReadMore(stream, state) {
|
|
if (!state.readingMore) {
|
|
state.readingMore = true;
|
|
setImmediate(function() {
|
|
maybeReadMore_(stream, state);
|
|
});
|
|
}
|
|
}
|
|
|
|
function maybeReadMore_(stream, state) {
|
|
var len = state.length;
|
|
while (!state.reading && !state.flowing && !state.ended &&
|
|
state.length < state.highWaterMark) {
|
|
stream.read(0);
|
|
if (len === state.length)
|
|
// didn't get any data, stop spinning.
|
|
break;
|
|
else
|
|
len = state.length;
|
|
}
|
|
state.readingMore = false;
|
|
}
|
|
|
|
// abstract method. to be overridden in specific implementation classes.
|
|
// call cb(er, data) where data is <= n in length.
|
|
// for virtual (non-string, non-buffer) streams, "length" is somewhat
|
|
// arbitrary, and perhaps not very meaningful.
|
|
Readable.prototype._read = function(n) {
|
|
this.emit('error', new Error('not implemented'));
|
|
};
|
|
|
|
Readable.prototype.pipe = function(dest, pipeOpts) {
|
|
var src = this;
|
|
var state = this._readableState;
|
|
|
|
switch (state.pipesCount) {
|
|
case 0:
|
|
state.pipes = dest;
|
|
break;
|
|
case 1:
|
|
state.pipes = [state.pipes, dest];
|
|
break;
|
|
default:
|
|
state.pipes.push(dest);
|
|
break;
|
|
}
|
|
state.pipesCount += 1;
|
|
|
|
var doEnd = (!pipeOpts || pipeOpts.end !== false) &&
|
|
dest !== process.stdout &&
|
|
dest !== process.stderr;
|
|
|
|
var endFn = doEnd ? onend : cleanup;
|
|
if (state.endEmitted)
|
|
setImmediate(endFn);
|
|
else
|
|
src.once('end', endFn);
|
|
|
|
dest.on('unpipe', onunpipe);
|
|
function onunpipe(readable) {
|
|
if (readable !== src) return;
|
|
cleanup();
|
|
}
|
|
|
|
function onend() {
|
|
dest.end();
|
|
}
|
|
|
|
// when the dest drains, it reduces the awaitDrain counter
|
|
// on the source. This would be more elegant with a .once()
|
|
// handler in flow(), but adding and removing repeatedly is
|
|
// too slow.
|
|
var ondrain = pipeOnDrain(src);
|
|
dest.on('drain', ondrain);
|
|
|
|
function cleanup() {
|
|
// cleanup event handlers once the pipe is broken
|
|
dest.removeListener('close', onclose);
|
|
dest.removeListener('finish', onfinish);
|
|
dest.removeListener('drain', ondrain);
|
|
dest.removeListener('error', onerror);
|
|
dest.removeListener('unpipe', onunpipe);
|
|
src.removeListener('end', onend);
|
|
src.removeListener('end', cleanup);
|
|
|
|
// if the reader is waiting for a drain event from this
|
|
// specific writer, then it would cause it to never start
|
|
// flowing again.
|
|
// So, if this is awaiting a drain, then we just call it now.
|
|
// If we don't know, then assume that we are waiting for one.
|
|
if (!dest._writableState || dest._writableState.needDrain)
|
|
ondrain();
|
|
}
|
|
|
|
// if the dest has an error, then stop piping into it.
|
|
// however, don't suppress the throwing behavior for this.
|
|
// check for listeners before emit removes one-time listeners.
|
|
var errListeners = EE.listenerCount(dest, 'error');
|
|
function onerror(er) {
|
|
unpipe();
|
|
if (errListeners === 0 && EE.listenerCount(dest, 'error') === 0)
|
|
dest.emit('error', er);
|
|
}
|
|
dest.once('error', onerror);
|
|
|
|
// Both close and finish should trigger unpipe, but only once.
|
|
function onclose() {
|
|
dest.removeListener('finish', onfinish);
|
|
unpipe();
|
|
}
|
|
dest.once('close', onclose);
|
|
function onfinish() {
|
|
dest.removeListener('close', onclose);
|
|
unpipe();
|
|
}
|
|
dest.once('finish', onfinish);
|
|
|
|
function unpipe() {
|
|
src.unpipe(dest);
|
|
}
|
|
|
|
// tell the dest that it's being piped to
|
|
dest.emit('pipe', src);
|
|
|
|
// start the flow if it hasn't been started already.
|
|
if (!state.flowing) {
|
|
// the handler that waits for readable events after all
|
|
// the data gets sucked out in flow.
|
|
// This would be easier to follow with a .once() handler
|
|
// in flow(), but that is too slow.
|
|
this.on('readable', pipeOnReadable);
|
|
|
|
state.flowing = true;
|
|
setImmediate(function() {
|
|
flow(src);
|
|
});
|
|
}
|
|
|
|
return dest;
|
|
};
|
|
|
|
function pipeOnDrain(src) {
|
|
return function() {
|
|
var dest = this;
|
|
var state = src._readableState;
|
|
state.awaitDrain--;
|
|
if (state.awaitDrain === 0)
|
|
flow(src);
|
|
};
|
|
}
|
|
|
|
function flow(src) {
|
|
var state = src._readableState;
|
|
var chunk;
|
|
state.awaitDrain = 0;
|
|
|
|
function write(dest, i, list) {
|
|
var written = dest.write(chunk);
|
|
if (false === written) {
|
|
state.awaitDrain++;
|
|
}
|
|
}
|
|
|
|
while (state.pipesCount && null !== (chunk = src.read())) {
|
|
|
|
if (state.pipesCount === 1)
|
|
write(state.pipes, 0, null);
|
|
else
|
|
forEach(state.pipes, write);
|
|
|
|
src.emit('data', chunk);
|
|
|
|
// if anyone needs a drain, then we have to wait for that.
|
|
if (state.awaitDrain > 0)
|
|
return;
|
|
}
|
|
|
|
// if every destination was unpiped, either before entering this
|
|
// function, or in the while loop, then stop flowing.
|
|
//
|
|
// NB: This is a pretty rare edge case.
|
|
if (state.pipesCount === 0) {
|
|
state.flowing = false;
|
|
|
|
// if there were data event listeners added, then switch to old mode.
|
|
if (EE.listenerCount(src, 'data') > 0)
|
|
emitDataEvents(src);
|
|
return;
|
|
}
|
|
|
|
// at this point, no one needed a drain, so we just ran out of data
|
|
// on the next readable event, start it over again.
|
|
state.ranOut = true;
|
|
}
|
|
|
|
function pipeOnReadable() {
|
|
if (this._readableState.ranOut) {
|
|
this._readableState.ranOut = false;
|
|
flow(this);
|
|
}
|
|
}
|
|
|
|
|
|
Readable.prototype.unpipe = function(dest) {
|
|
var state = this._readableState;
|
|
|
|
// if we're not piping anywhere, then do nothing.
|
|
if (state.pipesCount === 0)
|
|
return this;
|
|
|
|
// just one destination. most common case.
|
|
if (state.pipesCount === 1) {
|
|
// passed in one, but it's not the right one.
|
|
if (dest && dest !== state.pipes)
|
|
return this;
|
|
|
|
if (!dest)
|
|
dest = state.pipes;
|
|
|
|
// got a match.
|
|
state.pipes = null;
|
|
state.pipesCount = 0;
|
|
this.removeListener('readable', pipeOnReadable);
|
|
state.flowing = false;
|
|
if (dest)
|
|
dest.emit('unpipe', this);
|
|
return this;
|
|
}
|
|
|
|
// slow case. multiple pipe destinations.
|
|
|
|
if (!dest) {
|
|
// remove all.
|
|
var dests = state.pipes;
|
|
var len = state.pipesCount;
|
|
state.pipes = null;
|
|
state.pipesCount = 0;
|
|
this.removeListener('readable', pipeOnReadable);
|
|
state.flowing = false;
|
|
|
|
for (var i = 0; i < len; i++)
|
|
dests[i].emit('unpipe', this);
|
|
return this;
|
|
}
|
|
|
|
// try to find the right one.
|
|
var i = indexOf(state.pipes, dest);
|
|
if (i === -1)
|
|
return this;
|
|
|
|
state.pipes.splice(i, 1);
|
|
state.pipesCount -= 1;
|
|
if (state.pipesCount === 1)
|
|
state.pipes = state.pipes[0];
|
|
|
|
dest.emit('unpipe', this);
|
|
|
|
return this;
|
|
};
|
|
|
|
// set up data events if they are asked for
|
|
// Ensure readable listeners eventually get something
|
|
Readable.prototype.on = function(ev, fn) {
|
|
var res = Stream.prototype.on.call(this, ev, fn);
|
|
|
|
if (ev === 'data' && !this._readableState.flowing)
|
|
emitDataEvents(this);
|
|
|
|
if (ev === 'readable' && this.readable) {
|
|
var state = this._readableState;
|
|
if (!state.readableListening) {
|
|
state.readableListening = true;
|
|
state.emittedReadable = false;
|
|
state.needReadable = true;
|
|
if (!state.reading) {
|
|
this.read(0);
|
|
} else if (state.length) {
|
|
emitReadable(this, state);
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
};
|
|
Readable.prototype.addListener = Readable.prototype.on;
|
|
|
|
// pause() and resume() are remnants of the legacy readable stream API
|
|
// If the user uses them, then switch into old mode.
|
|
Readable.prototype.resume = function() {
|
|
emitDataEvents(this);
|
|
this.read(0);
|
|
this.emit('resume');
|
|
};
|
|
|
|
Readable.prototype.pause = function() {
|
|
emitDataEvents(this, true);
|
|
this.emit('pause');
|
|
};
|
|
|
|
function emitDataEvents(stream, startPaused) {
|
|
var state = stream._readableState;
|
|
|
|
if (state.flowing) {
|
|
// https://github.com/isaacs/readable-stream/issues/16
|
|
throw new Error('Cannot switch to old mode now.');
|
|
}
|
|
|
|
var paused = startPaused || false;
|
|
var readable = false;
|
|
|
|
// convert to an old-style stream.
|
|
stream.readable = true;
|
|
stream.pipe = Stream.prototype.pipe;
|
|
stream.on = stream.addListener = Stream.prototype.on;
|
|
|
|
stream.on('readable', function() {
|
|
readable = true;
|
|
|
|
var c;
|
|
while (!paused && (null !== (c = stream.read())))
|
|
stream.emit('data', c);
|
|
|
|
if (c === null) {
|
|
readable = false;
|
|
stream._readableState.needReadable = true;
|
|
}
|
|
});
|
|
|
|
stream.pause = function() {
|
|
paused = true;
|
|
this.emit('pause');
|
|
};
|
|
|
|
stream.resume = function() {
|
|
paused = false;
|
|
if (readable)
|
|
setImmediate(function() {
|
|
stream.emit('readable');
|
|
});
|
|
else
|
|
this.read(0);
|
|
this.emit('resume');
|
|
};
|
|
|
|
// now make it start, just in case it hadn't already.
|
|
stream.emit('readable');
|
|
}
|
|
|
|
// wrap an old-style stream as the async data source.
|
|
// This is *not* part of the readable stream interface.
|
|
// It is an ugly unfortunate mess of history.
|
|
Readable.prototype.wrap = function(stream) {
|
|
var state = this._readableState;
|
|
var paused = false;
|
|
|
|
var self = this;
|
|
stream.on('end', function() {
|
|
if (state.decoder && !state.ended) {
|
|
var chunk = state.decoder.end();
|
|
if (chunk && chunk.length)
|
|
self.push(chunk);
|
|
}
|
|
|
|
self.push(null);
|
|
});
|
|
|
|
stream.on('data', function(chunk) {
|
|
if (state.decoder)
|
|
chunk = state.decoder.write(chunk);
|
|
if (!chunk || !state.objectMode && !chunk.length)
|
|
return;
|
|
|
|
var ret = self.push(chunk);
|
|
if (!ret) {
|
|
paused = true;
|
|
stream.pause();
|
|
}
|
|
});
|
|
|
|
// proxy all the other methods.
|
|
// important when wrapping filters and duplexes.
|
|
for (var i in stream) {
|
|
if (typeof stream[i] === 'function' &&
|
|
typeof this[i] === 'undefined') {
|
|
this[i] = function(method) { return function() {
|
|
return stream[method].apply(stream, arguments);
|
|
}}(i);
|
|
}
|
|
}
|
|
|
|
// proxy certain important events.
|
|
var events = ['error', 'close', 'destroy', 'pause', 'resume'];
|
|
forEach(events, function(ev) {
|
|
stream.on(ev, function (x) {
|
|
return self.emit.apply(self, ev, x);
|
|
});
|
|
});
|
|
|
|
// when we try to consume some more bytes, simply unpause the
|
|
// underlying stream.
|
|
self._read = function(n) {
|
|
if (paused) {
|
|
paused = false;
|
|
stream.resume();
|
|
}
|
|
};
|
|
|
|
return self;
|
|
};
|
|
|
|
|
|
|
|
// exposed for testing purposes only.
|
|
Readable._fromList = fromList;
|
|
|
|
// Pluck off n bytes from an array of buffers.
|
|
// Length is the combined lengths of all the buffers in the list.
|
|
function fromList(n, state) {
|
|
var list = state.buffer;
|
|
var length = state.length;
|
|
var stringMode = !!state.decoder;
|
|
var objectMode = !!state.objectMode;
|
|
var ret;
|
|
|
|
// nothing in the list, definitely empty.
|
|
if (list.length === 0)
|
|
return null;
|
|
|
|
if (length === 0)
|
|
ret = null;
|
|
else if (objectMode)
|
|
ret = list.shift();
|
|
else if (!n || n >= length) {
|
|
// read it all, truncate the array.
|
|
if (stringMode)
|
|
ret = list.join('');
|
|
else
|
|
ret = Buffer.concat(list, length);
|
|
list.length = 0;
|
|
} else {
|
|
// read just some of it.
|
|
if (n < list[0].length) {
|
|
// just take a part of the first list item.
|
|
// slice is the same for buffers and strings.
|
|
var buf = list[0];
|
|
ret = buf.slice(0, n);
|
|
list[0] = buf.slice(n);
|
|
} else if (n === list[0].length) {
|
|
// first list is a perfect match
|
|
ret = list.shift();
|
|
} else {
|
|
// complex case.
|
|
// we have enough to cover it, but it spans past the first buffer.
|
|
if (stringMode)
|
|
ret = '';
|
|
else
|
|
ret = new Buffer(n);
|
|
|
|
var c = 0;
|
|
for (var i = 0, l = list.length; i < l && c < n; i++) {
|
|
var buf = list[0];
|
|
var cpy = Math.min(n - c, buf.length);
|
|
|
|
if (stringMode)
|
|
ret += buf.slice(0, cpy);
|
|
else
|
|
buf.copy(ret, c, 0, cpy);
|
|
|
|
if (cpy < buf.length)
|
|
list[0] = buf.slice(cpy);
|
|
else
|
|
list.shift();
|
|
|
|
c += cpy;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
function endReadable(stream) {
|
|
var state = stream._readableState;
|
|
|
|
// If we get here before consuming all the bytes, then that is a
|
|
// bug in node. Should never happen.
|
|
if (state.length > 0)
|
|
throw new Error('endReadable called on non-empty stream');
|
|
|
|
if (!state.endEmitted && state.calledRead) {
|
|
state.ended = true;
|
|
setImmediate(function() {
|
|
// Check that we didn't get one last unshift.
|
|
if (!state.endEmitted && state.length === 0) {
|
|
state.endEmitted = true;
|
|
stream.readable = false;
|
|
stream.emit('end');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function forEach (xs, f) {
|
|
for (var i = 0, l = xs.length; i < l; i++) {
|
|
f(xs[i], i);
|
|
}
|
|
}
|
|
|
|
function indexOf (xs, x) {
|
|
for (var i = 0, l = xs.length; i < l; i++) {
|
|
if (xs[i] === x) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
}).call(this,_dereq_("C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"))
|
|
},{"./index.js":150,"C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":144,"buffer":128,"events":137,"inherits":143,"process/browser.js":151,"string_decoder":156}],154:[function(_dereq_,module,exports){
|
|
// 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.
|
|
|
|
// a transform stream is a readable/writable stream where you do
|
|
// something with the data. Sometimes it's called a "filter",
|
|
// but that's not a great name for it, since that implies a thing where
|
|
// some bits pass through, and others are simply ignored. (That would
|
|
// be a valid example of a transform, of course.)
|
|
//
|
|
// While the output is causally related to the input, it's not a
|
|
// necessarily symmetric or synchronous transformation. For example,
|
|
// a zlib stream might take multiple plain-text writes(), and then
|
|
// emit a single compressed chunk some time in the future.
|
|
//
|
|
// Here's how this works:
|
|
//
|
|
// The Transform stream has all the aspects of the readable and writable
|
|
// stream classes. When you write(chunk), that calls _write(chunk,cb)
|
|
// internally, and returns false if there's a lot of pending writes
|
|
// buffered up. When you call read(), that calls _read(n) until
|
|
// there's enough pending readable data buffered up.
|
|
//
|
|
// In a transform stream, the written data is placed in a buffer. When
|
|
// _read(n) is called, it transforms the queued up data, calling the
|
|
// buffered _write cb's as it consumes chunks. If consuming a single
|
|
// written chunk would result in multiple output chunks, then the first
|
|
// outputted bit calls the readcb, and subsequent chunks just go into
|
|
// the read buffer, and will cause it to emit 'readable' if necessary.
|
|
//
|
|
// This way, back-pressure is actually determined by the reading side,
|
|
// since _read has to be called to start processing a new chunk. However,
|
|
// a pathological inflate type of transform can cause excessive buffering
|
|
// here. For example, imagine a stream where every byte of input is
|
|
// interpreted as an integer from 0-255, and then results in that many
|
|
// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in
|
|
// 1kb of data being output. In this case, you could write a very small
|
|
// amount of input, and end up with a very large amount of output. In
|
|
// such a pathological inflating mechanism, there'd be no way to tell
|
|
// the system to stop doing the transform. A single 4MB write could
|
|
// cause the system to run out of memory.
|
|
//
|
|
// However, even in such a pathological case, only a single written chunk
|
|
// would be consumed, and then the rest would wait (un-transformed) until
|
|
// the results of the previous transformed chunk were consumed.
|
|
|
|
module.exports = Transform;
|
|
|
|
var Duplex = _dereq_('./duplex.js');
|
|
var inherits = _dereq_('inherits');
|
|
inherits(Transform, Duplex);
|
|
|
|
|
|
function TransformState(options, stream) {
|
|
this.afterTransform = function(er, data) {
|
|
return afterTransform(stream, er, data);
|
|
};
|
|
|
|
this.needTransform = false;
|
|
this.transforming = false;
|
|
this.writecb = null;
|
|
this.writechunk = null;
|
|
}
|
|
|
|
function afterTransform(stream, er, data) {
|
|
var ts = stream._transformState;
|
|
ts.transforming = false;
|
|
|
|
var cb = ts.writecb;
|
|
|
|
if (!cb)
|
|
return stream.emit('error', new Error('no writecb in Transform class'));
|
|
|
|
ts.writechunk = null;
|
|
ts.writecb = null;
|
|
|
|
if (data !== null && data !== undefined)
|
|
stream.push(data);
|
|
|
|
if (cb)
|
|
cb(er);
|
|
|
|
var rs = stream._readableState;
|
|
rs.reading = false;
|
|
if (rs.needReadable || rs.length < rs.highWaterMark) {
|
|
stream._read(rs.highWaterMark);
|
|
}
|
|
}
|
|
|
|
|
|
function Transform(options) {
|
|
if (!(this instanceof Transform))
|
|
return new Transform(options);
|
|
|
|
Duplex.call(this, options);
|
|
|
|
var ts = this._transformState = new TransformState(options, this);
|
|
|
|
// when the writable side finishes, then flush out anything remaining.
|
|
var stream = this;
|
|
|
|
// start out asking for a readable event once data is transformed.
|
|
this._readableState.needReadable = true;
|
|
|
|
// we have implemented the _read method, and done the other things
|
|
// that Readable wants before the first _read call, so unset the
|
|
// sync guard flag.
|
|
this._readableState.sync = false;
|
|
|
|
this.once('finish', function() {
|
|
if ('function' === typeof this._flush)
|
|
this._flush(function(er) {
|
|
done(stream, er);
|
|
});
|
|
else
|
|
done(stream);
|
|
});
|
|
}
|
|
|
|
Transform.prototype.push = function(chunk, encoding) {
|
|
this._transformState.needTransform = false;
|
|
return Duplex.prototype.push.call(this, chunk, encoding);
|
|
};
|
|
|
|
// This is the part where you do stuff!
|
|
// override this function in implementation classes.
|
|
// 'chunk' is an input chunk.
|
|
//
|
|
// Call `push(newChunk)` to pass along transformed output
|
|
// to the readable side. You may call 'push' zero or more times.
|
|
//
|
|
// Call `cb(err)` when you are done with this chunk. If you pass
|
|
// an error, then that'll put the hurt on the whole operation. If you
|
|
// never call cb(), then you'll never get another chunk.
|
|
Transform.prototype._transform = function(chunk, encoding, cb) {
|
|
throw new Error('not implemented');
|
|
};
|
|
|
|
Transform.prototype._write = function(chunk, encoding, cb) {
|
|
var ts = this._transformState;
|
|
ts.writecb = cb;
|
|
ts.writechunk = chunk;
|
|
ts.writeencoding = encoding;
|
|
if (!ts.transforming) {
|
|
var rs = this._readableState;
|
|
if (ts.needTransform ||
|
|
rs.needReadable ||
|
|
rs.length < rs.highWaterMark)
|
|
this._read(rs.highWaterMark);
|
|
}
|
|
};
|
|
|
|
// Doesn't matter what the args are here.
|
|
// _transform does all the work.
|
|
// That we got here means that the readable side wants more data.
|
|
Transform.prototype._read = function(n) {
|
|
var ts = this._transformState;
|
|
|
|
if (ts.writechunk && ts.writecb && !ts.transforming) {
|
|
ts.transforming = true;
|
|
this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform);
|
|
} else {
|
|
// mark that we need a transform, so that any data that comes in
|
|
// will get processed, now that we've asked for it.
|
|
ts.needTransform = true;
|
|
}
|
|
};
|
|
|
|
|
|
function done(stream, er) {
|
|
if (er)
|
|
return stream.emit('error', er);
|
|
|
|
// if there's nothing in the write buffer, then that means
|
|
// that nothing more will ever be provided
|
|
var ws = stream._writableState;
|
|
var rs = stream._readableState;
|
|
var ts = stream._transformState;
|
|
|
|
if (ws.length)
|
|
throw new Error('calling transform done when ws.length != 0');
|
|
|
|
if (ts.transforming)
|
|
throw new Error('calling transform done when still transforming');
|
|
|
|
return stream.push(null);
|
|
}
|
|
|
|
},{"./duplex.js":149,"inherits":143}],155:[function(_dereq_,module,exports){
|
|
// 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.
|
|
|
|
// A bit simpler than readable streams.
|
|
// Implement an async ._write(chunk, cb), and it'll handle all
|
|
// the drain event emission and buffering.
|
|
|
|
module.exports = Writable;
|
|
Writable.WritableState = WritableState;
|
|
|
|
var isUint8Array = typeof Uint8Array !== 'undefined'
|
|
? function (x) { return x instanceof Uint8Array }
|
|
: function (x) {
|
|
return x && x.constructor && x.constructor.name === 'Uint8Array'
|
|
}
|
|
;
|
|
var isArrayBuffer = typeof ArrayBuffer !== 'undefined'
|
|
? function (x) { return x instanceof ArrayBuffer }
|
|
: function (x) {
|
|
return x && x.constructor && x.constructor.name === 'ArrayBuffer'
|
|
}
|
|
;
|
|
|
|
var inherits = _dereq_('inherits');
|
|
var Stream = _dereq_('./index.js');
|
|
var setImmediate = _dereq_('process/browser.js').nextTick;
|
|
var Buffer = _dereq_('buffer').Buffer;
|
|
|
|
inherits(Writable, Stream);
|
|
|
|
function WriteReq(chunk, encoding, cb) {
|
|
this.chunk = chunk;
|
|
this.encoding = encoding;
|
|
this.callback = cb;
|
|
}
|
|
|
|
function WritableState(options, stream) {
|
|
options = options || {};
|
|
|
|
// the point at which write() starts returning false
|
|
// Note: 0 is a valid value, means that we always return false if
|
|
// the entire buffer is not flushed immediately on write()
|
|
var hwm = options.highWaterMark;
|
|
this.highWaterMark = (hwm || hwm === 0) ? hwm : 16 * 1024;
|
|
|
|
// object stream flag to indicate whether or not this stream
|
|
// contains buffers or objects.
|
|
this.objectMode = !!options.objectMode;
|
|
|
|
// cast to ints.
|
|
this.highWaterMark = ~~this.highWaterMark;
|
|
|
|
this.needDrain = false;
|
|
// at the start of calling end()
|
|
this.ending = false;
|
|
// when end() has been called, and returned
|
|
this.ended = false;
|
|
// when 'finish' is emitted
|
|
this.finished = false;
|
|
|
|
// should we decode strings into buffers before passing to _write?
|
|
// this is here so that some node-core streams can optimize string
|
|
// handling at a lower level.
|
|
var noDecode = options.decodeStrings === false;
|
|
this.decodeStrings = !noDecode;
|
|
|
|
// Crypto is kind of old and crusty. Historically, its default string
|
|
// encoding is 'binary' so we have to make this configurable.
|
|
// Everything else in the universe uses 'utf8', though.
|
|
this.defaultEncoding = options.defaultEncoding || 'utf8';
|
|
|
|
// not an actual buffer we keep track of, but a measurement
|
|
// of how much we're waiting to get pushed to some underlying
|
|
// socket or file.
|
|
this.length = 0;
|
|
|
|
// a flag to see when we're in the middle of a write.
|
|
this.writing = false;
|
|
|
|
// a flag to be able to tell if the onwrite cb is called immediately,
|
|
// or on a later tick. We set this to true at first, becuase any
|
|
// actions that shouldn't happen until "later" should generally also
|
|
// not happen before the first write call.
|
|
this.sync = true;
|
|
|
|
// a flag to know if we're processing previously buffered items, which
|
|
// may call the _write() callback in the same tick, so that we don't
|
|
// end up in an overlapped onwrite situation.
|
|
this.bufferProcessing = false;
|
|
|
|
// the callback that's passed to _write(chunk,cb)
|
|
this.onwrite = function(er) {
|
|
onwrite(stream, er);
|
|
};
|
|
|
|
// the callback that the user supplies to write(chunk,encoding,cb)
|
|
this.writecb = null;
|
|
|
|
// the amount that is being written when _write is called.
|
|
this.writelen = 0;
|
|
|
|
this.buffer = [];
|
|
}
|
|
|
|
function Writable(options) {
|
|
// Writable ctor is applied to Duplexes, though they're not
|
|
// instanceof Writable, they're instanceof Readable.
|
|
if (!(this instanceof Writable) && !(this instanceof Stream.Duplex))
|
|
return new Writable(options);
|
|
|
|
this._writableState = new WritableState(options, this);
|
|
|
|
// legacy.
|
|
this.writable = true;
|
|
|
|
Stream.call(this);
|
|
}
|
|
|
|
// Otherwise people can pipe Writable streams, which is just wrong.
|
|
Writable.prototype.pipe = function() {
|
|
this.emit('error', new Error('Cannot pipe. Not readable.'));
|
|
};
|
|
|
|
|
|
function writeAfterEnd(stream, state, cb) {
|
|
var er = new Error('write after end');
|
|
// TODO: defer error events consistently everywhere, not just the cb
|
|
stream.emit('error', er);
|
|
setImmediate(function() {
|
|
cb(er);
|
|
});
|
|
}
|
|
|
|
// If we get something that is not a buffer, string, null, or undefined,
|
|
// and we're not in objectMode, then that's an error.
|
|
// Otherwise stream chunks are all considered to be of length=1, and the
|
|
// watermarks determine how many objects to keep in the buffer, rather than
|
|
// how many bytes or characters.
|
|
function validChunk(stream, state, chunk, cb) {
|
|
var valid = true;
|
|
if (!Buffer.isBuffer(chunk) &&
|
|
'string' !== typeof chunk &&
|
|
chunk !== null &&
|
|
chunk !== undefined &&
|
|
!state.objectMode) {
|
|
var er = new TypeError('Invalid non-string/buffer chunk');
|
|
stream.emit('error', er);
|
|
setImmediate(function() {
|
|
cb(er);
|
|
});
|
|
valid = false;
|
|
}
|
|
return valid;
|
|
}
|
|
|
|
Writable.prototype.write = function(chunk, encoding, cb) {
|
|
var state = this._writableState;
|
|
var ret = false;
|
|
|
|
if (typeof encoding === 'function') {
|
|
cb = encoding;
|
|
encoding = null;
|
|
}
|
|
|
|
if (!Buffer.isBuffer(chunk) && isUint8Array(chunk))
|
|
chunk = new Buffer(chunk);
|
|
if (isArrayBuffer(chunk) && typeof Uint8Array !== 'undefined')
|
|
chunk = new Buffer(new Uint8Array(chunk));
|
|
|
|
if (Buffer.isBuffer(chunk))
|
|
encoding = 'buffer';
|
|
else if (!encoding)
|
|
encoding = state.defaultEncoding;
|
|
|
|
if (typeof cb !== 'function')
|
|
cb = function() {};
|
|
|
|
if (state.ended)
|
|
writeAfterEnd(this, state, cb);
|
|
else if (validChunk(this, state, chunk, cb))
|
|
ret = writeOrBuffer(this, state, chunk, encoding, cb);
|
|
|
|
return ret;
|
|
};
|
|
|
|
function decodeChunk(state, chunk, encoding) {
|
|
if (!state.objectMode &&
|
|
state.decodeStrings !== false &&
|
|
typeof chunk === 'string') {
|
|
chunk = new Buffer(chunk, encoding);
|
|
}
|
|
return chunk;
|
|
}
|
|
|
|
// if we're already writing something, then just put this
|
|
// in the queue, and wait our turn. Otherwise, call _write
|
|
// If we return false, then we need a drain event, so set that flag.
|
|
function writeOrBuffer(stream, state, chunk, encoding, cb) {
|
|
chunk = decodeChunk(state, chunk, encoding);
|
|
var len = state.objectMode ? 1 : chunk.length;
|
|
|
|
state.length += len;
|
|
|
|
var ret = state.length < state.highWaterMark;
|
|
state.needDrain = !ret;
|
|
|
|
if (state.writing)
|
|
state.buffer.push(new WriteReq(chunk, encoding, cb));
|
|
else
|
|
doWrite(stream, state, len, chunk, encoding, cb);
|
|
|
|
return ret;
|
|
}
|
|
|
|
function doWrite(stream, state, len, chunk, encoding, cb) {
|
|
state.writelen = len;
|
|
state.writecb = cb;
|
|
state.writing = true;
|
|
state.sync = true;
|
|
stream._write(chunk, encoding, state.onwrite);
|
|
state.sync = false;
|
|
}
|
|
|
|
function onwriteError(stream, state, sync, er, cb) {
|
|
if (sync)
|
|
setImmediate(function() {
|
|
cb(er);
|
|
});
|
|
else
|
|
cb(er);
|
|
|
|
stream.emit('error', er);
|
|
}
|
|
|
|
function onwriteStateUpdate(state) {
|
|
state.writing = false;
|
|
state.writecb = null;
|
|
state.length -= state.writelen;
|
|
state.writelen = 0;
|
|
}
|
|
|
|
function onwrite(stream, er) {
|
|
var state = stream._writableState;
|
|
var sync = state.sync;
|
|
var cb = state.writecb;
|
|
|
|
onwriteStateUpdate(state);
|
|
|
|
if (er)
|
|
onwriteError(stream, state, sync, er, cb);
|
|
else {
|
|
// Check if we're actually ready to finish, but don't emit yet
|
|
var finished = needFinish(stream, state);
|
|
|
|
if (!finished && !state.bufferProcessing && state.buffer.length)
|
|
clearBuffer(stream, state);
|
|
|
|
if (sync) {
|
|
setImmediate(function() {
|
|
afterWrite(stream, state, finished, cb);
|
|
});
|
|
} else {
|
|
afterWrite(stream, state, finished, cb);
|
|
}
|
|
}
|
|
}
|
|
|
|
function afterWrite(stream, state, finished, cb) {
|
|
if (!finished)
|
|
onwriteDrain(stream, state);
|
|
cb();
|
|
if (finished)
|
|
finishMaybe(stream, state);
|
|
}
|
|
|
|
// Must force callback to be called on nextTick, so that we don't
|
|
// emit 'drain' before the write() consumer gets the 'false' return
|
|
// value, and has a chance to attach a 'drain' listener.
|
|
function onwriteDrain(stream, state) {
|
|
if (state.length === 0 && state.needDrain) {
|
|
state.needDrain = false;
|
|
stream.emit('drain');
|
|
}
|
|
}
|
|
|
|
|
|
// if there's something in the buffer waiting, then process it
|
|
function clearBuffer(stream, state) {
|
|
state.bufferProcessing = true;
|
|
|
|
for (var c = 0; c < state.buffer.length; c++) {
|
|
var entry = state.buffer[c];
|
|
var chunk = entry.chunk;
|
|
var encoding = entry.encoding;
|
|
var cb = entry.callback;
|
|
var len = state.objectMode ? 1 : chunk.length;
|
|
|
|
doWrite(stream, state, len, chunk, encoding, cb);
|
|
|
|
// if we didn't call the onwrite immediately, then
|
|
// it means that we need to wait until it does.
|
|
// also, that means that the chunk and cb are currently
|
|
// being processed, so move the buffer counter past them.
|
|
if (state.writing) {
|
|
c++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
state.bufferProcessing = false;
|
|
if (c < state.buffer.length)
|
|
state.buffer = state.buffer.slice(c);
|
|
else
|
|
state.buffer.length = 0;
|
|
}
|
|
|
|
Writable.prototype._write = function(chunk, encoding, cb) {
|
|
cb(new Error('not implemented'));
|
|
};
|
|
|
|
Writable.prototype.end = function(chunk, encoding, cb) {
|
|
var state = this._writableState;
|
|
|
|
if (typeof chunk === 'function') {
|
|
cb = chunk;
|
|
chunk = null;
|
|
encoding = null;
|
|
} else if (typeof encoding === 'function') {
|
|
cb = encoding;
|
|
encoding = null;
|
|
}
|
|
|
|
if (typeof chunk !== 'undefined' && chunk !== null)
|
|
this.write(chunk, encoding);
|
|
|
|
// ignore unnecessary end() calls.
|
|
if (!state.ending && !state.finished)
|
|
endWritable(this, state, cb);
|
|
};
|
|
|
|
|
|
function needFinish(stream, state) {
|
|
return (state.ending &&
|
|
state.length === 0 &&
|
|
!state.finished &&
|
|
!state.writing);
|
|
}
|
|
|
|
function finishMaybe(stream, state) {
|
|
var need = needFinish(stream, state);
|
|
if (need) {
|
|
state.finished = true;
|
|
stream.emit('finish');
|
|
}
|
|
return need;
|
|
}
|
|
|
|
function endWritable(stream, state, cb) {
|
|
state.ending = true;
|
|
finishMaybe(stream, state);
|
|
if (cb) {
|
|
if (state.finished)
|
|
setImmediate(cb);
|
|
else
|
|
stream.once('finish', cb);
|
|
}
|
|
state.ended = true;
|
|
}
|
|
|
|
},{"./index.js":150,"buffer":128,"inherits":143,"process/browser.js":151}],156:[function(_dereq_,module,exports){
|
|
// 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.
|
|
|
|
var Buffer = _dereq_('buffer').Buffer;
|
|
|
|
function assertEncoding(encoding) {
|
|
if (encoding && !Buffer.isEncoding(encoding)) {
|
|
throw new Error('Unknown encoding: ' + encoding);
|
|
}
|
|
}
|
|
|
|
var StringDecoder = exports.StringDecoder = function(encoding) {
|
|
this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, '');
|
|
assertEncoding(encoding);
|
|
switch (this.encoding) {
|
|
case 'utf8':
|
|
// CESU-8 represents each of Surrogate Pair by 3-bytes
|
|
this.surrogateSize = 3;
|
|
break;
|
|
case 'ucs2':
|
|
case 'utf16le':
|
|
// UTF-16 represents each of Surrogate Pair by 2-bytes
|
|
this.surrogateSize = 2;
|
|
this.detectIncompleteChar = utf16DetectIncompleteChar;
|
|
break;
|
|
case 'base64':
|
|
// Base-64 stores 3 bytes in 4 chars, and pads the remainder.
|
|
this.surrogateSize = 3;
|
|
this.detectIncompleteChar = base64DetectIncompleteChar;
|
|
break;
|
|
default:
|
|
this.write = passThroughWrite;
|
|
return;
|
|
}
|
|
|
|
this.charBuffer = new Buffer(6);
|
|
this.charReceived = 0;
|
|
this.charLength = 0;
|
|
};
|
|
|
|
|
|
StringDecoder.prototype.write = function(buffer) {
|
|
var charStr = '';
|
|
var offset = 0;
|
|
|
|
// if our last write ended with an incomplete multibyte character
|
|
while (this.charLength) {
|
|
// determine how many remaining bytes this buffer has to offer for this char
|
|
var i = (buffer.length >= this.charLength - this.charReceived) ?
|
|
this.charLength - this.charReceived :
|
|
buffer.length;
|
|
|
|
// add the new bytes to the char buffer
|
|
buffer.copy(this.charBuffer, this.charReceived, offset, i);
|
|
this.charReceived += (i - offset);
|
|
offset = i;
|
|
|
|
if (this.charReceived < this.charLength) {
|
|
// still not enough chars in this buffer? wait for more ...
|
|
return '';
|
|
}
|
|
|
|
// get the character that was split
|
|
charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding);
|
|
|
|
// lead surrogate (D800-DBFF) is also the incomplete character
|
|
var charCode = charStr.charCodeAt(charStr.length - 1);
|
|
if (charCode >= 0xD800 && charCode <= 0xDBFF) {
|
|
this.charLength += this.surrogateSize;
|
|
charStr = '';
|
|
continue;
|
|
}
|
|
this.charReceived = this.charLength = 0;
|
|
|
|
// if there are no more bytes in this buffer, just emit our char
|
|
if (i == buffer.length) return charStr;
|
|
|
|
// otherwise cut off the characters end from the beginning of this buffer
|
|
buffer = buffer.slice(i, buffer.length);
|
|
break;
|
|
}
|
|
|
|
var lenIncomplete = this.detectIncompleteChar(buffer);
|
|
|
|
var end = buffer.length;
|
|
if (this.charLength) {
|
|
// buffer the incomplete character bytes we got
|
|
buffer.copy(this.charBuffer, 0, buffer.length - lenIncomplete, end);
|
|
this.charReceived = lenIncomplete;
|
|
end -= lenIncomplete;
|
|
}
|
|
|
|
charStr += buffer.toString(this.encoding, 0, end);
|
|
|
|
var end = charStr.length - 1;
|
|
var charCode = charStr.charCodeAt(end);
|
|
// lead surrogate (D800-DBFF) is also the incomplete character
|
|
if (charCode >= 0xD800 && charCode <= 0xDBFF) {
|
|
var size = this.surrogateSize;
|
|
this.charLength += size;
|
|
this.charReceived += size;
|
|
this.charBuffer.copy(this.charBuffer, size, 0, size);
|
|
this.charBuffer.write(charStr.charAt(charStr.length - 1), this.encoding);
|
|
return charStr.substring(0, end);
|
|
}
|
|
|
|
// or just emit the charStr
|
|
return charStr;
|
|
};
|
|
|
|
StringDecoder.prototype.detectIncompleteChar = function(buffer) {
|
|
// determine how many bytes we have to check at the end of this buffer
|
|
var i = (buffer.length >= 3) ? 3 : buffer.length;
|
|
|
|
// Figure out if one of the last i bytes of our buffer announces an
|
|
// incomplete char.
|
|
for (; i > 0; i--) {
|
|
var c = buffer[buffer.length - i];
|
|
|
|
// See http://en.wikipedia.org/wiki/UTF-8#Description
|
|
|
|
// 110XXXXX
|
|
if (i == 1 && c >> 5 == 0x06) {
|
|
this.charLength = 2;
|
|
break;
|
|
}
|
|
|
|
// 1110XXXX
|
|
if (i <= 2 && c >> 4 == 0x0E) {
|
|
this.charLength = 3;
|
|
break;
|
|
}
|
|
|
|
// 11110XXX
|
|
if (i <= 3 && c >> 3 == 0x1E) {
|
|
this.charLength = 4;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return i;
|
|
};
|
|
|
|
StringDecoder.prototype.end = function(buffer) {
|
|
var res = '';
|
|
if (buffer && buffer.length)
|
|
res = this.write(buffer);
|
|
|
|
if (this.charReceived) {
|
|
var cr = this.charReceived;
|
|
var buf = this.charBuffer;
|
|
var enc = this.encoding;
|
|
res += buf.slice(0, cr).toString(enc);
|
|
}
|
|
|
|
return res;
|
|
};
|
|
|
|
function passThroughWrite(buffer) {
|
|
return buffer.toString(this.encoding);
|
|
}
|
|
|
|
function utf16DetectIncompleteChar(buffer) {
|
|
var incomplete = this.charReceived = buffer.length % 2;
|
|
this.charLength = incomplete ? 2 : 0;
|
|
return incomplete;
|
|
}
|
|
|
|
function base64DetectIncompleteChar(buffer) {
|
|
var incomplete = this.charReceived = buffer.length % 3;
|
|
this.charLength = incomplete ? 3 : 0;
|
|
return incomplete;
|
|
}
|
|
|
|
},{"buffer":128}],157:[function(_dereq_,module,exports){
|
|
// 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.
|
|
|
|
var punycode = _dereq_('punycode');
|
|
|
|
exports.parse = urlParse;
|
|
exports.resolve = urlResolve;
|
|
exports.resolveObject = urlResolveObject;
|
|
exports.format = urlFormat;
|
|
|
|
exports.Url = Url;
|
|
|
|
function Url() {
|
|
this.protocol = null;
|
|
this.slashes = null;
|
|
this.auth = null;
|
|
this.host = null;
|
|
this.port = null;
|
|
this.hostname = null;
|
|
this.hash = null;
|
|
this.search = null;
|
|
this.query = null;
|
|
this.pathname = null;
|
|
this.path = null;
|
|
this.href = null;
|
|
}
|
|
|
|
// Reference: RFC 3986, RFC 1808, RFC 2396
|
|
|
|
// define these here so at least they only have to be
|
|
// compiled once on the first module load.
|
|
var protocolPattern = /^([a-z0-9.+-]+:)/i,
|
|
portPattern = /:[0-9]*$/,
|
|
|
|
// RFC 2396: characters reserved for delimiting URLs.
|
|
// We actually just auto-escape these.
|
|
delims = ['<', '>', '"', '`', ' ', '\r', '\n', '\t'],
|
|
|
|
// RFC 2396: characters not allowed for various reasons.
|
|
unwise = ['{', '}', '|', '\\', '^', '`'].concat(delims),
|
|
|
|
// Allowed by RFCs, but cause of XSS attacks. Always escape these.
|
|
autoEscape = ['\''].concat(unwise),
|
|
// Characters that are never ever allowed in a hostname.
|
|
// Note that any invalid chars are also handled, but these
|
|
// are the ones that are *expected* to be seen, so we fast-path
|
|
// them.
|
|
nonHostChars = ['%', '/', '?', ';', '#'].concat(autoEscape),
|
|
hostEndingChars = ['/', '?', '#'],
|
|
hostnameMaxLen = 255,
|
|
hostnamePartPattern = /^[a-z0-9A-Z_-]{0,63}$/,
|
|
hostnamePartStart = /^([a-z0-9A-Z_-]{0,63})(.*)$/,
|
|
// protocols that can allow "unsafe" and "unwise" chars.
|
|
unsafeProtocol = {
|
|
'javascript': true,
|
|
'javascript:': true
|
|
},
|
|
// protocols that never have a hostname.
|
|
hostlessProtocol = {
|
|
'javascript': true,
|
|
'javascript:': true
|
|
},
|
|
// protocols that always contain a // bit.
|
|
slashedProtocol = {
|
|
'http': true,
|
|
'https': true,
|
|
'ftp': true,
|
|
'gopher': true,
|
|
'file': true,
|
|
'http:': true,
|
|
'https:': true,
|
|
'ftp:': true,
|
|
'gopher:': true,
|
|
'file:': true
|
|
},
|
|
querystring = _dereq_('querystring');
|
|
|
|
function urlParse(url, parseQueryString, slashesDenoteHost) {
|
|
if (url && isObject(url) && url instanceof Url) return url;
|
|
|
|
var u = new Url;
|
|
u.parse(url, parseQueryString, slashesDenoteHost);
|
|
return u;
|
|
}
|
|
|
|
Url.prototype.parse = function(url, parseQueryString, slashesDenoteHost) {
|
|
if (!isString(url)) {
|
|
throw new TypeError("Parameter 'url' must be a string, not " + typeof url);
|
|
}
|
|
|
|
var rest = url;
|
|
|
|
// trim before proceeding.
|
|
// This is to support parse stuff like " http://foo.com \n"
|
|
rest = rest.trim();
|
|
|
|
var proto = protocolPattern.exec(rest);
|
|
if (proto) {
|
|
proto = proto[0];
|
|
var lowerProto = proto.toLowerCase();
|
|
this.protocol = lowerProto;
|
|
rest = rest.substr(proto.length);
|
|
}
|
|
|
|
// figure out if it's got a host
|
|
// user@server is *always* interpreted as a hostname, and url
|
|
// resolution will treat //foo/bar as host=foo,path=bar because that's
|
|
// how the browser resolves relative URLs.
|
|
if (slashesDenoteHost || proto || rest.match(/^\/\/[^@\/]+@[^@\/]+/)) {
|
|
var slashes = rest.substr(0, 2) === '//';
|
|
if (slashes && !(proto && hostlessProtocol[proto])) {
|
|
rest = rest.substr(2);
|
|
this.slashes = true;
|
|
}
|
|
}
|
|
|
|
if (!hostlessProtocol[proto] &&
|
|
(slashes || (proto && !slashedProtocol[proto]))) {
|
|
|
|
// there's a hostname.
|
|
// the first instance of /, ?, ;, or # ends the host.
|
|
//
|
|
// If there is an @ in the hostname, then non-host chars *are* allowed
|
|
// to the left of the last @ sign, unless some host-ending character
|
|
// comes *before* the @-sign.
|
|
// URLs are obnoxious.
|
|
//
|
|
// ex:
|
|
// http://a@b@c/ => user:a@b host:c
|
|
// http://a@b?@c => user:a host:c path:/?@c
|
|
|
|
// v0.12 TODO(isaacs): This is not quite how Chrome does things.
|
|
// Review our test case against browsers more comprehensively.
|
|
|
|
// find the first instance of any hostEndingChars
|
|
var hostEnd = -1;
|
|
for (var i = 0; i < hostEndingChars.length; i++) {
|
|
var hec = rest.indexOf(hostEndingChars[i]);
|
|
if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
|
|
hostEnd = hec;
|
|
}
|
|
|
|
// at this point, either we have an explicit point where the
|
|
// auth portion cannot go past, or the last @ char is the decider.
|
|
var auth, atSign;
|
|
if (hostEnd === -1) {
|
|
// atSign can be anywhere.
|
|
atSign = rest.lastIndexOf('@');
|
|
} else {
|
|
// atSign must be in auth portion.
|
|
// http://a@b/c@d => host:b auth:a path:/c@d
|
|
atSign = rest.lastIndexOf('@', hostEnd);
|
|
}
|
|
|
|
// Now we have a portion which is definitely the auth.
|
|
// Pull that off.
|
|
if (atSign !== -1) {
|
|
auth = rest.slice(0, atSign);
|
|
rest = rest.slice(atSign + 1);
|
|
this.auth = decodeURIComponent(auth);
|
|
}
|
|
|
|
// the host is the remaining to the left of the first non-host char
|
|
hostEnd = -1;
|
|
for (var i = 0; i < nonHostChars.length; i++) {
|
|
var hec = rest.indexOf(nonHostChars[i]);
|
|
if (hec !== -1 && (hostEnd === -1 || hec < hostEnd))
|
|
hostEnd = hec;
|
|
}
|
|
// if we still have not hit it, then the entire thing is a host.
|
|
if (hostEnd === -1)
|
|
hostEnd = rest.length;
|
|
|
|
this.host = rest.slice(0, hostEnd);
|
|
rest = rest.slice(hostEnd);
|
|
|
|
// pull out port.
|
|
this.parseHost();
|
|
|
|
// we've indicated that there is a hostname,
|
|
// so even if it's empty, it has to be present.
|
|
this.hostname = this.hostname || '';
|
|
|
|
// if hostname begins with [ and ends with ]
|
|
// assume that it's an IPv6 address.
|
|
var ipv6Hostname = this.hostname[0] === '[' &&
|
|
this.hostname[this.hostname.length - 1] === ']';
|
|
|
|
// validate a little.
|
|
if (!ipv6Hostname) {
|
|
var hostparts = this.hostname.split(/\./);
|
|
for (var i = 0, l = hostparts.length; i < l; i++) {
|
|
var part = hostparts[i];
|
|
if (!part) continue;
|
|
if (!part.match(hostnamePartPattern)) {
|
|
var newpart = '';
|
|
for (var j = 0, k = part.length; j < k; j++) {
|
|
if (part.charCodeAt(j) > 127) {
|
|
// we replace non-ASCII char with a temporary placeholder
|
|
// we need this to make sure size of hostname is not
|
|
// broken by replacing non-ASCII by nothing
|
|
newpart += 'x';
|
|
} else {
|
|
newpart += part[j];
|
|
}
|
|
}
|
|
// we test again with ASCII char only
|
|
if (!newpart.match(hostnamePartPattern)) {
|
|
var validParts = hostparts.slice(0, i);
|
|
var notHost = hostparts.slice(i + 1);
|
|
var bit = part.match(hostnamePartStart);
|
|
if (bit) {
|
|
validParts.push(bit[1]);
|
|
notHost.unshift(bit[2]);
|
|
}
|
|
if (notHost.length) {
|
|
rest = '/' + notHost.join('.') + rest;
|
|
}
|
|
this.hostname = validParts.join('.');
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (this.hostname.length > hostnameMaxLen) {
|
|
this.hostname = '';
|
|
} else {
|
|
// hostnames are always lower case.
|
|
this.hostname = this.hostname.toLowerCase();
|
|
}
|
|
|
|
if (!ipv6Hostname) {
|
|
// IDNA Support: Returns a puny coded representation of "domain".
|
|
// It only converts the part of the domain name that
|
|
// has non ASCII characters. I.e. it dosent matter if
|
|
// you call it with a domain that already is in ASCII.
|
|
var domainArray = this.hostname.split('.');
|
|
var newOut = [];
|
|
for (var i = 0; i < domainArray.length; ++i) {
|
|
var s = domainArray[i];
|
|
newOut.push(s.match(/[^A-Za-z0-9_-]/) ?
|
|
'xn--' + punycode.encode(s) : s);
|
|
}
|
|
this.hostname = newOut.join('.');
|
|
}
|
|
|
|
var p = this.port ? ':' + this.port : '';
|
|
var h = this.hostname || '';
|
|
this.host = h + p;
|
|
this.href += this.host;
|
|
|
|
// strip [ and ] from the hostname
|
|
// the host field still retains them, though
|
|
if (ipv6Hostname) {
|
|
this.hostname = this.hostname.substr(1, this.hostname.length - 2);
|
|
if (rest[0] !== '/') {
|
|
rest = '/' + rest;
|
|
}
|
|
}
|
|
}
|
|
|
|
// now rest is set to the post-host stuff.
|
|
// chop off any delim chars.
|
|
if (!unsafeProtocol[lowerProto]) {
|
|
|
|
// First, make 100% sure that any "autoEscape" chars get
|
|
// escaped, even if encodeURIComponent doesn't think they
|
|
// need to be.
|
|
for (var i = 0, l = autoEscape.length; i < l; i++) {
|
|
var ae = autoEscape[i];
|
|
var esc = encodeURIComponent(ae);
|
|
if (esc === ae) {
|
|
esc = escape(ae);
|
|
}
|
|
rest = rest.split(ae).join(esc);
|
|
}
|
|
}
|
|
|
|
|
|
// chop off from the tail first.
|
|
var hash = rest.indexOf('#');
|
|
if (hash !== -1) {
|
|
// got a fragment string.
|
|
this.hash = rest.substr(hash);
|
|
rest = rest.slice(0, hash);
|
|
}
|
|
var qm = rest.indexOf('?');
|
|
if (qm !== -1) {
|
|
this.search = rest.substr(qm);
|
|
this.query = rest.substr(qm + 1);
|
|
if (parseQueryString) {
|
|
this.query = querystring.parse(this.query);
|
|
}
|
|
rest = rest.slice(0, qm);
|
|
} else if (parseQueryString) {
|
|
// no query string, but parseQueryString still requested
|
|
this.search = '';
|
|
this.query = {};
|
|
}
|
|
if (rest) this.pathname = rest;
|
|
if (slashedProtocol[lowerProto] &&
|
|
this.hostname && !this.pathname) {
|
|
this.pathname = '/';
|
|
}
|
|
|
|
//to support http.request
|
|
if (this.pathname || this.search) {
|
|
var p = this.pathname || '';
|
|
var s = this.search || '';
|
|
this.path = p + s;
|
|
}
|
|
|
|
// finally, reconstruct the href based on what has been validated.
|
|
this.href = this.format();
|
|
return this;
|
|
};
|
|
|
|
// format a parsed object into a url string
|
|
function urlFormat(obj) {
|
|
// ensure it's an object, and not a string url.
|
|
// If it's an obj, this is a no-op.
|
|
// this way, you can call url_format() on strings
|
|
// to clean up potentially wonky urls.
|
|
if (isString(obj)) obj = urlParse(obj);
|
|
if (!(obj instanceof Url)) return Url.prototype.format.call(obj);
|
|
return obj.format();
|
|
}
|
|
|
|
Url.prototype.format = function() {
|
|
var auth = this.auth || '';
|
|
if (auth) {
|
|
auth = encodeURIComponent(auth);
|
|
auth = auth.replace(/%3A/i, ':');
|
|
auth += '@';
|
|
}
|
|
|
|
var protocol = this.protocol || '',
|
|
pathname = this.pathname || '',
|
|
hash = this.hash || '',
|
|
host = false,
|
|
query = '';
|
|
|
|
if (this.host) {
|
|
host = auth + this.host;
|
|
} else if (this.hostname) {
|
|
host = auth + (this.hostname.indexOf(':') === -1 ?
|
|
this.hostname :
|
|
'[' + this.hostname + ']');
|
|
if (this.port) {
|
|
host += ':' + this.port;
|
|
}
|
|
}
|
|
|
|
if (this.query &&
|
|
isObject(this.query) &&
|
|
Object.keys(this.query).length) {
|
|
query = querystring.stringify(this.query);
|
|
}
|
|
|
|
var search = this.search || (query && ('?' + query)) || '';
|
|
|
|
if (protocol && protocol.substr(-1) !== ':') protocol += ':';
|
|
|
|
// only the slashedProtocols get the //. Not mailto:, xmpp:, etc.
|
|
// unless they had them to begin with.
|
|
if (this.slashes ||
|
|
(!protocol || slashedProtocol[protocol]) && host !== false) {
|
|
host = '//' + (host || '');
|
|
if (pathname && pathname.charAt(0) !== '/') pathname = '/' + pathname;
|
|
} else if (!host) {
|
|
host = '';
|
|
}
|
|
|
|
if (hash && hash.charAt(0) !== '#') hash = '#' + hash;
|
|
if (search && search.charAt(0) !== '?') search = '?' + search;
|
|
|
|
pathname = pathname.replace(/[?#]/g, function(match) {
|
|
return encodeURIComponent(match);
|
|
});
|
|
search = search.replace('#', '%23');
|
|
|
|
return protocol + host + pathname + search + hash;
|
|
};
|
|
|
|
function urlResolve(source, relative) {
|
|
return urlParse(source, false, true).resolve(relative);
|
|
}
|
|
|
|
Url.prototype.resolve = function(relative) {
|
|
return this.resolveObject(urlParse(relative, false, true)).format();
|
|
};
|
|
|
|
function urlResolveObject(source, relative) {
|
|
if (!source) return relative;
|
|
return urlParse(source, false, true).resolveObject(relative);
|
|
}
|
|
|
|
Url.prototype.resolveObject = function(relative) {
|
|
if (isString(relative)) {
|
|
var rel = new Url();
|
|
rel.parse(relative, false, true);
|
|
relative = rel;
|
|
}
|
|
|
|
var result = new Url();
|
|
Object.keys(this).forEach(function(k) {
|
|
result[k] = this[k];
|
|
}, this);
|
|
|
|
// hash is always overridden, no matter what.
|
|
// even href="" will remove it.
|
|
result.hash = relative.hash;
|
|
|
|
// if the relative url is empty, then there's nothing left to do here.
|
|
if (relative.href === '') {
|
|
result.href = result.format();
|
|
return result;
|
|
}
|
|
|
|
// hrefs like //foo/bar always cut to the protocol.
|
|
if (relative.slashes && !relative.protocol) {
|
|
// take everything except the protocol from relative
|
|
Object.keys(relative).forEach(function(k) {
|
|
if (k !== 'protocol')
|
|
result[k] = relative[k];
|
|
});
|
|
|
|
//urlParse appends trailing / to urls like http://www.example.com
|
|
if (slashedProtocol[result.protocol] &&
|
|
result.hostname && !result.pathname) {
|
|
result.path = result.pathname = '/';
|
|
}
|
|
|
|
result.href = result.format();
|
|
return result;
|
|
}
|
|
|
|
if (relative.protocol && relative.protocol !== result.protocol) {
|
|
// if it's a known url protocol, then changing
|
|
// the protocol does weird things
|
|
// first, if it's not file:, then we MUST have a host,
|
|
// and if there was a path
|
|
// to begin with, then we MUST have a path.
|
|
// if it is file:, then the host is dropped,
|
|
// because that's known to be hostless.
|
|
// anything else is assumed to be absolute.
|
|
if (!slashedProtocol[relative.protocol]) {
|
|
Object.keys(relative).forEach(function(k) {
|
|
result[k] = relative[k];
|
|
});
|
|
result.href = result.format();
|
|
return result;
|
|
}
|
|
|
|
result.protocol = relative.protocol;
|
|
if (!relative.host && !hostlessProtocol[relative.protocol]) {
|
|
var relPath = (relative.pathname || '').split('/');
|
|
while (relPath.length && !(relative.host = relPath.shift()));
|
|
if (!relative.host) relative.host = '';
|
|
if (!relative.hostname) relative.hostname = '';
|
|
if (relPath[0] !== '') relPath.unshift('');
|
|
if (relPath.length < 2) relPath.unshift('');
|
|
result.pathname = relPath.join('/');
|
|
} else {
|
|
result.pathname = relative.pathname;
|
|
}
|
|
result.search = relative.search;
|
|
result.query = relative.query;
|
|
result.host = relative.host || '';
|
|
result.auth = relative.auth;
|
|
result.hostname = relative.hostname || relative.host;
|
|
result.port = relative.port;
|
|
// to support http.request
|
|
if (result.pathname || result.search) {
|
|
var p = result.pathname || '';
|
|
var s = result.search || '';
|
|
result.path = p + s;
|
|
}
|
|
result.slashes = result.slashes || relative.slashes;
|
|
result.href = result.format();
|
|
return result;
|
|
}
|
|
|
|
var isSourceAbs = (result.pathname && result.pathname.charAt(0) === '/'),
|
|
isRelAbs = (
|
|
relative.host ||
|
|
relative.pathname && relative.pathname.charAt(0) === '/'
|
|
),
|
|
mustEndAbs = (isRelAbs || isSourceAbs ||
|
|
(result.host && relative.pathname)),
|
|
removeAllDots = mustEndAbs,
|
|
srcPath = result.pathname && result.pathname.split('/') || [],
|
|
relPath = relative.pathname && relative.pathname.split('/') || [],
|
|
psychotic = result.protocol && !slashedProtocol[result.protocol];
|
|
|
|
// if the url is a non-slashed url, then relative
|
|
// links like ../.. should be able
|
|
// to crawl up to the hostname, as well. This is strange.
|
|
// result.protocol has already been set by now.
|
|
// Later on, put the first path part into the host field.
|
|
if (psychotic) {
|
|
result.hostname = '';
|
|
result.port = null;
|
|
if (result.host) {
|
|
if (srcPath[0] === '') srcPath[0] = result.host;
|
|
else srcPath.unshift(result.host);
|
|
}
|
|
result.host = '';
|
|
if (relative.protocol) {
|
|
relative.hostname = null;
|
|
relative.port = null;
|
|
if (relative.host) {
|
|
if (relPath[0] === '') relPath[0] = relative.host;
|
|
else relPath.unshift(relative.host);
|
|
}
|
|
relative.host = null;
|
|
}
|
|
mustEndAbs = mustEndAbs && (relPath[0] === '' || srcPath[0] === '');
|
|
}
|
|
|
|
if (isRelAbs) {
|
|
// it's absolute.
|
|
result.host = (relative.host || relative.host === '') ?
|
|
relative.host : result.host;
|
|
result.hostname = (relative.hostname || relative.hostname === '') ?
|
|
relative.hostname : result.hostname;
|
|
result.search = relative.search;
|
|
result.query = relative.query;
|
|
srcPath = relPath;
|
|
// fall through to the dot-handling below.
|
|
} else if (relPath.length) {
|
|
// it's relative
|
|
// throw away the existing file, and take the new path instead.
|
|
if (!srcPath) srcPath = [];
|
|
srcPath.pop();
|
|
srcPath = srcPath.concat(relPath);
|
|
result.search = relative.search;
|
|
result.query = relative.query;
|
|
} else if (!isNullOrUndefined(relative.search)) {
|
|
// just pull out the search.
|
|
// like href='?foo'.
|
|
// Put this after the other two cases because it simplifies the booleans
|
|
if (psychotic) {
|
|
result.hostname = result.host = srcPath.shift();
|
|
//occationaly the auth can get stuck only in host
|
|
//this especialy happens in cases like
|
|
//url.resolveObject('mailto:local1@domain1', 'local2@domain2')
|
|
var authInHost = result.host && result.host.indexOf('@') > 0 ?
|
|
result.host.split('@') : false;
|
|
if (authInHost) {
|
|
result.auth = authInHost.shift();
|
|
result.host = result.hostname = authInHost.shift();
|
|
}
|
|
}
|
|
result.search = relative.search;
|
|
result.query = relative.query;
|
|
//to support http.request
|
|
if (!isNull(result.pathname) || !isNull(result.search)) {
|
|
result.path = (result.pathname ? result.pathname : '') +
|
|
(result.search ? result.search : '');
|
|
}
|
|
result.href = result.format();
|
|
return result;
|
|
}
|
|
|
|
if (!srcPath.length) {
|
|
// no path at all. easy.
|
|
// we've already handled the other stuff above.
|
|
result.pathname = null;
|
|
//to support http.request
|
|
if (result.search) {
|
|
result.path = '/' + result.search;
|
|
} else {
|
|
result.path = null;
|
|
}
|
|
result.href = result.format();
|
|
return result;
|
|
}
|
|
|
|
// if a url ENDs in . or .., then it must get a trailing slash.
|
|
// however, if it ends in anything else non-slashy,
|
|
// then it must NOT get a trailing slash.
|
|
var last = srcPath.slice(-1)[0];
|
|
var hasTrailingSlash = (
|
|
(result.host || relative.host) && (last === '.' || last === '..') ||
|
|
last === '');
|
|
|
|
// strip single dots, resolve double dots to parent dir
|
|
// if the path tries to go above the root, `up` ends up > 0
|
|
var up = 0;
|
|
for (var i = srcPath.length; i >= 0; i--) {
|
|
last = srcPath[i];
|
|
if (last == '.') {
|
|
srcPath.splice(i, 1);
|
|
} else if (last === '..') {
|
|
srcPath.splice(i, 1);
|
|
up++;
|
|
} else if (up) {
|
|
srcPath.splice(i, 1);
|
|
up--;
|
|
}
|
|
}
|
|
|
|
// if the path is allowed to go above the root, restore leading ..s
|
|
if (!mustEndAbs && !removeAllDots) {
|
|
for (; up--; up) {
|
|
srcPath.unshift('..');
|
|
}
|
|
}
|
|
|
|
if (mustEndAbs && srcPath[0] !== '' &&
|
|
(!srcPath[0] || srcPath[0].charAt(0) !== '/')) {
|
|
srcPath.unshift('');
|
|
}
|
|
|
|
if (hasTrailingSlash && (srcPath.join('/').substr(-1) !== '/')) {
|
|
srcPath.push('');
|
|
}
|
|
|
|
var isAbsolute = srcPath[0] === '' ||
|
|
(srcPath[0] && srcPath[0].charAt(0) === '/');
|
|
|
|
// put the host back
|
|
if (psychotic) {
|
|
result.hostname = result.host = isAbsolute ? '' :
|
|
srcPath.length ? srcPath.shift() : '';
|
|
//occationaly the auth can get stuck only in host
|
|
//this especialy happens in cases like
|
|
//url.resolveObject('mailto:local1@domain1', 'local2@domain2')
|
|
var authInHost = result.host && result.host.indexOf('@') > 0 ?
|
|
result.host.split('@') : false;
|
|
if (authInHost) {
|
|
result.auth = authInHost.shift();
|
|
result.host = result.hostname = authInHost.shift();
|
|
}
|
|
}
|
|
|
|
mustEndAbs = mustEndAbs || (result.host && srcPath.length);
|
|
|
|
if (mustEndAbs && !isAbsolute) {
|
|
srcPath.unshift('');
|
|
}
|
|
|
|
if (!srcPath.length) {
|
|
result.pathname = null;
|
|
result.path = null;
|
|
} else {
|
|
result.pathname = srcPath.join('/');
|
|
}
|
|
|
|
//to support request.http
|
|
if (!isNull(result.pathname) || !isNull(result.search)) {
|
|
result.path = (result.pathname ? result.pathname : '') +
|
|
(result.search ? result.search : '');
|
|
}
|
|
result.auth = relative.auth || result.auth;
|
|
result.slashes = result.slashes || relative.slashes;
|
|
result.href = result.format();
|
|
return result;
|
|
};
|
|
|
|
Url.prototype.parseHost = function() {
|
|
var host = this.host;
|
|
var port = portPattern.exec(host);
|
|
if (port) {
|
|
port = port[0];
|
|
if (port !== ':') {
|
|
this.port = port.substr(1);
|
|
}
|
|
host = host.substr(0, host.length - port.length);
|
|
}
|
|
if (host) this.hostname = host;
|
|
};
|
|
|
|
function isString(arg) {
|
|
return typeof arg === "string";
|
|
}
|
|
|
|
function isObject(arg) {
|
|
return typeof arg === 'object' && arg !== null;
|
|
}
|
|
|
|
function isNull(arg) {
|
|
return arg === null;
|
|
}
|
|
function isNullOrUndefined(arg) {
|
|
return arg == null;
|
|
}
|
|
|
|
},{"punycode":145,"querystring":148}],158:[function(_dereq_,module,exports){
|
|
module.exports = function isBuffer(arg) {
|
|
return arg && typeof arg === 'object'
|
|
&& typeof arg.copy === 'function'
|
|
&& typeof arg.fill === 'function'
|
|
&& typeof arg.readUInt8 === 'function';
|
|
}
|
|
},{}],159:[function(_dereq_,module,exports){
|
|
(function (process,global){
|
|
// 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.
|
|
|
|
var formatRegExp = /%[sdj%]/g;
|
|
exports.format = function(f) {
|
|
if (!isString(f)) {
|
|
var objects = [];
|
|
for (var i = 0; i < arguments.length; i++) {
|
|
objects.push(inspect(arguments[i]));
|
|
}
|
|
return objects.join(' ');
|
|
}
|
|
|
|
var i = 1;
|
|
var args = arguments;
|
|
var len = args.length;
|
|
var str = String(f).replace(formatRegExp, function(x) {
|
|
if (x === '%%') return '%';
|
|
if (i >= len) return x;
|
|
switch (x) {
|
|
case '%s': return String(args[i++]);
|
|
case '%d': return Number(args[i++]);
|
|
case '%j':
|
|
try {
|
|
return JSON.stringify(args[i++]);
|
|
} catch (_) {
|
|
return '[Circular]';
|
|
}
|
|
default:
|
|
return x;
|
|
}
|
|
});
|
|
for (var x = args[i]; i < len; x = args[++i]) {
|
|
if (isNull(x) || !isObject(x)) {
|
|
str += ' ' + x;
|
|
} else {
|
|
str += ' ' + inspect(x);
|
|
}
|
|
}
|
|
return str;
|
|
};
|
|
|
|
|
|
// Mark that a method should not be used.
|
|
// Returns a modified function which warns once by default.
|
|
// If --no-deprecation is set, then it is a no-op.
|
|
exports.deprecate = function(fn, msg) {
|
|
// Allow for deprecating things in the process of starting up.
|
|
if (isUndefined(global.process)) {
|
|
return function() {
|
|
return exports.deprecate(fn, msg).apply(this, arguments);
|
|
};
|
|
}
|
|
|
|
if (process.noDeprecation === true) {
|
|
return fn;
|
|
}
|
|
|
|
var warned = false;
|
|
function deprecated() {
|
|
if (!warned) {
|
|
if (process.throwDeprecation) {
|
|
throw new Error(msg);
|
|
} else if (process.traceDeprecation) {
|
|
console.trace(msg);
|
|
} else {
|
|
console.error(msg);
|
|
}
|
|
warned = true;
|
|
}
|
|
return fn.apply(this, arguments);
|
|
}
|
|
|
|
return deprecated;
|
|
};
|
|
|
|
|
|
var debugs = {};
|
|
var debugEnviron;
|
|
exports.debuglog = function(set) {
|
|
if (isUndefined(debugEnviron))
|
|
debugEnviron = process.env.NODE_DEBUG || '';
|
|
set = set.toUpperCase();
|
|
if (!debugs[set]) {
|
|
if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
|
|
var pid = process.pid;
|
|
debugs[set] = function() {
|
|
var msg = exports.format.apply(exports, arguments);
|
|
console.error('%s %d: %s', set, pid, msg);
|
|
};
|
|
} else {
|
|
debugs[set] = function() {};
|
|
}
|
|
}
|
|
return debugs[set];
|
|
};
|
|
|
|
|
|
/**
|
|
* Echos the value of a value. Trys to print the value out
|
|
* in the best way possible given the different types.
|
|
*
|
|
* @param {Object} obj The object to print out.
|
|
* @param {Object} opts Optional options object that alters the output.
|
|
*/
|
|
/* legacy: obj, showHidden, depth, colors*/
|
|
function inspect(obj, opts) {
|
|
// default options
|
|
var ctx = {
|
|
seen: [],
|
|
stylize: stylizeNoColor
|
|
};
|
|
// legacy...
|
|
if (arguments.length >= 3) ctx.depth = arguments[2];
|
|
if (arguments.length >= 4) ctx.colors = arguments[3];
|
|
if (isBoolean(opts)) {
|
|
// legacy...
|
|
ctx.showHidden = opts;
|
|
} else if (opts) {
|
|
// got an "options" object
|
|
exports._extend(ctx, opts);
|
|
}
|
|
// set default options
|
|
if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
|
|
if (isUndefined(ctx.depth)) ctx.depth = 2;
|
|
if (isUndefined(ctx.colors)) ctx.colors = false;
|
|
if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
|
|
if (ctx.colors) ctx.stylize = stylizeWithColor;
|
|
return formatValue(ctx, obj, ctx.depth);
|
|
}
|
|
exports.inspect = inspect;
|
|
|
|
|
|
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
|
|
inspect.colors = {
|
|
'bold' : [1, 22],
|
|
'italic' : [3, 23],
|
|
'underline' : [4, 24],
|
|
'inverse' : [7, 27],
|
|
'white' : [37, 39],
|
|
'grey' : [90, 39],
|
|
'black' : [30, 39],
|
|
'blue' : [34, 39],
|
|
'cyan' : [36, 39],
|
|
'green' : [32, 39],
|
|
'magenta' : [35, 39],
|
|
'red' : [31, 39],
|
|
'yellow' : [33, 39]
|
|
};
|
|
|
|
// Don't use 'blue' not visible on cmd.exe
|
|
inspect.styles = {
|
|
'special': 'cyan',
|
|
'number': 'yellow',
|
|
'boolean': 'yellow',
|
|
'undefined': 'grey',
|
|
'null': 'bold',
|
|
'string': 'green',
|
|
'date': 'magenta',
|
|
// "name": intentionally not styling
|
|
'regexp': 'red'
|
|
};
|
|
|
|
|
|
function stylizeWithColor(str, styleType) {
|
|
var style = inspect.styles[styleType];
|
|
|
|
if (style) {
|
|
return '\u001b[' + inspect.colors[style][0] + 'm' + str +
|
|
'\u001b[' + inspect.colors[style][1] + 'm';
|
|
} else {
|
|
return str;
|
|
}
|
|
}
|
|
|
|
|
|
function stylizeNoColor(str, styleType) {
|
|
return str;
|
|
}
|
|
|
|
|
|
function arrayToHash(array) {
|
|
var hash = {};
|
|
|
|
array.forEach(function(val, idx) {
|
|
hash[val] = true;
|
|
});
|
|
|
|
return hash;
|
|
}
|
|
|
|
|
|
function formatValue(ctx, value, recurseTimes) {
|
|
// Provide a hook for user-specified inspect functions.
|
|
// Check that value is an object with an inspect function on it
|
|
if (ctx.customInspect &&
|
|
value &&
|
|
isFunction(value.inspect) &&
|
|
// Filter out the util module, it's inspect function is special
|
|
value.inspect !== exports.inspect &&
|
|
// Also filter out any prototype objects using the circular check.
|
|
!(value.constructor && value.constructor.prototype === value)) {
|
|
var ret = value.inspect(recurseTimes, ctx);
|
|
if (!isString(ret)) {
|
|
ret = formatValue(ctx, ret, recurseTimes);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// Primitive types cannot have properties
|
|
var primitive = formatPrimitive(ctx, value);
|
|
if (primitive) {
|
|
return primitive;
|
|
}
|
|
|
|
// Look up the keys of the object.
|
|
var keys = Object.keys(value);
|
|
var visibleKeys = arrayToHash(keys);
|
|
|
|
if (ctx.showHidden) {
|
|
keys = Object.getOwnPropertyNames(value);
|
|
}
|
|
|
|
// IE doesn't make error fields non-enumerable
|
|
// http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
|
|
if (isError(value)
|
|
&& (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
|
|
return formatError(value);
|
|
}
|
|
|
|
// Some type of object without properties can be shortcutted.
|
|
if (keys.length === 0) {
|
|
if (isFunction(value)) {
|
|
var name = value.name ? ': ' + value.name : '';
|
|
return ctx.stylize('[Function' + name + ']', 'special');
|
|
}
|
|
if (isRegExp(value)) {
|
|
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
|
|
}
|
|
if (isDate(value)) {
|
|
return ctx.stylize(Date.prototype.toString.call(value), 'date');
|
|
}
|
|
if (isError(value)) {
|
|
return formatError(value);
|
|
}
|
|
}
|
|
|
|
var base = '', array = false, braces = ['{', '}'];
|
|
|
|
// Make Array say that they are Array
|
|
if (isArray(value)) {
|
|
array = true;
|
|
braces = ['[', ']'];
|
|
}
|
|
|
|
// Make functions say that they are functions
|
|
if (isFunction(value)) {
|
|
var n = value.name ? ': ' + value.name : '';
|
|
base = ' [Function' + n + ']';
|
|
}
|
|
|
|
// Make RegExps say that they are RegExps
|
|
if (isRegExp(value)) {
|
|
base = ' ' + RegExp.prototype.toString.call(value);
|
|
}
|
|
|
|
// Make dates with properties first say the date
|
|
if (isDate(value)) {
|
|
base = ' ' + Date.prototype.toUTCString.call(value);
|
|
}
|
|
|
|
// Make error with message first say the error
|
|
if (isError(value)) {
|
|
base = ' ' + formatError(value);
|
|
}
|
|
|
|
if (keys.length === 0 && (!array || value.length == 0)) {
|
|
return braces[0] + base + braces[1];
|
|
}
|
|
|
|
if (recurseTimes < 0) {
|
|
if (isRegExp(value)) {
|
|
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
|
|
} else {
|
|
return ctx.stylize('[Object]', 'special');
|
|
}
|
|
}
|
|
|
|
ctx.seen.push(value);
|
|
|
|
var output;
|
|
if (array) {
|
|
output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
|
|
} else {
|
|
output = keys.map(function(key) {
|
|
return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
|
|
});
|
|
}
|
|
|
|
ctx.seen.pop();
|
|
|
|
return reduceToSingleString(output, base, braces);
|
|
}
|
|
|
|
|
|
function formatPrimitive(ctx, value) {
|
|
if (isUndefined(value))
|
|
return ctx.stylize('undefined', 'undefined');
|
|
if (isString(value)) {
|
|
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
|
|
.replace(/'/g, "\\'")
|
|
.replace(/\\"/g, '"') + '\'';
|
|
return ctx.stylize(simple, 'string');
|
|
}
|
|
if (isNumber(value))
|
|
return ctx.stylize('' + value, 'number');
|
|
if (isBoolean(value))
|
|
return ctx.stylize('' + value, 'boolean');
|
|
// For some reason typeof null is "object", so special case here.
|
|
if (isNull(value))
|
|
return ctx.stylize('null', 'null');
|
|
}
|
|
|
|
|
|
function formatError(value) {
|
|
return '[' + Error.prototype.toString.call(value) + ']';
|
|
}
|
|
|
|
|
|
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
|
|
var output = [];
|
|
for (var i = 0, l = value.length; i < l; ++i) {
|
|
if (hasOwnProperty(value, String(i))) {
|
|
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
|
|
String(i), true));
|
|
} else {
|
|
output.push('');
|
|
}
|
|
}
|
|
keys.forEach(function(key) {
|
|
if (!key.match(/^\d+$/)) {
|
|
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
|
|
key, true));
|
|
}
|
|
});
|
|
return output;
|
|
}
|
|
|
|
|
|
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
|
|
var name, str, desc;
|
|
desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
|
|
if (desc.get) {
|
|
if (desc.set) {
|
|
str = ctx.stylize('[Getter/Setter]', 'special');
|
|
} else {
|
|
str = ctx.stylize('[Getter]', 'special');
|
|
}
|
|
} else {
|
|
if (desc.set) {
|
|
str = ctx.stylize('[Setter]', 'special');
|
|
}
|
|
}
|
|
if (!hasOwnProperty(visibleKeys, key)) {
|
|
name = '[' + key + ']';
|
|
}
|
|
if (!str) {
|
|
if (ctx.seen.indexOf(desc.value) < 0) {
|
|
if (isNull(recurseTimes)) {
|
|
str = formatValue(ctx, desc.value, null);
|
|
} else {
|
|
str = formatValue(ctx, desc.value, recurseTimes - 1);
|
|
}
|
|
if (str.indexOf('\n') > -1) {
|
|
if (array) {
|
|
str = str.split('\n').map(function(line) {
|
|
return ' ' + line;
|
|
}).join('\n').substr(2);
|
|
} else {
|
|
str = '\n' + str.split('\n').map(function(line) {
|
|
return ' ' + line;
|
|
}).join('\n');
|
|
}
|
|
}
|
|
} else {
|
|
str = ctx.stylize('[Circular]', 'special');
|
|
}
|
|
}
|
|
if (isUndefined(name)) {
|
|
if (array && key.match(/^\d+$/)) {
|
|
return str;
|
|
}
|
|
name = JSON.stringify('' + key);
|
|
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
|
|
name = name.substr(1, name.length - 2);
|
|
name = ctx.stylize(name, 'name');
|
|
} else {
|
|
name = name.replace(/'/g, "\\'")
|
|
.replace(/\\"/g, '"')
|
|
.replace(/(^"|"$)/g, "'");
|
|
name = ctx.stylize(name, 'string');
|
|
}
|
|
}
|
|
|
|
return name + ': ' + str;
|
|
}
|
|
|
|
|
|
function reduceToSingleString(output, base, braces) {
|
|
var numLinesEst = 0;
|
|
var length = output.reduce(function(prev, cur) {
|
|
numLinesEst++;
|
|
if (cur.indexOf('\n') >= 0) numLinesEst++;
|
|
return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
|
|
}, 0);
|
|
|
|
if (length > 60) {
|
|
return braces[0] +
|
|
(base === '' ? '' : base + '\n ') +
|
|
' ' +
|
|
output.join(',\n ') +
|
|
' ' +
|
|
braces[1];
|
|
}
|
|
|
|
return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
|
|
}
|
|
|
|
|
|
// NOTE: These type checking functions intentionally don't use `instanceof`
|
|
// because it is fragile and can be easily faked with `Object.create()`.
|
|
function isArray(ar) {
|
|
return Array.isArray(ar);
|
|
}
|
|
exports.isArray = isArray;
|
|
|
|
function isBoolean(arg) {
|
|
return typeof arg === 'boolean';
|
|
}
|
|
exports.isBoolean = isBoolean;
|
|
|
|
function isNull(arg) {
|
|
return arg === null;
|
|
}
|
|
exports.isNull = isNull;
|
|
|
|
function isNullOrUndefined(arg) {
|
|
return arg == null;
|
|
}
|
|
exports.isNullOrUndefined = isNullOrUndefined;
|
|
|
|
function isNumber(arg) {
|
|
return typeof arg === 'number';
|
|
}
|
|
exports.isNumber = isNumber;
|
|
|
|
function isString(arg) {
|
|
return typeof arg === 'string';
|
|
}
|
|
exports.isString = isString;
|
|
|
|
function isSymbol(arg) {
|
|
return typeof arg === 'symbol';
|
|
}
|
|
exports.isSymbol = isSymbol;
|
|
|
|
function isUndefined(arg) {
|
|
return arg === void 0;
|
|
}
|
|
exports.isUndefined = isUndefined;
|
|
|
|
function isRegExp(re) {
|
|
return isObject(re) && objectToString(re) === '[object RegExp]';
|
|
}
|
|
exports.isRegExp = isRegExp;
|
|
|
|
function isObject(arg) {
|
|
return typeof arg === 'object' && arg !== null;
|
|
}
|
|
exports.isObject = isObject;
|
|
|
|
function isDate(d) {
|
|
return isObject(d) && objectToString(d) === '[object Date]';
|
|
}
|
|
exports.isDate = isDate;
|
|
|
|
function isError(e) {
|
|
return isObject(e) &&
|
|
(objectToString(e) === '[object Error]' || e instanceof Error);
|
|
}
|
|
exports.isError = isError;
|
|
|
|
function isFunction(arg) {
|
|
return typeof arg === 'function';
|
|
}
|
|
exports.isFunction = isFunction;
|
|
|
|
function isPrimitive(arg) {
|
|
return arg === null ||
|
|
typeof arg === 'boolean' ||
|
|
typeof arg === 'number' ||
|
|
typeof arg === 'string' ||
|
|
typeof arg === 'symbol' || // ES6 symbol
|
|
typeof arg === 'undefined';
|
|
}
|
|
exports.isPrimitive = isPrimitive;
|
|
|
|
exports.isBuffer = _dereq_('./support/isBuffer');
|
|
|
|
function objectToString(o) {
|
|
return Object.prototype.toString.call(o);
|
|
}
|
|
|
|
|
|
function pad(n) {
|
|
return n < 10 ? '0' + n.toString(10) : n.toString(10);
|
|
}
|
|
|
|
|
|
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
|
|
'Oct', 'Nov', 'Dec'];
|
|
|
|
// 26 Feb 16:19:34
|
|
function timestamp() {
|
|
var d = new Date();
|
|
var time = [pad(d.getHours()),
|
|
pad(d.getMinutes()),
|
|
pad(d.getSeconds())].join(':');
|
|
return [d.getDate(), months[d.getMonth()], time].join(' ');
|
|
}
|
|
|
|
|
|
// log is just a thin wrapper to console.log that prepends a timestamp
|
|
exports.log = function() {
|
|
console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
|
|
};
|
|
|
|
|
|
/**
|
|
* Inherit the prototype methods from one constructor into another.
|
|
*
|
|
* The Function.prototype.inherits from lang.js rewritten as a standalone
|
|
* function (not on Function.prototype). NOTE: If this file is to be loaded
|
|
* during bootstrapping this function needs to be rewritten using some native
|
|
* functions as prototype setup using normal JavaScript does not work as
|
|
* expected during bootstrapping (see mirror.js in r114903).
|
|
*
|
|
* @param {function} ctor Constructor function which needs to inherit the
|
|
* prototype.
|
|
* @param {function} superCtor Constructor function to inherit prototype from.
|
|
*/
|
|
exports.inherits = _dereq_('inherits');
|
|
|
|
exports._extend = function(origin, add) {
|
|
// Don't do anything if add isn't an object
|
|
if (!add || !isObject(add)) return origin;
|
|
|
|
var keys = Object.keys(add);
|
|
var i = keys.length;
|
|
while (i--) {
|
|
origin[keys[i]] = add[keys[i]];
|
|
}
|
|
return origin;
|
|
};
|
|
|
|
function hasOwnProperty(obj, prop) {
|
|
return Object.prototype.hasOwnProperty.call(obj, prop);
|
|
}
|
|
|
|
}).call(this,_dereq_("C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js"),typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
|
|
},{"./support/isBuffer":158,"C:\\Users\\Alex\\AppData\\Roaming\\npm\\node_modules\\browserify\\node_modules\\insert-module-globals\\node_modules\\process\\browser.js":144,"inherits":143}]},{},[1])
|
|
(1)
|
|
});
|