mirror of
https://github.com/orbitdb/orbitdb.git
synced 2025-05-22 06:46:38 +00:00
36775 lines
1.0 MiB
36775 lines
1.0 MiB
var OrbitDB =
|
||
/******/ (function(modules) { // webpackBootstrap
|
||
/******/ // The module cache
|
||
/******/ var installedModules = {};
|
||
|
||
/******/ // The require function
|
||
/******/ function __webpack_require__(moduleId) {
|
||
|
||
/******/ // Check if module is in cache
|
||
/******/ if(installedModules[moduleId])
|
||
/******/ return installedModules[moduleId].exports;
|
||
|
||
/******/ // Create a new module (and put it into the cache)
|
||
/******/ var module = installedModules[moduleId] = {
|
||
/******/ exports: {},
|
||
/******/ id: moduleId,
|
||
/******/ loaded: false
|
||
/******/ };
|
||
|
||
/******/ // Execute the module function
|
||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||
|
||
/******/ // Flag the module as loaded
|
||
/******/ module.loaded = true;
|
||
|
||
/******/ // Return the exports of the module
|
||
/******/ return module.exports;
|
||
/******/ }
|
||
|
||
|
||
/******/ // expose the modules object (__webpack_modules__)
|
||
/******/ __webpack_require__.m = modules;
|
||
|
||
/******/ // expose the module cache
|
||
/******/ __webpack_require__.c = installedModules;
|
||
|
||
/******/ // __webpack_public_path__
|
||
/******/ __webpack_require__.p = "";
|
||
|
||
/******/ // Load entry module and return exports
|
||
/******/ return __webpack_require__(0);
|
||
/******/ })
|
||
/************************************************************************/
|
||
/******/ ([
|
||
/* 0 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _promise = __webpack_require__(1);
|
||
|
||
var _promise2 = _interopRequireDefault(_promise);
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _createClass2 = __webpack_require__(57);
|
||
|
||
var _createClass3 = _interopRequireDefault(_createClass2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var EventEmitter = __webpack_require__(60).EventEmitter;
|
||
var logger = __webpack_require__(61).create("orbit-db.Client");
|
||
var PubSub = __webpack_require__(65);
|
||
var CounterStore = __webpack_require__(118);
|
||
var KeyValueStore = __webpack_require__(180);
|
||
var EventStore = __webpack_require__(182);
|
||
|
||
var Client = function () {
|
||
function Client(ipfs, options) {
|
||
(0, _classCallCheck3.default)(this, Client);
|
||
|
||
this._ipfs = ipfs;
|
||
this._pubsub = null;
|
||
this.user = null;
|
||
this.network = null;
|
||
this.events = new EventEmitter();
|
||
this.kvStore = new KeyValueStore(this._ipfs, options);
|
||
this.eventStore = new EventStore(this._ipfs, options);
|
||
this.counterStore = new CounterStore(this._ipfs, options);
|
||
}
|
||
|
||
(0, _createClass3.default)(Client, [{
|
||
key: 'eventlog',
|
||
value: function eventlog(dbname, subscribe) {
|
||
var _this = this;
|
||
|
||
var db = this.eventStore;
|
||
var api = {
|
||
iterator: function iterator(options) {
|
||
return db.iterator(dbname, options);
|
||
},
|
||
add: function add(data) {
|
||
return db.add(dbname, data);
|
||
},
|
||
del: function del(hash) {
|
||
return db.remove(dbname, hash);
|
||
},
|
||
delete: function _delete() {
|
||
return db.delete(dbname);
|
||
},
|
||
close: function close() {
|
||
return _this._pubsub.unsubscribe(dbname);
|
||
}
|
||
};
|
||
|
||
return this._subscribe(db, dbname, subscribe).then(function () {
|
||
return api;
|
||
});
|
||
}
|
||
}, {
|
||
key: 'kvstore',
|
||
value: function kvstore(dbname, subscribe) {
|
||
var _this2 = this;
|
||
|
||
var db = this.kvStore;
|
||
var api = {
|
||
put: function put(key, value) {
|
||
return db.put(dbname, key, value);
|
||
},
|
||
set: function set(key, value) {
|
||
return db.set(dbname, key, value);
|
||
}, // alias for put()
|
||
get: function get(key) {
|
||
return db.get(dbname, key);
|
||
},
|
||
del: function del(key) {
|
||
return db.del(dbname, key);
|
||
},
|
||
delete: function _delete() {
|
||
return db.delete(dbname);
|
||
},
|
||
close: function close() {
|
||
return _this2._pubsub.unsubscribe(dbname);
|
||
}
|
||
};
|
||
|
||
return this._subscribe(db, dbname, subscribe).then(function () {
|
||
return api;
|
||
});
|
||
}
|
||
}, {
|
||
key: 'counter',
|
||
value: function counter(dbname, subscribe) {
|
||
var _this3 = this;
|
||
|
||
var db = this.counterStore;
|
||
var api = {
|
||
value: function value() {
|
||
return db.query(dbname);
|
||
},
|
||
inc: function inc(amount) {
|
||
return db.inc(dbname, amount);
|
||
},
|
||
dec: function dec(amount) {
|
||
return console.log("dec() not implemented yet");
|
||
},
|
||
delete: function _delete() {
|
||
return db.delete(dbname);
|
||
},
|
||
close: function close() {
|
||
return _this3._pubsub.unsubscribe(dbname);
|
||
}
|
||
};
|
||
|
||
return this._subscribe(db, dbname, subscribe).then(function () {
|
||
return api;
|
||
});
|
||
}
|
||
}, {
|
||
key: 'disconnect',
|
||
value: function disconnect() {
|
||
this._pubsub.disconnect();
|
||
this._store = {};
|
||
this.user = null;
|
||
this.network = null;
|
||
}
|
||
}, {
|
||
key: '_subscribe',
|
||
value: function _subscribe(db, dbname, subscribe, callback) {
|
||
var _this4 = this;
|
||
|
||
if (subscribe === undefined) subscribe = true;
|
||
|
||
return db.use(dbname, this.user.username).then(function (events) {
|
||
events.on('readable', _this4._onSync.bind(_this4));
|
||
events.on('data', _this4._onWrite.bind(_this4));
|
||
events.on('load', _this4._onLoad.bind(_this4));
|
||
|
||
if (subscribe) _this4._pubsub.subscribe(dbname, '', _this4._onMessage.bind(_this4));
|
||
|
||
return;
|
||
});
|
||
}
|
||
}, {
|
||
key: '_onMessage',
|
||
value: function _onMessage(channel, message) {
|
||
[this.eventStore, this.kvStore, this.counterStore].forEach(function (db) {
|
||
db.sync(channel, message).catch(function (e) {
|
||
return logger.error(e.stack);
|
||
});
|
||
});
|
||
}
|
||
}, {
|
||
key: '_onWrite',
|
||
value: function _onWrite(channel, hash) {
|
||
this._pubsub.publish(channel, hash);
|
||
this.events.emit('data', channel, hash);
|
||
}
|
||
}, {
|
||
key: '_onSync',
|
||
value: function _onSync(channel, hash) {
|
||
this.events.emit('readable', channel, hash);
|
||
}
|
||
}, {
|
||
key: '_onLoad',
|
||
value: function _onLoad(channel, hash) {
|
||
this.events.emit('load', channel, hash);
|
||
}
|
||
}, {
|
||
key: '_connect',
|
||
value: function _connect(host, port, username, password, allowOffline) {
|
||
var _this5 = this;
|
||
|
||
return new _promise2.default(function (resolve, reject) {
|
||
if (allowOffline === undefined) allowOffline = false;
|
||
|
||
_this5._pubsub = new PubSub(_this5._ipfs);
|
||
_this5._pubsub.connect(host, port, username, password).then(function () {
|
||
logger.debug('Connected to Pubsub at \'' + host + ':' + port + '\'');
|
||
_this5.user = { username: username, id: username }; // TODO: user id from ipfs hash
|
||
_this5.network = { host: host, port: port, name: 'TODO: network name' };
|
||
resolve();
|
||
}).catch(function (e) {
|
||
logger.warn("Couldn't connect to Pubsub:", e.message);
|
||
if (!allowOffline) {
|
||
logger.debug("'allowOffline' set to false, terminating");
|
||
_this5._pubsub.disconnect();
|
||
reject(e);
|
||
return;
|
||
}
|
||
_this5.user = { username: username, id: username }; // TODO: user id from ipfs hash
|
||
_this5.network = { host: host, port: port, name: 'TODO: network name' };
|
||
resolve();
|
||
});
|
||
});
|
||
}
|
||
}]);
|
||
return Client;
|
||
}();
|
||
|
||
var OrbitClientFactory = function () {
|
||
function OrbitClientFactory() {
|
||
(0, _classCallCheck3.default)(this, OrbitClientFactory);
|
||
}
|
||
|
||
(0, _createClass3.default)(OrbitClientFactory, null, [{
|
||
key: 'connect',
|
||
value: function connect(host, port, username, password, ipfs, options) {
|
||
var createClient = function createClient(ipfs) {
|
||
return new _promise2.default(function (resolve, reject) {
|
||
var client = new Client(ipfs, options);
|
||
client._connect(host, port, username, password, options.allowOffline).then(function () {
|
||
return resolve(client);
|
||
}).catch(reject);
|
||
});
|
||
};
|
||
|
||
options = options ? options : {};
|
||
|
||
if (!ipfs) {
|
||
logger.error("IPFS instance not provided");
|
||
throw new Error("IPFS instance not provided");
|
||
}
|
||
|
||
return createClient(ipfs);
|
||
}
|
||
}]);
|
||
return OrbitClientFactory;
|
||
}();
|
||
|
||
module.exports = OrbitClientFactory;
|
||
|
||
/***/ },
|
||
/* 1 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = { "default": __webpack_require__(2), __esModule: true };
|
||
|
||
/***/ },
|
||
/* 2 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
__webpack_require__(3);
|
||
__webpack_require__(4);
|
||
__webpack_require__(28);
|
||
__webpack_require__(35);
|
||
module.exports = __webpack_require__(12).Promise;
|
||
|
||
/***/ },
|
||
/* 3 */
|
||
/***/ function(module, exports) {
|
||
|
||
|
||
|
||
/***/ },
|
||
/* 4 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
var $at = __webpack_require__(5)(true);
|
||
|
||
// 21.1.3.27 String.prototype[@@iterator]()
|
||
__webpack_require__(8)(String, 'String', function(iterated){
|
||
this._t = String(iterated); // target
|
||
this._i = 0; // next index
|
||
// 21.1.5.2.1 %StringIteratorPrototype%.next()
|
||
}, function(){
|
||
var O = this._t
|
||
, index = this._i
|
||
, point;
|
||
if(index >= O.length)return {value: undefined, done: true};
|
||
point = $at(O, index);
|
||
this._i += point.length;
|
||
return {value: point, done: false};
|
||
});
|
||
|
||
/***/ },
|
||
/* 5 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var toInteger = __webpack_require__(6)
|
||
, defined = __webpack_require__(7);
|
||
// true -> String#at
|
||
// false -> String#codePointAt
|
||
module.exports = function(TO_STRING){
|
||
return function(that, pos){
|
||
var s = String(defined(that))
|
||
, i = toInteger(pos)
|
||
, l = s.length
|
||
, a, b;
|
||
if(i < 0 || i >= l)return TO_STRING ? '' : undefined;
|
||
a = s.charCodeAt(i);
|
||
return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff
|
||
? TO_STRING ? s.charAt(i) : a
|
||
: TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000;
|
||
};
|
||
};
|
||
|
||
/***/ },
|
||
/* 6 */
|
||
/***/ function(module, exports) {
|
||
|
||
// 7.1.4 ToInteger
|
||
var ceil = Math.ceil
|
||
, floor = Math.floor;
|
||
module.exports = function(it){
|
||
return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it);
|
||
};
|
||
|
||
/***/ },
|
||
/* 7 */
|
||
/***/ function(module, exports) {
|
||
|
||
// 7.2.1 RequireObjectCoercible(argument)
|
||
module.exports = function(it){
|
||
if(it == undefined)throw TypeError("Can't call method on " + it);
|
||
return it;
|
||
};
|
||
|
||
/***/ },
|
||
/* 8 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
var LIBRARY = __webpack_require__(9)
|
||
, $export = __webpack_require__(10)
|
||
, redefine = __webpack_require__(15)
|
||
, hide = __webpack_require__(16)
|
||
, has = __webpack_require__(21)
|
||
, Iterators = __webpack_require__(22)
|
||
, $iterCreate = __webpack_require__(23)
|
||
, setToStringTag = __webpack_require__(24)
|
||
, getProto = __webpack_require__(17).getProto
|
||
, ITERATOR = __webpack_require__(25)('iterator')
|
||
, BUGGY = !([].keys && 'next' in [].keys()) // Safari has buggy iterators w/o `next`
|
||
, FF_ITERATOR = '@@iterator'
|
||
, KEYS = 'keys'
|
||
, VALUES = 'values';
|
||
|
||
var returnThis = function(){ return this; };
|
||
|
||
module.exports = function(Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED){
|
||
$iterCreate(Constructor, NAME, next);
|
||
var getMethod = function(kind){
|
||
if(!BUGGY && kind in proto)return proto[kind];
|
||
switch(kind){
|
||
case KEYS: return function keys(){ return new Constructor(this, kind); };
|
||
case VALUES: return function values(){ return new Constructor(this, kind); };
|
||
} return function entries(){ return new Constructor(this, kind); };
|
||
};
|
||
var TAG = NAME + ' Iterator'
|
||
, DEF_VALUES = DEFAULT == VALUES
|
||
, VALUES_BUG = false
|
||
, proto = Base.prototype
|
||
, $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT]
|
||
, $default = $native || getMethod(DEFAULT)
|
||
, methods, key;
|
||
// Fix native
|
||
if($native){
|
||
var IteratorPrototype = getProto($default.call(new Base));
|
||
// Set @@toStringTag to native iterators
|
||
setToStringTag(IteratorPrototype, TAG, true);
|
||
// FF fix
|
||
if(!LIBRARY && has(proto, FF_ITERATOR))hide(IteratorPrototype, ITERATOR, returnThis);
|
||
// fix Array#{values, @@iterator}.name in V8 / FF
|
||
if(DEF_VALUES && $native.name !== VALUES){
|
||
VALUES_BUG = true;
|
||
$default = function values(){ return $native.call(this); };
|
||
}
|
||
}
|
||
// Define iterator
|
||
if((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])){
|
||
hide(proto, ITERATOR, $default);
|
||
}
|
||
// Plug for library
|
||
Iterators[NAME] = $default;
|
||
Iterators[TAG] = returnThis;
|
||
if(DEFAULT){
|
||
methods = {
|
||
values: DEF_VALUES ? $default : getMethod(VALUES),
|
||
keys: IS_SET ? $default : getMethod(KEYS),
|
||
entries: !DEF_VALUES ? $default : getMethod('entries')
|
||
};
|
||
if(FORCED)for(key in methods){
|
||
if(!(key in proto))redefine(proto, key, methods[key]);
|
||
} else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods);
|
||
}
|
||
return methods;
|
||
};
|
||
|
||
/***/ },
|
||
/* 9 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = true;
|
||
|
||
/***/ },
|
||
/* 10 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var global = __webpack_require__(11)
|
||
, core = __webpack_require__(12)
|
||
, ctx = __webpack_require__(13)
|
||
, PROTOTYPE = 'prototype';
|
||
|
||
var $export = function(type, name, source){
|
||
var IS_FORCED = type & $export.F
|
||
, IS_GLOBAL = type & $export.G
|
||
, IS_STATIC = type & $export.S
|
||
, IS_PROTO = type & $export.P
|
||
, IS_BIND = type & $export.B
|
||
, IS_WRAP = type & $export.W
|
||
, exports = IS_GLOBAL ? core : core[name] || (core[name] = {})
|
||
, target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE]
|
||
, key, own, out;
|
||
if(IS_GLOBAL)source = name;
|
||
for(key in source){
|
||
// contains in native
|
||
own = !IS_FORCED && target && key in target;
|
||
if(own && key in exports)continue;
|
||
// export native or passed
|
||
out = own ? target[key] : source[key];
|
||
// prevent global pollution for namespaces
|
||
exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key]
|
||
// bind timers to global for call from export context
|
||
: IS_BIND && own ? ctx(out, global)
|
||
// wrap global constructors for prevent change them in library
|
||
: IS_WRAP && target[key] == out ? (function(C){
|
||
var F = function(param){
|
||
return this instanceof C ? new C(param) : C(param);
|
||
};
|
||
F[PROTOTYPE] = C[PROTOTYPE];
|
||
return F;
|
||
// make static versions for prototype methods
|
||
})(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out;
|
||
if(IS_PROTO)(exports[PROTOTYPE] || (exports[PROTOTYPE] = {}))[key] = out;
|
||
}
|
||
};
|
||
// type bitmap
|
||
$export.F = 1; // forced
|
||
$export.G = 2; // global
|
||
$export.S = 4; // static
|
||
$export.P = 8; // proto
|
||
$export.B = 16; // bind
|
||
$export.W = 32; // wrap
|
||
module.exports = $export;
|
||
|
||
/***/ },
|
||
/* 11 */
|
||
/***/ function(module, exports) {
|
||
|
||
// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
|
||
var global = module.exports = typeof window != 'undefined' && window.Math == Math
|
||
? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')();
|
||
if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef
|
||
|
||
/***/ },
|
||
/* 12 */
|
||
/***/ function(module, exports) {
|
||
|
||
var core = module.exports = {version: '1.2.6'};
|
||
if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef
|
||
|
||
/***/ },
|
||
/* 13 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// optional / simple context binding
|
||
var aFunction = __webpack_require__(14);
|
||
module.exports = function(fn, that, length){
|
||
aFunction(fn);
|
||
if(that === undefined)return fn;
|
||
switch(length){
|
||
case 1: return function(a){
|
||
return fn.call(that, a);
|
||
};
|
||
case 2: return function(a, b){
|
||
return fn.call(that, a, b);
|
||
};
|
||
case 3: return function(a, b, c){
|
||
return fn.call(that, a, b, c);
|
||
};
|
||
}
|
||
return function(/* ...args */){
|
||
return fn.apply(that, arguments);
|
||
};
|
||
};
|
||
|
||
/***/ },
|
||
/* 14 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = function(it){
|
||
if(typeof it != 'function')throw TypeError(it + ' is not a function!');
|
||
return it;
|
||
};
|
||
|
||
/***/ },
|
||
/* 15 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = __webpack_require__(16);
|
||
|
||
/***/ },
|
||
/* 16 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var $ = __webpack_require__(17)
|
||
, createDesc = __webpack_require__(18);
|
||
module.exports = __webpack_require__(19) ? function(object, key, value){
|
||
return $.setDesc(object, key, createDesc(1, value));
|
||
} : function(object, key, value){
|
||
object[key] = value;
|
||
return object;
|
||
};
|
||
|
||
/***/ },
|
||
/* 17 */
|
||
/***/ function(module, exports) {
|
||
|
||
var $Object = Object;
|
||
module.exports = {
|
||
create: $Object.create,
|
||
getProto: $Object.getPrototypeOf,
|
||
isEnum: {}.propertyIsEnumerable,
|
||
getDesc: $Object.getOwnPropertyDescriptor,
|
||
setDesc: $Object.defineProperty,
|
||
setDescs: $Object.defineProperties,
|
||
getKeys: $Object.keys,
|
||
getNames: $Object.getOwnPropertyNames,
|
||
getSymbols: $Object.getOwnPropertySymbols,
|
||
each: [].forEach
|
||
};
|
||
|
||
/***/ },
|
||
/* 18 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = function(bitmap, value){
|
||
return {
|
||
enumerable : !(bitmap & 1),
|
||
configurable: !(bitmap & 2),
|
||
writable : !(bitmap & 4),
|
||
value : value
|
||
};
|
||
};
|
||
|
||
/***/ },
|
||
/* 19 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// Thank's IE8 for his funny defineProperty
|
||
module.exports = !__webpack_require__(20)(function(){
|
||
return Object.defineProperty({}, 'a', {get: function(){ return 7; }}).a != 7;
|
||
});
|
||
|
||
/***/ },
|
||
/* 20 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = function(exec){
|
||
try {
|
||
return !!exec();
|
||
} catch(e){
|
||
return true;
|
||
}
|
||
};
|
||
|
||
/***/ },
|
||
/* 21 */
|
||
/***/ function(module, exports) {
|
||
|
||
var hasOwnProperty = {}.hasOwnProperty;
|
||
module.exports = function(it, key){
|
||
return hasOwnProperty.call(it, key);
|
||
};
|
||
|
||
/***/ },
|
||
/* 22 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = {};
|
||
|
||
/***/ },
|
||
/* 23 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
var $ = __webpack_require__(17)
|
||
, descriptor = __webpack_require__(18)
|
||
, setToStringTag = __webpack_require__(24)
|
||
, IteratorPrototype = {};
|
||
|
||
// 25.1.2.1.1 %IteratorPrototype%[@@iterator]()
|
||
__webpack_require__(16)(IteratorPrototype, __webpack_require__(25)('iterator'), function(){ return this; });
|
||
|
||
module.exports = function(Constructor, NAME, next){
|
||
Constructor.prototype = $.create(IteratorPrototype, {next: descriptor(1, next)});
|
||
setToStringTag(Constructor, NAME + ' Iterator');
|
||
};
|
||
|
||
/***/ },
|
||
/* 24 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var def = __webpack_require__(17).setDesc
|
||
, has = __webpack_require__(21)
|
||
, TAG = __webpack_require__(25)('toStringTag');
|
||
|
||
module.exports = function(it, tag, stat){
|
||
if(it && !has(it = stat ? it : it.prototype, TAG))def(it, TAG, {configurable: true, value: tag});
|
||
};
|
||
|
||
/***/ },
|
||
/* 25 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var store = __webpack_require__(26)('wks')
|
||
, uid = __webpack_require__(27)
|
||
, Symbol = __webpack_require__(11).Symbol;
|
||
module.exports = function(name){
|
||
return store[name] || (store[name] =
|
||
Symbol && Symbol[name] || (Symbol || uid)('Symbol.' + name));
|
||
};
|
||
|
||
/***/ },
|
||
/* 26 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var global = __webpack_require__(11)
|
||
, SHARED = '__core-js_shared__'
|
||
, store = global[SHARED] || (global[SHARED] = {});
|
||
module.exports = function(key){
|
||
return store[key] || (store[key] = {});
|
||
};
|
||
|
||
/***/ },
|
||
/* 27 */
|
||
/***/ function(module, exports) {
|
||
|
||
var id = 0
|
||
, px = Math.random();
|
||
module.exports = function(key){
|
||
return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36));
|
||
};
|
||
|
||
/***/ },
|
||
/* 28 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
__webpack_require__(29);
|
||
var Iterators = __webpack_require__(22);
|
||
Iterators.NodeList = Iterators.HTMLCollection = Iterators.Array;
|
||
|
||
/***/ },
|
||
/* 29 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
var addToUnscopables = __webpack_require__(30)
|
||
, step = __webpack_require__(31)
|
||
, Iterators = __webpack_require__(22)
|
||
, toIObject = __webpack_require__(32);
|
||
|
||
// 22.1.3.4 Array.prototype.entries()
|
||
// 22.1.3.13 Array.prototype.keys()
|
||
// 22.1.3.29 Array.prototype.values()
|
||
// 22.1.3.30 Array.prototype[@@iterator]()
|
||
module.exports = __webpack_require__(8)(Array, 'Array', function(iterated, kind){
|
||
this._t = toIObject(iterated); // target
|
||
this._i = 0; // next index
|
||
this._k = kind; // kind
|
||
// 22.1.5.2.1 %ArrayIteratorPrototype%.next()
|
||
}, function(){
|
||
var O = this._t
|
||
, kind = this._k
|
||
, index = this._i++;
|
||
if(!O || index >= O.length){
|
||
this._t = undefined;
|
||
return step(1);
|
||
}
|
||
if(kind == 'keys' )return step(0, index);
|
||
if(kind == 'values')return step(0, O[index]);
|
||
return step(0, [index, O[index]]);
|
||
}, 'values');
|
||
|
||
// argumentsList[@@iterator] is %ArrayProto_values% (9.4.4.6, 9.4.4.7)
|
||
Iterators.Arguments = Iterators.Array;
|
||
|
||
addToUnscopables('keys');
|
||
addToUnscopables('values');
|
||
addToUnscopables('entries');
|
||
|
||
/***/ },
|
||
/* 30 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = function(){ /* empty */ };
|
||
|
||
/***/ },
|
||
/* 31 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = function(done, value){
|
||
return {value: value, done: !!done};
|
||
};
|
||
|
||
/***/ },
|
||
/* 32 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// to indexed object, toObject with fallback for non-array-like ES3 strings
|
||
var IObject = __webpack_require__(33)
|
||
, defined = __webpack_require__(7);
|
||
module.exports = function(it){
|
||
return IObject(defined(it));
|
||
};
|
||
|
||
/***/ },
|
||
/* 33 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// fallback for non-array-like ES3 and non-enumerable old V8 strings
|
||
var cof = __webpack_require__(34);
|
||
module.exports = Object('z').propertyIsEnumerable(0) ? Object : function(it){
|
||
return cof(it) == 'String' ? it.split('') : Object(it);
|
||
};
|
||
|
||
/***/ },
|
||
/* 34 */
|
||
/***/ function(module, exports) {
|
||
|
||
var toString = {}.toString;
|
||
|
||
module.exports = function(it){
|
||
return toString.call(it).slice(8, -1);
|
||
};
|
||
|
||
/***/ },
|
||
/* 35 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
var $ = __webpack_require__(17)
|
||
, LIBRARY = __webpack_require__(9)
|
||
, global = __webpack_require__(11)
|
||
, ctx = __webpack_require__(13)
|
||
, classof = __webpack_require__(36)
|
||
, $export = __webpack_require__(10)
|
||
, isObject = __webpack_require__(37)
|
||
, anObject = __webpack_require__(38)
|
||
, aFunction = __webpack_require__(14)
|
||
, strictNew = __webpack_require__(39)
|
||
, forOf = __webpack_require__(40)
|
||
, setProto = __webpack_require__(45).set
|
||
, same = __webpack_require__(46)
|
||
, SPECIES = __webpack_require__(25)('species')
|
||
, speciesConstructor = __webpack_require__(47)
|
||
, asap = __webpack_require__(48)
|
||
, PROMISE = 'Promise'
|
||
, process = global.process
|
||
, isNode = classof(process) == 'process'
|
||
, P = global[PROMISE]
|
||
, Wrapper;
|
||
|
||
var testResolve = function(sub){
|
||
var test = new P(function(){});
|
||
if(sub)test.constructor = Object;
|
||
return P.resolve(test) === test;
|
||
};
|
||
|
||
var USE_NATIVE = function(){
|
||
var works = false;
|
||
function P2(x){
|
||
var self = new P(x);
|
||
setProto(self, P2.prototype);
|
||
return self;
|
||
}
|
||
try {
|
||
works = P && P.resolve && testResolve();
|
||
setProto(P2, P);
|
||
P2.prototype = $.create(P.prototype, {constructor: {value: P2}});
|
||
// actual Firefox has broken subclass support, test that
|
||
if(!(P2.resolve(5).then(function(){}) instanceof P2)){
|
||
works = false;
|
||
}
|
||
// actual V8 bug, https://code.google.com/p/v8/issues/detail?id=4162
|
||
if(works && __webpack_require__(19)){
|
||
var thenableThenGotten = false;
|
||
P.resolve($.setDesc({}, 'then', {
|
||
get: function(){ thenableThenGotten = true; }
|
||
}));
|
||
works = thenableThenGotten;
|
||
}
|
||
} catch(e){ works = false; }
|
||
return works;
|
||
}();
|
||
|
||
// helpers
|
||
var sameConstructor = function(a, b){
|
||
// library wrapper special case
|
||
if(LIBRARY && a === P && b === Wrapper)return true;
|
||
return same(a, b);
|
||
};
|
||
var getConstructor = function(C){
|
||
var S = anObject(C)[SPECIES];
|
||
return S != undefined ? S : C;
|
||
};
|
||
var isThenable = function(it){
|
||
var then;
|
||
return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
|
||
};
|
||
var PromiseCapability = function(C){
|
||
var resolve, reject;
|
||
this.promise = new C(function($$resolve, $$reject){
|
||
if(resolve !== undefined || reject !== undefined)throw TypeError('Bad Promise constructor');
|
||
resolve = $$resolve;
|
||
reject = $$reject;
|
||
});
|
||
this.resolve = aFunction(resolve),
|
||
this.reject = aFunction(reject)
|
||
};
|
||
var perform = function(exec){
|
||
try {
|
||
exec();
|
||
} catch(e){
|
||
return {error: e};
|
||
}
|
||
};
|
||
var notify = function(record, isReject){
|
||
if(record.n)return;
|
||
record.n = true;
|
||
var chain = record.c;
|
||
asap(function(){
|
||
var value = record.v
|
||
, ok = record.s == 1
|
||
, i = 0;
|
||
var run = function(reaction){
|
||
var handler = ok ? reaction.ok : reaction.fail
|
||
, resolve = reaction.resolve
|
||
, reject = reaction.reject
|
||
, result, then;
|
||
try {
|
||
if(handler){
|
||
if(!ok)record.h = true;
|
||
result = handler === true ? value : handler(value);
|
||
if(result === reaction.promise){
|
||
reject(TypeError('Promise-chain cycle'));
|
||
} else if(then = isThenable(result)){
|
||
then.call(result, resolve, reject);
|
||
} else resolve(result);
|
||
} else reject(value);
|
||
} catch(e){
|
||
reject(e);
|
||
}
|
||
};
|
||
while(chain.length > i)run(chain[i++]); // variable length - can't use forEach
|
||
chain.length = 0;
|
||
record.n = false;
|
||
if(isReject)setTimeout(function(){
|
||
var promise = record.p
|
||
, handler, console;
|
||
if(isUnhandled(promise)){
|
||
if(isNode){
|
||
process.emit('unhandledRejection', value, promise);
|
||
} else if(handler = global.onunhandledrejection){
|
||
handler({promise: promise, reason: value});
|
||
} else if((console = global.console) && console.error){
|
||
console.error('Unhandled promise rejection', value);
|
||
}
|
||
} record.a = undefined;
|
||
}, 1);
|
||
});
|
||
};
|
||
var isUnhandled = function(promise){
|
||
var record = promise._d
|
||
, chain = record.a || record.c
|
||
, i = 0
|
||
, reaction;
|
||
if(record.h)return false;
|
||
while(chain.length > i){
|
||
reaction = chain[i++];
|
||
if(reaction.fail || !isUnhandled(reaction.promise))return false;
|
||
} return true;
|
||
};
|
||
var $reject = function(value){
|
||
var record = this;
|
||
if(record.d)return;
|
||
record.d = true;
|
||
record = record.r || record; // unwrap
|
||
record.v = value;
|
||
record.s = 2;
|
||
record.a = record.c.slice();
|
||
notify(record, true);
|
||
};
|
||
var $resolve = function(value){
|
||
var record = this
|
||
, then;
|
||
if(record.d)return;
|
||
record.d = true;
|
||
record = record.r || record; // unwrap
|
||
try {
|
||
if(record.p === value)throw TypeError("Promise can't be resolved itself");
|
||
if(then = isThenable(value)){
|
||
asap(function(){
|
||
var wrapper = {r: record, d: false}; // wrap
|
||
try {
|
||
then.call(value, ctx($resolve, wrapper, 1), ctx($reject, wrapper, 1));
|
||
} catch(e){
|
||
$reject.call(wrapper, e);
|
||
}
|
||
});
|
||
} else {
|
||
record.v = value;
|
||
record.s = 1;
|
||
notify(record, false);
|
||
}
|
||
} catch(e){
|
||
$reject.call({r: record, d: false}, e); // wrap
|
||
}
|
||
};
|
||
|
||
// constructor polyfill
|
||
if(!USE_NATIVE){
|
||
// 25.4.3.1 Promise(executor)
|
||
P = function Promise(executor){
|
||
aFunction(executor);
|
||
var record = this._d = {
|
||
p: strictNew(this, P, PROMISE), // <- promise
|
||
c: [], // <- awaiting reactions
|
||
a: undefined, // <- checked in isUnhandled reactions
|
||
s: 0, // <- state
|
||
d: false, // <- done
|
||
v: undefined, // <- value
|
||
h: false, // <- handled rejection
|
||
n: false // <- notify
|
||
};
|
||
try {
|
||
executor(ctx($resolve, record, 1), ctx($reject, record, 1));
|
||
} catch(err){
|
||
$reject.call(record, err);
|
||
}
|
||
};
|
||
__webpack_require__(53)(P.prototype, {
|
||
// 25.4.5.3 Promise.prototype.then(onFulfilled, onRejected)
|
||
then: function then(onFulfilled, onRejected){
|
||
var reaction = new PromiseCapability(speciesConstructor(this, P))
|
||
, promise = reaction.promise
|
||
, record = this._d;
|
||
reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
|
||
reaction.fail = typeof onRejected == 'function' && onRejected;
|
||
record.c.push(reaction);
|
||
if(record.a)record.a.push(reaction);
|
||
if(record.s)notify(record, false);
|
||
return promise;
|
||
},
|
||
// 25.4.5.1 Promise.prototype.catch(onRejected)
|
||
'catch': function(onRejected){
|
||
return this.then(undefined, onRejected);
|
||
}
|
||
});
|
||
}
|
||
|
||
$export($export.G + $export.W + $export.F * !USE_NATIVE, {Promise: P});
|
||
__webpack_require__(24)(P, PROMISE);
|
||
__webpack_require__(54)(PROMISE);
|
||
Wrapper = __webpack_require__(12)[PROMISE];
|
||
|
||
// statics
|
||
$export($export.S + $export.F * !USE_NATIVE, PROMISE, {
|
||
// 25.4.4.5 Promise.reject(r)
|
||
reject: function reject(r){
|
||
var capability = new PromiseCapability(this)
|
||
, $$reject = capability.reject;
|
||
$$reject(r);
|
||
return capability.promise;
|
||
}
|
||
});
|
||
$export($export.S + $export.F * (!USE_NATIVE || testResolve(true)), PROMISE, {
|
||
// 25.4.4.6 Promise.resolve(x)
|
||
resolve: function resolve(x){
|
||
// instanceof instead of internal slot check because we should fix it without replacement native Promise core
|
||
if(x instanceof P && sameConstructor(x.constructor, this))return x;
|
||
var capability = new PromiseCapability(this)
|
||
, $$resolve = capability.resolve;
|
||
$$resolve(x);
|
||
return capability.promise;
|
||
}
|
||
});
|
||
$export($export.S + $export.F * !(USE_NATIVE && __webpack_require__(55)(function(iter){
|
||
P.all(iter)['catch'](function(){});
|
||
})), PROMISE, {
|
||
// 25.4.4.1 Promise.all(iterable)
|
||
all: function all(iterable){
|
||
var C = getConstructor(this)
|
||
, capability = new PromiseCapability(C)
|
||
, resolve = capability.resolve
|
||
, reject = capability.reject
|
||
, values = [];
|
||
var abrupt = perform(function(){
|
||
forOf(iterable, false, values.push, values);
|
||
var remaining = values.length
|
||
, results = Array(remaining);
|
||
if(remaining)$.each.call(values, function(promise, index){
|
||
var alreadyCalled = false;
|
||
C.resolve(promise).then(function(value){
|
||
if(alreadyCalled)return;
|
||
alreadyCalled = true;
|
||
results[index] = value;
|
||
--remaining || resolve(results);
|
||
}, reject);
|
||
});
|
||
else resolve(results);
|
||
});
|
||
if(abrupt)reject(abrupt.error);
|
||
return capability.promise;
|
||
},
|
||
// 25.4.4.4 Promise.race(iterable)
|
||
race: function race(iterable){
|
||
var C = getConstructor(this)
|
||
, capability = new PromiseCapability(C)
|
||
, reject = capability.reject;
|
||
var abrupt = perform(function(){
|
||
forOf(iterable, false, function(promise){
|
||
C.resolve(promise).then(capability.resolve, reject);
|
||
});
|
||
});
|
||
if(abrupt)reject(abrupt.error);
|
||
return capability.promise;
|
||
}
|
||
});
|
||
|
||
/***/ },
|
||
/* 36 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// getting tag from 19.1.3.6 Object.prototype.toString()
|
||
var cof = __webpack_require__(34)
|
||
, TAG = __webpack_require__(25)('toStringTag')
|
||
// ES3 wrong here
|
||
, ARG = cof(function(){ return arguments; }()) == 'Arguments';
|
||
|
||
module.exports = function(it){
|
||
var O, T, B;
|
||
return it === undefined ? 'Undefined' : it === null ? 'Null'
|
||
// @@toStringTag case
|
||
: typeof (T = (O = Object(it))[TAG]) == 'string' ? T
|
||
// builtinTag case
|
||
: ARG ? cof(O)
|
||
// ES3 arguments fallback
|
||
: (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B;
|
||
};
|
||
|
||
/***/ },
|
||
/* 37 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = function(it){
|
||
return typeof it === 'object' ? it !== null : typeof it === 'function';
|
||
};
|
||
|
||
/***/ },
|
||
/* 38 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var isObject = __webpack_require__(37);
|
||
module.exports = function(it){
|
||
if(!isObject(it))throw TypeError(it + ' is not an object!');
|
||
return it;
|
||
};
|
||
|
||
/***/ },
|
||
/* 39 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = function(it, Constructor, name){
|
||
if(!(it instanceof Constructor))throw TypeError(name + ": use the 'new' operator!");
|
||
return it;
|
||
};
|
||
|
||
/***/ },
|
||
/* 40 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var ctx = __webpack_require__(13)
|
||
, call = __webpack_require__(41)
|
||
, isArrayIter = __webpack_require__(42)
|
||
, anObject = __webpack_require__(38)
|
||
, toLength = __webpack_require__(43)
|
||
, getIterFn = __webpack_require__(44);
|
||
module.exports = function(iterable, entries, fn, that){
|
||
var iterFn = getIterFn(iterable)
|
||
, f = ctx(fn, that, entries ? 2 : 1)
|
||
, index = 0
|
||
, length, step, iterator;
|
||
if(typeof iterFn != 'function')throw TypeError(iterable + ' is not iterable!');
|
||
// fast case for arrays with default iterator
|
||
if(isArrayIter(iterFn))for(length = toLength(iterable.length); length > index; index++){
|
||
entries ? f(anObject(step = iterable[index])[0], step[1]) : f(iterable[index]);
|
||
} else for(iterator = iterFn.call(iterable); !(step = iterator.next()).done; ){
|
||
call(iterator, f, step.value, entries);
|
||
}
|
||
};
|
||
|
||
/***/ },
|
||
/* 41 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// call something on iterator step with safe closing on error
|
||
var anObject = __webpack_require__(38);
|
||
module.exports = function(iterator, fn, value, entries){
|
||
try {
|
||
return entries ? fn(anObject(value)[0], value[1]) : fn(value);
|
||
// 7.4.6 IteratorClose(iterator, completion)
|
||
} catch(e){
|
||
var ret = iterator['return'];
|
||
if(ret !== undefined)anObject(ret.call(iterator));
|
||
throw e;
|
||
}
|
||
};
|
||
|
||
/***/ },
|
||
/* 42 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// check on default Array iterator
|
||
var Iterators = __webpack_require__(22)
|
||
, ITERATOR = __webpack_require__(25)('iterator')
|
||
, ArrayProto = Array.prototype;
|
||
|
||
module.exports = function(it){
|
||
return it !== undefined && (Iterators.Array === it || ArrayProto[ITERATOR] === it);
|
||
};
|
||
|
||
/***/ },
|
||
/* 43 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// 7.1.15 ToLength
|
||
var toInteger = __webpack_require__(6)
|
||
, min = Math.min;
|
||
module.exports = function(it){
|
||
return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991
|
||
};
|
||
|
||
/***/ },
|
||
/* 44 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var classof = __webpack_require__(36)
|
||
, ITERATOR = __webpack_require__(25)('iterator')
|
||
, Iterators = __webpack_require__(22);
|
||
module.exports = __webpack_require__(12).getIteratorMethod = function(it){
|
||
if(it != undefined)return it[ITERATOR]
|
||
|| it['@@iterator']
|
||
|| Iterators[classof(it)];
|
||
};
|
||
|
||
/***/ },
|
||
/* 45 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// Works with __proto__ only. Old v8 can't work with null proto objects.
|
||
/* eslint-disable no-proto */
|
||
var getDesc = __webpack_require__(17).getDesc
|
||
, isObject = __webpack_require__(37)
|
||
, anObject = __webpack_require__(38);
|
||
var check = function(O, proto){
|
||
anObject(O);
|
||
if(!isObject(proto) && proto !== null)throw TypeError(proto + ": can't set as prototype!");
|
||
};
|
||
module.exports = {
|
||
set: Object.setPrototypeOf || ('__proto__' in {} ? // eslint-disable-line
|
||
function(test, buggy, set){
|
||
try {
|
||
set = __webpack_require__(13)(Function.call, getDesc(Object.prototype, '__proto__').set, 2);
|
||
set(test, []);
|
||
buggy = !(test instanceof Array);
|
||
} catch(e){ buggy = true; }
|
||
return function setPrototypeOf(O, proto){
|
||
check(O, proto);
|
||
if(buggy)O.__proto__ = proto;
|
||
else set(O, proto);
|
||
return O;
|
||
};
|
||
}({}, false) : undefined),
|
||
check: check
|
||
};
|
||
|
||
/***/ },
|
||
/* 46 */
|
||
/***/ function(module, exports) {
|
||
|
||
// 7.2.9 SameValue(x, y)
|
||
module.exports = Object.is || function is(x, y){
|
||
return x === y ? x !== 0 || 1 / x === 1 / y : x != x && y != y;
|
||
};
|
||
|
||
/***/ },
|
||
/* 47 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// 7.3.20 SpeciesConstructor(O, defaultConstructor)
|
||
var anObject = __webpack_require__(38)
|
||
, aFunction = __webpack_require__(14)
|
||
, SPECIES = __webpack_require__(25)('species');
|
||
module.exports = function(O, D){
|
||
var C = anObject(O).constructor, S;
|
||
return C === undefined || (S = anObject(C)[SPECIES]) == undefined ? D : aFunction(S);
|
||
};
|
||
|
||
/***/ },
|
||
/* 48 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var global = __webpack_require__(11)
|
||
, macrotask = __webpack_require__(49).set
|
||
, Observer = global.MutationObserver || global.WebKitMutationObserver
|
||
, process = global.process
|
||
, Promise = global.Promise
|
||
, isNode = __webpack_require__(34)(process) == 'process'
|
||
, head, last, notify;
|
||
|
||
var flush = function(){
|
||
var parent, domain, fn;
|
||
if(isNode && (parent = process.domain)){
|
||
process.domain = null;
|
||
parent.exit();
|
||
}
|
||
while(head){
|
||
domain = head.domain;
|
||
fn = head.fn;
|
||
if(domain)domain.enter();
|
||
fn(); // <- currently we use it only for Promise - try / catch not required
|
||
if(domain)domain.exit();
|
||
head = head.next;
|
||
} last = undefined;
|
||
if(parent)parent.enter();
|
||
};
|
||
|
||
// Node.js
|
||
if(isNode){
|
||
notify = function(){
|
||
process.nextTick(flush);
|
||
};
|
||
// browsers with MutationObserver
|
||
} else if(Observer){
|
||
var toggle = 1
|
||
, node = document.createTextNode('');
|
||
new Observer(flush).observe(node, {characterData: true}); // eslint-disable-line no-new
|
||
notify = function(){
|
||
node.data = toggle = -toggle;
|
||
};
|
||
// environments with maybe non-completely correct, but existent Promise
|
||
} else if(Promise && Promise.resolve){
|
||
notify = function(){
|
||
Promise.resolve().then(flush);
|
||
};
|
||
// for other environments - macrotask based on:
|
||
// - setImmediate
|
||
// - MessageChannel
|
||
// - window.postMessag
|
||
// - onreadystatechange
|
||
// - setTimeout
|
||
} else {
|
||
notify = function(){
|
||
// strange IE + webpack dev server bug - use .call(global)
|
||
macrotask.call(global, flush);
|
||
};
|
||
}
|
||
|
||
module.exports = function asap(fn){
|
||
var task = {fn: fn, next: undefined, domain: isNode && process.domain};
|
||
if(last)last.next = task;
|
||
if(!head){
|
||
head = task;
|
||
notify();
|
||
} last = task;
|
||
};
|
||
|
||
/***/ },
|
||
/* 49 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var ctx = __webpack_require__(13)
|
||
, invoke = __webpack_require__(50)
|
||
, html = __webpack_require__(51)
|
||
, cel = __webpack_require__(52)
|
||
, global = __webpack_require__(11)
|
||
, process = global.process
|
||
, setTask = global.setImmediate
|
||
, clearTask = global.clearImmediate
|
||
, MessageChannel = global.MessageChannel
|
||
, counter = 0
|
||
, queue = {}
|
||
, ONREADYSTATECHANGE = 'onreadystatechange'
|
||
, defer, channel, port;
|
||
var run = function(){
|
||
var id = +this;
|
||
if(queue.hasOwnProperty(id)){
|
||
var fn = queue[id];
|
||
delete queue[id];
|
||
fn();
|
||
}
|
||
};
|
||
var listner = function(event){
|
||
run.call(event.data);
|
||
};
|
||
// Node.js 0.9+ & IE10+ has setImmediate, otherwise:
|
||
if(!setTask || !clearTask){
|
||
setTask = function setImmediate(fn){
|
||
var args = [], i = 1;
|
||
while(arguments.length > i)args.push(arguments[i++]);
|
||
queue[++counter] = function(){
|
||
invoke(typeof fn == 'function' ? fn : Function(fn), args);
|
||
};
|
||
defer(counter);
|
||
return counter;
|
||
};
|
||
clearTask = function clearImmediate(id){
|
||
delete queue[id];
|
||
};
|
||
// Node.js 0.8-
|
||
if(__webpack_require__(34)(process) == 'process'){
|
||
defer = function(id){
|
||
process.nextTick(ctx(run, id, 1));
|
||
};
|
||
// Browsers with MessageChannel, includes WebWorkers
|
||
} else if(MessageChannel){
|
||
channel = new MessageChannel;
|
||
port = channel.port2;
|
||
channel.port1.onmessage = listner;
|
||
defer = ctx(port.postMessage, port, 1);
|
||
// Browsers with postMessage, skip WebWorkers
|
||
// IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
|
||
} else if(global.addEventListener && typeof postMessage == 'function' && !global.importScripts){
|
||
defer = function(id){
|
||
global.postMessage(id + '', '*');
|
||
};
|
||
global.addEventListener('message', listner, false);
|
||
// IE8-
|
||
} else if(ONREADYSTATECHANGE in cel('script')){
|
||
defer = function(id){
|
||
html.appendChild(cel('script'))[ONREADYSTATECHANGE] = function(){
|
||
html.removeChild(this);
|
||
run.call(id);
|
||
};
|
||
};
|
||
// Rest old browsers
|
||
} else {
|
||
defer = function(id){
|
||
setTimeout(ctx(run, id, 1), 0);
|
||
};
|
||
}
|
||
}
|
||
module.exports = {
|
||
set: setTask,
|
||
clear: clearTask
|
||
};
|
||
|
||
/***/ },
|
||
/* 50 */
|
||
/***/ function(module, exports) {
|
||
|
||
// fast apply, http://jsperf.lnkit.com/fast-apply/5
|
||
module.exports = function(fn, args, that){
|
||
var un = that === undefined;
|
||
switch(args.length){
|
||
case 0: return un ? fn()
|
||
: fn.call(that);
|
||
case 1: return un ? fn(args[0])
|
||
: fn.call(that, args[0]);
|
||
case 2: return un ? fn(args[0], args[1])
|
||
: fn.call(that, args[0], args[1]);
|
||
case 3: return un ? fn(args[0], args[1], args[2])
|
||
: fn.call(that, args[0], args[1], args[2]);
|
||
case 4: return un ? fn(args[0], args[1], args[2], args[3])
|
||
: fn.call(that, args[0], args[1], args[2], args[3]);
|
||
} return fn.apply(that, args);
|
||
};
|
||
|
||
/***/ },
|
||
/* 51 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = __webpack_require__(11).document && document.documentElement;
|
||
|
||
/***/ },
|
||
/* 52 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var isObject = __webpack_require__(37)
|
||
, document = __webpack_require__(11).document
|
||
// in old IE typeof document.createElement is 'object'
|
||
, is = isObject(document) && isObject(document.createElement);
|
||
module.exports = function(it){
|
||
return is ? document.createElement(it) : {};
|
||
};
|
||
|
||
/***/ },
|
||
/* 53 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var redefine = __webpack_require__(15);
|
||
module.exports = function(target, src){
|
||
for(var key in src)redefine(target, key, src[key]);
|
||
return target;
|
||
};
|
||
|
||
/***/ },
|
||
/* 54 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
var core = __webpack_require__(12)
|
||
, $ = __webpack_require__(17)
|
||
, DESCRIPTORS = __webpack_require__(19)
|
||
, SPECIES = __webpack_require__(25)('species');
|
||
|
||
module.exports = function(KEY){
|
||
var C = core[KEY];
|
||
if(DESCRIPTORS && C && !C[SPECIES])$.setDesc(C, SPECIES, {
|
||
configurable: true,
|
||
get: function(){ return this; }
|
||
});
|
||
};
|
||
|
||
/***/ },
|
||
/* 55 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var ITERATOR = __webpack_require__(25)('iterator')
|
||
, SAFE_CLOSING = false;
|
||
|
||
try {
|
||
var riter = [7][ITERATOR]();
|
||
riter['return'] = function(){ SAFE_CLOSING = true; };
|
||
Array.from(riter, function(){ throw 2; });
|
||
} catch(e){ /* empty */ }
|
||
|
||
module.exports = function(exec, skipClosing){
|
||
if(!skipClosing && !SAFE_CLOSING)return false;
|
||
var safe = false;
|
||
try {
|
||
var arr = [7]
|
||
, iter = arr[ITERATOR]();
|
||
iter.next = function(){ safe = true; };
|
||
arr[ITERATOR] = function(){ return iter; };
|
||
exec(arr);
|
||
} catch(e){ /* empty */ }
|
||
return safe;
|
||
};
|
||
|
||
/***/ },
|
||
/* 56 */
|
||
/***/ function(module, exports) {
|
||
|
||
"use strict";
|
||
|
||
exports.__esModule = true;
|
||
|
||
exports.default = function (instance, Constructor) {
|
||
if (!(instance instanceof Constructor)) {
|
||
throw new TypeError("Cannot call a class as a function");
|
||
}
|
||
};
|
||
|
||
/***/ },
|
||
/* 57 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
exports.__esModule = true;
|
||
|
||
var _defineProperty = __webpack_require__(58);
|
||
|
||
var _defineProperty2 = _interopRequireDefault(_defineProperty);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
exports.default = function () {
|
||
function defineProperties(target, props) {
|
||
for (var i = 0; i < props.length; i++) {
|
||
var descriptor = props[i];
|
||
descriptor.enumerable = descriptor.enumerable || false;
|
||
descriptor.configurable = true;
|
||
if ("value" in descriptor) descriptor.writable = true;
|
||
(0, _defineProperty2.default)(target, descriptor.key, descriptor);
|
||
}
|
||
}
|
||
|
||
return function (Constructor, protoProps, staticProps) {
|
||
if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
||
if (staticProps) defineProperties(Constructor, staticProps);
|
||
return Constructor;
|
||
};
|
||
}();
|
||
|
||
/***/ },
|
||
/* 58 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = { "default": __webpack_require__(59), __esModule: true };
|
||
|
||
/***/ },
|
||
/* 59 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var $ = __webpack_require__(17);
|
||
module.exports = function defineProperty(it, key, desc){
|
||
return $.setDesc(it, key, desc);
|
||
};
|
||
|
||
/***/ },
|
||
/* 60 */
|
||
/***/ function(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
|
||
}
|
||
throw TypeError('Uncaught, unspecified "error" event.');
|
||
}
|
||
}
|
||
|
||
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:
|
||
args = Array.prototype.slice.call(arguments, 1);
|
||
handler.apply(this, args);
|
||
}
|
||
} else if (isObject(handler)) {
|
||
args = Array.prototype.slice.call(arguments, 1);
|
||
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) {
|
||
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);
|
||
if (typeof console.trace === 'function') {
|
||
// not supported in IE 10
|
||
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 if (listeners) {
|
||
// 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.prototype.listenerCount = function(type) {
|
||
if (this._events) {
|
||
var evlistener = this._events[type];
|
||
|
||
if (isFunction(evlistener))
|
||
return 1;
|
||
else if (evlistener)
|
||
return evlistener.length;
|
||
}
|
||
return 0;
|
||
};
|
||
|
||
EventEmitter.listenerCount = function(emitter, type) {
|
||
return emitter.listenerCount(type);
|
||
};
|
||
|
||
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;
|
||
}
|
||
|
||
|
||
/***/ },
|
||
/* 61 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(process) {'use strict';
|
||
|
||
const fs = __webpack_require__(64);
|
||
|
||
let isNodejs = process.version ? true : false;
|
||
|
||
const LogLevels = {
|
||
'DEBUG': 'DEBUG',
|
||
'INFO': 'INFO',
|
||
'WARN': 'WARN',
|
||
'ERROR': 'ERROR',
|
||
'NONE': 'NONE',
|
||
};
|
||
|
||
// Global log level
|
||
let GlobalLogLevel = LogLevels.DEBUG;
|
||
|
||
// Global log file name
|
||
let GlobalLogfile = null;
|
||
|
||
// ANSI colors
|
||
let Colors = {
|
||
'Black': 0,
|
||
'Red': 1,
|
||
'Green': 2,
|
||
'Yellow': 3,
|
||
'Blue': 4,
|
||
'Magenta': 5,
|
||
'Cyan': 6,
|
||
'Grey': 7,
|
||
'White': 9,
|
||
'Default': 9,
|
||
};
|
||
|
||
// CSS colors
|
||
if(!isNodejs) {
|
||
Colors = {
|
||
'Black': 'Black',
|
||
'Red': 'IndianRed',
|
||
'Green': 'LimeGreen',
|
||
'Yellow': 'Orange',
|
||
'Blue': 'RoyalBlue',
|
||
'Magenta': 'Orchid',
|
||
'Cyan': 'SkyBlue',
|
||
'Grey': 'DimGrey',
|
||
'White': 'White',
|
||
'Default': 'Black',
|
||
};
|
||
}
|
||
|
||
const loglevelColors = [Colors.Cyan, Colors.Green, Colors.Yellow, Colors.Red, Colors.Default];
|
||
|
||
const defaultOptions = {
|
||
useColors: true,
|
||
color: Colors.Default,
|
||
showTimestamp: true,
|
||
showLevel: true,
|
||
filename: GlobalLogfile,
|
||
appendFile: true,
|
||
};
|
||
|
||
class Logger {
|
||
constructor(category, options) {
|
||
this.category = category;
|
||
let opts = {};
|
||
Object.assign(opts, defaultOptions);
|
||
Object.assign(opts, options);
|
||
this.options = opts;
|
||
}
|
||
|
||
debug(text) {
|
||
this._write(LogLevels.DEBUG, text);
|
||
}
|
||
|
||
log(text) {
|
||
this.debug(text);
|
||
}
|
||
|
||
info(text) {
|
||
this._write(LogLevels.INFO, text);
|
||
}
|
||
|
||
warn(text) {
|
||
this._write(LogLevels.WARN, text);
|
||
}
|
||
|
||
error(text) {
|
||
this._write(LogLevels.ERROR, text);
|
||
}
|
||
|
||
_write(level, text) {
|
||
if(!this._shouldLog(level))
|
||
return;
|
||
|
||
if((this.options.filename || GlobalLogfile) && !this.fileWriter)
|
||
this.fileWriter = fs.openSync(this.options.filename || GlobalLogfile, this.options.appendFile ? 'a+' : 'w+');
|
||
|
||
let format = this._format(level, text);
|
||
let unformattedText = this._createLogMessage(level, text);
|
||
let formattedText = this._createLogMessage(level, text, format.timestamp, format.level, format.category, format.text);
|
||
|
||
if(this.fileWriter)
|
||
fs.writeSync(this.fileWriter, unformattedText + '\n', null, 'utf-8');
|
||
|
||
if(isNodejs) {
|
||
console.log(formattedText)
|
||
} else {
|
||
// TODO: clean this up
|
||
if(level === LogLevels.ERROR) {
|
||
if(this.options.showTimestamp && this.options.showLevel) {
|
||
console.error(formattedText, format.timestamp, format.level, format.category, format.text)
|
||
} else if(this.options.showTimestamp && !this.options.showLevel) {
|
||
console.error(formattedText, format.timestamp, format.category, format.text)
|
||
} else if(!this.options.showTimestamp && this.options.showLevel) {
|
||
console.error(formattedText, format.level, format.category, format.text)
|
||
} else {
|
||
console.error(formattedText, format.category, format.text)
|
||
}
|
||
} else {
|
||
if(this.options.showTimestamp && this.options.showLevel) {
|
||
console.log(formattedText, format.timestamp, format.level, format.category, format.text)
|
||
} else if(this.options.showTimestamp && !this.options.showLevel) {
|
||
console.log(formattedText, format.timestamp, format.category, format.text)
|
||
} else if(!this.options.showTimestamp && this.options.showLevel) {
|
||
console.log(formattedText, format.level, format.category, format.text)
|
||
} else {
|
||
console.log(formattedText, format.category, format.text)
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
_format(level, text) {
|
||
let timestampFormat = '';
|
||
let levelFormat = '';
|
||
let categoryFormat = '';
|
||
let textFormat = ': ';
|
||
|
||
if(this.options.useColors) {
|
||
const levelColor = Object.keys(LogLevels).map((f) => LogLevels[f]).indexOf(level);
|
||
const categoryColor = this.options.color;
|
||
|
||
if(isNodejs) {
|
||
if(this.options.showTimestamp)
|
||
timestampFormat = '\u001b[3' + Colors.Grey + 'm';
|
||
|
||
if(this.options.showLevel)
|
||
levelFormat = '\u001b[3' + loglevelColors[levelColor] + ';22m';
|
||
|
||
categoryFormat = '\u001b[3' + categoryColor + ';1m';
|
||
textFormat = '\u001b[0m: ';
|
||
} else {
|
||
if(this.options.showTimestamp)
|
||
timestampFormat = 'color:' + Colors.Grey;
|
||
|
||
if(this.options.showLevel)
|
||
levelFormat = 'color:' + loglevelColors[levelColor];
|
||
|
||
categoryFormat = 'color:' + categoryColor + '; font-weight: bold';
|
||
}
|
||
}
|
||
|
||
return {
|
||
timestamp: timestampFormat,
|
||
level: levelFormat,
|
||
category: categoryFormat,
|
||
text: textFormat
|
||
};
|
||
}
|
||
|
||
_createLogMessage(level, text, timestampFormat, levelFormat, categoryFormat, textFormat) {
|
||
timestampFormat = timestampFormat || '';
|
||
levelFormat = levelFormat || '';
|
||
categoryFormat = categoryFormat || '';
|
||
textFormat = textFormat || ': ';
|
||
|
||
if(!isNodejs) {
|
||
if(this.options.showTimestamp)
|
||
timestampFormat = '%c';
|
||
|
||
if(this.options.showLevel)
|
||
levelFormat = '%c';
|
||
|
||
categoryFormat = '%c';
|
||
textFormat = ': %c';
|
||
}
|
||
|
||
let result = '';
|
||
|
||
if(this.options.showTimestamp)
|
||
result += '' + new Date().toISOString() + ' ';
|
||
|
||
result = timestampFormat + result;
|
||
|
||
if(this.options.showLevel)
|
||
result += levelFormat + '[' + level +']' + (level === LogLevels.INFO || level === LogLevels.WARN ? ' ' : '') + ' ';
|
||
|
||
result += categoryFormat + this.category;
|
||
result += textFormat + text;
|
||
return result;
|
||
}
|
||
|
||
_shouldLog(level) {
|
||
const levels = Object.keys(LogLevels).map((f) => LogLevels[f]);
|
||
const index = levels.indexOf(level);
|
||
const levelIdx = levels.indexOf(GlobalLogLevel);
|
||
return index >= levelIdx;
|
||
}
|
||
};
|
||
|
||
/* Public API */
|
||
module.exports = {
|
||
Colors: Colors,
|
||
LogLevels: LogLevels,
|
||
setLogLevel: (level) => {
|
||
GlobalLogLevel = level;
|
||
},
|
||
setLogfile: (filename) => {
|
||
GlobalLogfile = filename;
|
||
},
|
||
create: (category, options) => {
|
||
const logger = new Logger(category, options);
|
||
return logger;
|
||
},
|
||
forceBrowserMode: (force) => isNodejs = !force, // for testing
|
||
};
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(62)))
|
||
|
||
/***/ },
|
||
/* 62 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
exports.nextTick = function nextTick(fn) {
|
||
setTimeout(fn, 0);
|
||
};
|
||
|
||
exports.platform = exports.arch =
|
||
exports.execPath = exports.title = 'browser';
|
||
exports.pid = 1;
|
||
exports.browser = true;
|
||
exports.env = {};
|
||
exports.argv = [];
|
||
|
||
exports.binding = function (name) {
|
||
throw new Error('No such module. (Possibly not yet loaded)')
|
||
};
|
||
|
||
(function () {
|
||
var cwd = '/';
|
||
var path;
|
||
exports.cwd = function () { return cwd };
|
||
exports.chdir = function (dir) {
|
||
if (!path) path = __webpack_require__(63);
|
||
cwd = path.resolve(dir, cwd);
|
||
};
|
||
})();
|
||
|
||
exports.exit = exports.kill =
|
||
exports.umask = exports.dlopen =
|
||
exports.uptime = exports.memoryUsage =
|
||
exports.uvCounters = function() {};
|
||
exports.features = {};
|
||
|
||
|
||
/***/ },
|
||
/* 63 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(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.
|
||
|
||
// resolves . and .. elements in a path array with directory names there
|
||
// must be no slashes, empty elements, or device names (c:\) in the array
|
||
// (so also no leading and trailing slashes - it does not distinguish
|
||
// relative and absolute paths)
|
||
function normalizeArray(parts, allowAboveRoot) {
|
||
// if the path tries to go above the root, `up` ends up > 0
|
||
var up = 0;
|
||
for (var i = parts.length - 1; i >= 0; i--) {
|
||
var last = parts[i];
|
||
if (last === '.') {
|
||
parts.splice(i, 1);
|
||
} else if (last === '..') {
|
||
parts.splice(i, 1);
|
||
up++;
|
||
} else if (up) {
|
||
parts.splice(i, 1);
|
||
up--;
|
||
}
|
||
}
|
||
|
||
// if the path is allowed to go above the root, restore leading ..s
|
||
if (allowAboveRoot) {
|
||
for (; up--; up) {
|
||
parts.unshift('..');
|
||
}
|
||
}
|
||
|
||
return parts;
|
||
}
|
||
|
||
// Split a filename into [root, dir, basename, ext], unix version
|
||
// 'root' is just a slash, or nothing.
|
||
var splitPathRe =
|
||
/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
|
||
var splitPath = function(filename) {
|
||
return splitPathRe.exec(filename).slice(1);
|
||
};
|
||
|
||
// path.resolve([from ...], to)
|
||
// posix version
|
||
exports.resolve = function() {
|
||
var resolvedPath = '',
|
||
resolvedAbsolute = false;
|
||
|
||
for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
|
||
var path = (i >= 0) ? arguments[i] : process.cwd();
|
||
|
||
// Skip empty and invalid entries
|
||
if (typeof path !== 'string') {
|
||
throw new TypeError('Arguments to path.resolve must be strings');
|
||
} else if (!path) {
|
||
continue;
|
||
}
|
||
|
||
resolvedPath = path + '/' + resolvedPath;
|
||
resolvedAbsolute = path.charAt(0) === '/';
|
||
}
|
||
|
||
// At this point the path should be resolved to a full absolute path, but
|
||
// handle relative paths to be safe (might happen when process.cwd() fails)
|
||
|
||
// Normalize the path
|
||
resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
|
||
return !!p;
|
||
}), !resolvedAbsolute).join('/');
|
||
|
||
return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
|
||
};
|
||
|
||
// path.normalize(path)
|
||
// posix version
|
||
exports.normalize = function(path) {
|
||
var isAbsolute = exports.isAbsolute(path),
|
||
trailingSlash = substr(path, -1) === '/';
|
||
|
||
// Normalize the path
|
||
path = normalizeArray(filter(path.split('/'), function(p) {
|
||
return !!p;
|
||
}), !isAbsolute).join('/');
|
||
|
||
if (!path && !isAbsolute) {
|
||
path = '.';
|
||
}
|
||
if (path && trailingSlash) {
|
||
path += '/';
|
||
}
|
||
|
||
return (isAbsolute ? '/' : '') + path;
|
||
};
|
||
|
||
// posix version
|
||
exports.isAbsolute = function(path) {
|
||
return path.charAt(0) === '/';
|
||
};
|
||
|
||
// posix version
|
||
exports.join = function() {
|
||
var paths = Array.prototype.slice.call(arguments, 0);
|
||
return exports.normalize(filter(paths, function(p, index) {
|
||
if (typeof p !== 'string') {
|
||
throw new TypeError('Arguments to path.join must be strings');
|
||
}
|
||
return p;
|
||
}).join('/'));
|
||
};
|
||
|
||
|
||
// path.relative(from, to)
|
||
// posix version
|
||
exports.relative = function(from, to) {
|
||
from = exports.resolve(from).substr(1);
|
||
to = exports.resolve(to).substr(1);
|
||
|
||
function trim(arr) {
|
||
var start = 0;
|
||
for (; start < arr.length; start++) {
|
||
if (arr[start] !== '') break;
|
||
}
|
||
|
||
var end = arr.length - 1;
|
||
for (; end >= 0; end--) {
|
||
if (arr[end] !== '') break;
|
||
}
|
||
|
||
if (start > end) return [];
|
||
return arr.slice(start, end - start + 1);
|
||
}
|
||
|
||
var fromParts = trim(from.split('/'));
|
||
var toParts = trim(to.split('/'));
|
||
|
||
var length = Math.min(fromParts.length, toParts.length);
|
||
var samePartsLength = length;
|
||
for (var i = 0; i < length; i++) {
|
||
if (fromParts[i] !== toParts[i]) {
|
||
samePartsLength = i;
|
||
break;
|
||
}
|
||
}
|
||
|
||
var outputParts = [];
|
||
for (var i = samePartsLength; i < fromParts.length; i++) {
|
||
outputParts.push('..');
|
||
}
|
||
|
||
outputParts = outputParts.concat(toParts.slice(samePartsLength));
|
||
|
||
return outputParts.join('/');
|
||
};
|
||
|
||
exports.sep = '/';
|
||
exports.delimiter = ':';
|
||
|
||
exports.dirname = function(path) {
|
||
var result = splitPath(path),
|
||
root = result[0],
|
||
dir = result[1];
|
||
|
||
if (!root && !dir) {
|
||
// No dirname whatsoever
|
||
return '.';
|
||
}
|
||
|
||
if (dir) {
|
||
// It has a dirname, strip trailing slash
|
||
dir = dir.substr(0, dir.length - 1);
|
||
}
|
||
|
||
return root + dir;
|
||
};
|
||
|
||
|
||
exports.basename = function(path, ext) {
|
||
var f = splitPath(path)[2];
|
||
// TODO: make this comparison case-insensitive on windows?
|
||
if (ext && f.substr(-1 * ext.length) === ext) {
|
||
f = f.substr(0, f.length - ext.length);
|
||
}
|
||
return f;
|
||
};
|
||
|
||
|
||
exports.extname = function(path) {
|
||
return splitPath(path)[3];
|
||
};
|
||
|
||
function filter (xs, f) {
|
||
if (xs.filter) return xs.filter(f);
|
||
var res = [];
|
||
for (var i = 0; i < xs.length; i++) {
|
||
if (f(xs[i], i, xs)) res.push(xs[i]);
|
||
}
|
||
return res;
|
||
}
|
||
|
||
// String.prototype.substr - negative index don't work in IE8
|
||
var substr = 'ab'.substr(-1) === 'b'
|
||
? function (str, start, len) { return str.substr(start, len) }
|
||
: function (str, start, len) {
|
||
if (start < 0) start = str.length + start;
|
||
return str.substr(start, len);
|
||
}
|
||
;
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(62)))
|
||
|
||
/***/ },
|
||
/* 64 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = {
|
||
createWriteStream: function(filename, options) {
|
||
return;
|
||
},
|
||
writeFileSync: function() {
|
||
return;
|
||
},
|
||
openSync: function() {
|
||
return;
|
||
},
|
||
writeSync: function() {
|
||
return;
|
||
}
|
||
}
|
||
|
||
|
||
/***/ },
|
||
/* 65 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _stringify = __webpack_require__(66);
|
||
|
||
var _stringify2 = _interopRequireDefault(_stringify);
|
||
|
||
var _promise = __webpack_require__(1);
|
||
|
||
var _promise2 = _interopRequireDefault(_promise);
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _createClass2 = __webpack_require__(57);
|
||
|
||
var _createClass3 = _interopRequireDefault(_createClass2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var io = __webpack_require__(68);
|
||
var logger = __webpack_require__(61).create("orbit-db.Pubsub");
|
||
|
||
var Pubsub = function () {
|
||
function Pubsub(ipfs) {
|
||
(0, _classCallCheck3.default)(this, Pubsub);
|
||
|
||
this.ipfs = ipfs;
|
||
this._socket = null;
|
||
this._subscriptions = {};
|
||
this.onConnected = null;
|
||
this.onConnectionError = null;
|
||
}
|
||
|
||
(0, _createClass3.default)(Pubsub, [{
|
||
key: 'connect',
|
||
value: function connect(host, port, username, password) {
|
||
var _this = this;
|
||
|
||
return new _promise2.default(function (resolve, reject) {
|
||
if (!_this._socket) _this._socket = io.connect('http://' + host + ':' + port, { 'forceNew': true });
|
||
|
||
_this._socket.on('connect', resolve);
|
||
_this._socket.on('connect_error', function (err) {
|
||
return reject(new Error('Connection refused to Pubsub at \'' + host + ':' + port + '\''));
|
||
});
|
||
_this._socket.on('disconnect', function (socket) {
|
||
return logger.warn('Disconnected from Pubsub at \'http://' + host + ':' + port + '\'');
|
||
});
|
||
_this._socket.on('error', function (e) {
|
||
return logger.error('Pubsub socket error:', e);
|
||
});
|
||
_this._socket.on('message', _this._handleMessage.bind(_this));
|
||
_this._socket.on('subscribed', _this._handleMessage.bind(_this));
|
||
});
|
||
}
|
||
}, {
|
||
key: 'disconnect',
|
||
value: function disconnect() {
|
||
if (this._socket) this._socket.disconnect();
|
||
}
|
||
}, {
|
||
key: 'subscribe',
|
||
value: function subscribe(hash, password, callback) {
|
||
if (!this._subscriptions[hash]) {
|
||
this._subscriptions[hash] = { callback: callback };
|
||
this._socket.emit('subscribe', { channel: hash }); // calls back with 'subscribed' event
|
||
}
|
||
}
|
||
}, {
|
||
key: 'unsubscribe',
|
||
value: function unsubscribe(hash) {
|
||
this._socket.emit('unsubscribe', { channel: hash });
|
||
delete this._subscriptions[hash];
|
||
}
|
||
}, {
|
||
key: 'publish',
|
||
value: function publish(hash, message) {
|
||
this._socket.send((0, _stringify2.default)({ channel: hash, message: message }));
|
||
}
|
||
}, {
|
||
key: '_handleMessage',
|
||
value: function _handleMessage(hash, message) {
|
||
if (this._subscriptions[hash] && this._subscriptions[hash].callback) this._subscriptions[hash].callback(hash, message);
|
||
}
|
||
}]);
|
||
return Pubsub;
|
||
}();
|
||
|
||
module.exports = Pubsub;
|
||
|
||
/***/ },
|
||
/* 66 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = { "default": __webpack_require__(67), __esModule: true };
|
||
|
||
/***/ },
|
||
/* 67 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var core = __webpack_require__(12);
|
||
module.exports = function stringify(it){ // eslint-disable-line no-unused-vars
|
||
return (core.JSON && core.JSON.stringify || JSON.stringify).apply(JSON, arguments);
|
||
};
|
||
|
||
/***/ },
|
||
/* 68 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
|
||
/**
|
||
* Module dependencies.
|
||
*/
|
||
|
||
var url = __webpack_require__(69);
|
||
var parser = __webpack_require__(74);
|
||
var Manager = __webpack_require__(82);
|
||
var debug = __webpack_require__(71)('socket.io-client');
|
||
|
||
/**
|
||
* Module exports.
|
||
*/
|
||
|
||
module.exports = exports = lookup;
|
||
|
||
/**
|
||
* Managers cache.
|
||
*/
|
||
|
||
var cache = exports.managers = {};
|
||
|
||
/**
|
||
* Looks up an existing `Manager` for multiplexing.
|
||
* If the user summons:
|
||
*
|
||
* `io('http://localhost/a');`
|
||
* `io('http://localhost/b');`
|
||
*
|
||
* We reuse the existing instance based on same scheme/port/host,
|
||
* and we initialize sockets for each namespace.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
function lookup(uri, opts) {
|
||
if (typeof uri == 'object') {
|
||
opts = uri;
|
||
uri = undefined;
|
||
}
|
||
|
||
opts = opts || {};
|
||
|
||
var parsed = url(uri);
|
||
var source = parsed.source;
|
||
var id = parsed.id;
|
||
var path = parsed.path;
|
||
var sameNamespace = cache[id] && path in cache[id].nsps;
|
||
var newConnection = opts.forceNew || opts['force new connection'] ||
|
||
false === opts.multiplex || sameNamespace;
|
||
|
||
var io;
|
||
|
||
if (newConnection) {
|
||
debug('ignoring socket cache for %s', source);
|
||
io = Manager(source, opts);
|
||
} else {
|
||
if (!cache[id]) {
|
||
debug('new io instance for %s', source);
|
||
cache[id] = Manager(source, opts);
|
||
}
|
||
io = cache[id];
|
||
}
|
||
|
||
return io.socket(parsed.path);
|
||
}
|
||
|
||
/**
|
||
* Protocol version.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
exports.protocol = parser.protocol;
|
||
|
||
/**
|
||
* `connect`.
|
||
*
|
||
* @param {String} uri
|
||
* @api public
|
||
*/
|
||
|
||
exports.connect = lookup;
|
||
|
||
/**
|
||
* Expose constructors for standalone build.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
exports.Manager = __webpack_require__(82);
|
||
exports.Socket = __webpack_require__(110);
|
||
|
||
|
||
/***/ },
|
||
/* 69 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(global) {
|
||
/**
|
||
* Module dependencies.
|
||
*/
|
||
|
||
var parseuri = __webpack_require__(70);
|
||
var debug = __webpack_require__(71)('socket.io-client:url');
|
||
|
||
/**
|
||
* Module exports.
|
||
*/
|
||
|
||
module.exports = url;
|
||
|
||
/**
|
||
* URL parser.
|
||
*
|
||
* @param {String} url
|
||
* @param {Object} An object meant to mimic window.location.
|
||
* Defaults to window.location.
|
||
* @api public
|
||
*/
|
||
|
||
function url(uri, loc){
|
||
var obj = uri;
|
||
|
||
// default to window.location
|
||
var loc = loc || global.location;
|
||
if (null == uri) uri = loc.protocol + '//' + loc.host;
|
||
|
||
// relative path support
|
||
if ('string' == typeof uri) {
|
||
if ('/' == uri.charAt(0)) {
|
||
if ('/' == uri.charAt(1)) {
|
||
uri = loc.protocol + uri;
|
||
} else {
|
||
uri = loc.host + uri;
|
||
}
|
||
}
|
||
|
||
if (!/^(https?|wss?):\/\//.test(uri)) {
|
||
debug('protocol-less url %s', uri);
|
||
if ('undefined' != typeof loc) {
|
||
uri = loc.protocol + '//' + uri;
|
||
} else {
|
||
uri = 'https://' + uri;
|
||
}
|
||
}
|
||
|
||
// parse
|
||
debug('parse %s', uri);
|
||
obj = parseuri(uri);
|
||
}
|
||
|
||
// make sure we treat `localhost:80` and `localhost` equally
|
||
if (!obj.port) {
|
||
if (/^(http|ws)$/.test(obj.protocol)) {
|
||
obj.port = '80';
|
||
}
|
||
else if (/^(http|ws)s$/.test(obj.protocol)) {
|
||
obj.port = '443';
|
||
}
|
||
}
|
||
|
||
obj.path = obj.path || '/';
|
||
|
||
var ipv6 = obj.host.indexOf(':') !== -1;
|
||
var host = ipv6 ? '[' + obj.host + ']' : obj.host;
|
||
|
||
// define unique id
|
||
obj.id = obj.protocol + '://' + host + ':' + obj.port;
|
||
// define href
|
||
obj.href = obj.protocol + '://' + host + (loc && loc.port == obj.port ? '' : (':' + obj.port));
|
||
|
||
return obj;
|
||
}
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 70 */
|
||
/***/ function(module, exports) {
|
||
|
||
/**
|
||
* Parses an URI
|
||
*
|
||
* @author Steven Levithan <stevenlevithan.com> (MIT license)
|
||
* @api private
|
||
*/
|
||
|
||
var re = /^(?:(?![^:@]+:[^:@\/]*@)(http|https|ws|wss):\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?((?:[a-f0-9]{0,4}:){2,7}[a-f0-9]{0,4}|[^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/;
|
||
|
||
var parts = [
|
||
'source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'anchor'
|
||
];
|
||
|
||
module.exports = function parseuri(str) {
|
||
var src = str,
|
||
b = str.indexOf('['),
|
||
e = str.indexOf(']');
|
||
|
||
if (b != -1 && e != -1) {
|
||
str = str.substring(0, b) + str.substring(b, e).replace(/:/g, ';') + str.substring(e, str.length);
|
||
}
|
||
|
||
var m = re.exec(str || ''),
|
||
uri = {},
|
||
i = 14;
|
||
|
||
while (i--) {
|
||
uri[parts[i]] = m[i] || '';
|
||
}
|
||
|
||
if (b != -1 && e != -1) {
|
||
uri.source = src;
|
||
uri.host = uri.host.substring(1, uri.host.length - 1).replace(/;/g, ':');
|
||
uri.authority = uri.authority.replace('[', '').replace(']', '').replace(/;/g, ':');
|
||
uri.ipv6uri = true;
|
||
}
|
||
|
||
return uri;
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 71 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
|
||
/**
|
||
* This is the web browser implementation of `debug()`.
|
||
*
|
||
* Expose `debug()` as the module.
|
||
*/
|
||
|
||
exports = module.exports = __webpack_require__(72);
|
||
exports.log = log;
|
||
exports.formatArgs = formatArgs;
|
||
exports.save = save;
|
||
exports.load = load;
|
||
exports.useColors = useColors;
|
||
exports.storage = 'undefined' != typeof chrome
|
||
&& 'undefined' != typeof chrome.storage
|
||
? chrome.storage.local
|
||
: localstorage();
|
||
|
||
/**
|
||
* Colors.
|
||
*/
|
||
|
||
exports.colors = [
|
||
'lightseagreen',
|
||
'forestgreen',
|
||
'goldenrod',
|
||
'dodgerblue',
|
||
'darkorchid',
|
||
'crimson'
|
||
];
|
||
|
||
/**
|
||
* Currently only WebKit-based Web Inspectors, Firefox >= v31,
|
||
* and the Firebug extension (any Firefox version) are known
|
||
* to support "%c" CSS customizations.
|
||
*
|
||
* TODO: add a `localStorage` variable to explicitly enable/disable colors
|
||
*/
|
||
|
||
function useColors() {
|
||
// is webkit? http://stackoverflow.com/a/16459606/376773
|
||
return ('WebkitAppearance' in document.documentElement.style) ||
|
||
// is firebug? http://stackoverflow.com/a/398120/376773
|
||
(window.console && (console.firebug || (console.exception && console.table))) ||
|
||
// is firefox >= v31?
|
||
// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
|
||
(navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31);
|
||
}
|
||
|
||
/**
|
||
* Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
|
||
*/
|
||
|
||
exports.formatters.j = function(v) {
|
||
return JSON.stringify(v);
|
||
};
|
||
|
||
|
||
/**
|
||
* Colorize log arguments if enabled.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
function formatArgs() {
|
||
var args = arguments;
|
||
var useColors = this.useColors;
|
||
|
||
args[0] = (useColors ? '%c' : '')
|
||
+ this.namespace
|
||
+ (useColors ? ' %c' : ' ')
|
||
+ args[0]
|
||
+ (useColors ? '%c ' : ' ')
|
||
+ '+' + exports.humanize(this.diff);
|
||
|
||
if (!useColors) return args;
|
||
|
||
var c = 'color: ' + this.color;
|
||
args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1));
|
||
|
||
// the final "%c" is somewhat tricky, because there could be other
|
||
// arguments passed either before or after the %c, so we need to
|
||
// figure out the correct index to insert the CSS into
|
||
var index = 0;
|
||
var lastC = 0;
|
||
args[0].replace(/%[a-z%]/g, function(match) {
|
||
if ('%%' === match) return;
|
||
index++;
|
||
if ('%c' === match) {
|
||
// we only are interested in the *last* %c
|
||
// (the user may have provided their own)
|
||
lastC = index;
|
||
}
|
||
});
|
||
|
||
args.splice(lastC, 0, c);
|
||
return args;
|
||
}
|
||
|
||
/**
|
||
* Invokes `console.log()` when available.
|
||
* No-op when `console.log` is not a "function".
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
function log() {
|
||
// this hackery is required for IE8/9, where
|
||
// the `console.log` function doesn't have 'apply'
|
||
return 'object' === typeof console
|
||
&& console.log
|
||
&& Function.prototype.apply.call(console.log, console, arguments);
|
||
}
|
||
|
||
/**
|
||
* Save `namespaces`.
|
||
*
|
||
* @param {String} namespaces
|
||
* @api private
|
||
*/
|
||
|
||
function save(namespaces) {
|
||
try {
|
||
if (null == namespaces) {
|
||
exports.storage.removeItem('debug');
|
||
} else {
|
||
exports.storage.debug = namespaces;
|
||
}
|
||
} catch(e) {}
|
||
}
|
||
|
||
/**
|
||
* Load `namespaces`.
|
||
*
|
||
* @return {String} returns the previously persisted debug modes
|
||
* @api private
|
||
*/
|
||
|
||
function load() {
|
||
var r;
|
||
try {
|
||
r = exports.storage.debug;
|
||
} catch(e) {}
|
||
return r;
|
||
}
|
||
|
||
/**
|
||
* Enable namespaces listed in `localStorage.debug` initially.
|
||
*/
|
||
|
||
exports.enable(load());
|
||
|
||
/**
|
||
* Localstorage attempts to return the localstorage.
|
||
*
|
||
* This is necessary because safari throws
|
||
* when a user disables cookies/localstorage
|
||
* and you attempt to access it.
|
||
*
|
||
* @return {LocalStorage}
|
||
* @api private
|
||
*/
|
||
|
||
function localstorage(){
|
||
try {
|
||
return window.localStorage;
|
||
} catch (e) {}
|
||
}
|
||
|
||
|
||
/***/ },
|
||
/* 72 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
|
||
/**
|
||
* This is the common logic for both the Node.js and web browser
|
||
* implementations of `debug()`.
|
||
*
|
||
* Expose `debug()` as the module.
|
||
*/
|
||
|
||
exports = module.exports = debug;
|
||
exports.coerce = coerce;
|
||
exports.disable = disable;
|
||
exports.enable = enable;
|
||
exports.enabled = enabled;
|
||
exports.humanize = __webpack_require__(73);
|
||
|
||
/**
|
||
* The currently active debug mode names, and names to skip.
|
||
*/
|
||
|
||
exports.names = [];
|
||
exports.skips = [];
|
||
|
||
/**
|
||
* Map of special "%n" handling functions, for the debug "format" argument.
|
||
*
|
||
* Valid key names are a single, lowercased letter, i.e. "n".
|
||
*/
|
||
|
||
exports.formatters = {};
|
||
|
||
/**
|
||
* Previously assigned color.
|
||
*/
|
||
|
||
var prevColor = 0;
|
||
|
||
/**
|
||
* Previous log timestamp.
|
||
*/
|
||
|
||
var prevTime;
|
||
|
||
/**
|
||
* Select a color.
|
||
*
|
||
* @return {Number}
|
||
* @api private
|
||
*/
|
||
|
||
function selectColor() {
|
||
return exports.colors[prevColor++ % exports.colors.length];
|
||
}
|
||
|
||
/**
|
||
* Create a debugger with the given `namespace`.
|
||
*
|
||
* @param {String} namespace
|
||
* @return {Function}
|
||
* @api public
|
||
*/
|
||
|
||
function debug(namespace) {
|
||
|
||
// define the `disabled` version
|
||
function disabled() {
|
||
}
|
||
disabled.enabled = false;
|
||
|
||
// define the `enabled` version
|
||
function enabled() {
|
||
|
||
var self = enabled;
|
||
|
||
// set `diff` timestamp
|
||
var curr = +new Date();
|
||
var ms = curr - (prevTime || curr);
|
||
self.diff = ms;
|
||
self.prev = prevTime;
|
||
self.curr = curr;
|
||
prevTime = curr;
|
||
|
||
// add the `color` if not set
|
||
if (null == self.useColors) self.useColors = exports.useColors();
|
||
if (null == self.color && self.useColors) self.color = selectColor();
|
||
|
||
var args = Array.prototype.slice.call(arguments);
|
||
|
||
args[0] = exports.coerce(args[0]);
|
||
|
||
if ('string' !== typeof args[0]) {
|
||
// anything else let's inspect with %o
|
||
args = ['%o'].concat(args);
|
||
}
|
||
|
||
// apply any `formatters` transformations
|
||
var index = 0;
|
||
args[0] = args[0].replace(/%([a-z%])/g, function(match, format) {
|
||
// if we encounter an escaped % then don't increase the array index
|
||
if (match === '%%') return match;
|
||
index++;
|
||
var formatter = exports.formatters[format];
|
||
if ('function' === typeof formatter) {
|
||
var val = args[index];
|
||
match = formatter.call(self, val);
|
||
|
||
// now we need to remove `args[index]` since it's inlined in the `format`
|
||
args.splice(index, 1);
|
||
index--;
|
||
}
|
||
return match;
|
||
});
|
||
|
||
if ('function' === typeof exports.formatArgs) {
|
||
args = exports.formatArgs.apply(self, args);
|
||
}
|
||
var logFn = enabled.log || exports.log || console.log.bind(console);
|
||
logFn.apply(self, args);
|
||
}
|
||
enabled.enabled = true;
|
||
|
||
var fn = exports.enabled(namespace) ? enabled : disabled;
|
||
|
||
fn.namespace = namespace;
|
||
|
||
return fn;
|
||
}
|
||
|
||
/**
|
||
* Enables a debug mode by namespaces. This can include modes
|
||
* separated by a colon and wildcards.
|
||
*
|
||
* @param {String} namespaces
|
||
* @api public
|
||
*/
|
||
|
||
function enable(namespaces) {
|
||
exports.save(namespaces);
|
||
|
||
var split = (namespaces || '').split(/[\s,]+/);
|
||
var len = split.length;
|
||
|
||
for (var i = 0; i < len; i++) {
|
||
if (!split[i]) continue; // ignore empty strings
|
||
namespaces = split[i].replace(/\*/g, '.*?');
|
||
if (namespaces[0] === '-') {
|
||
exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
|
||
} else {
|
||
exports.names.push(new RegExp('^' + namespaces + '$'));
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Disable debug output.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
function disable() {
|
||
exports.enable('');
|
||
}
|
||
|
||
/**
|
||
* Returns true if the given mode name is enabled, false otherwise.
|
||
*
|
||
* @param {String} name
|
||
* @return {Boolean}
|
||
* @api public
|
||
*/
|
||
|
||
function enabled(name) {
|
||
var i, len;
|
||
for (i = 0, len = exports.skips.length; i < len; i++) {
|
||
if (exports.skips[i].test(name)) {
|
||
return false;
|
||
}
|
||
}
|
||
for (i = 0, len = exports.names.length; i < len; i++) {
|
||
if (exports.names[i].test(name)) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Coerce `val`.
|
||
*
|
||
* @param {Mixed} val
|
||
* @return {Mixed}
|
||
* @api private
|
||
*/
|
||
|
||
function coerce(val) {
|
||
if (val instanceof Error) return val.stack || val.message;
|
||
return val;
|
||
}
|
||
|
||
|
||
/***/ },
|
||
/* 73 */
|
||
/***/ function(module, exports) {
|
||
|
||
/**
|
||
* Helpers.
|
||
*/
|
||
|
||
var s = 1000;
|
||
var m = s * 60;
|
||
var h = m * 60;
|
||
var d = h * 24;
|
||
var y = d * 365.25;
|
||
|
||
/**
|
||
* Parse or format the given `val`.
|
||
*
|
||
* Options:
|
||
*
|
||
* - `long` verbose formatting [false]
|
||
*
|
||
* @param {String|Number} val
|
||
* @param {Object} options
|
||
* @return {String|Number}
|
||
* @api public
|
||
*/
|
||
|
||
module.exports = function(val, options){
|
||
options = options || {};
|
||
if ('string' == typeof val) return parse(val);
|
||
return options.long
|
||
? long(val)
|
||
: short(val);
|
||
};
|
||
|
||
/**
|
||
* Parse the given `str` and return milliseconds.
|
||
*
|
||
* @param {String} str
|
||
* @return {Number}
|
||
* @api private
|
||
*/
|
||
|
||
function parse(str) {
|
||
str = '' + str;
|
||
if (str.length > 10000) return;
|
||
var match = /^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(str);
|
||
if (!match) return;
|
||
var n = parseFloat(match[1]);
|
||
var type = (match[2] || 'ms').toLowerCase();
|
||
switch (type) {
|
||
case 'years':
|
||
case 'year':
|
||
case 'yrs':
|
||
case 'yr':
|
||
case 'y':
|
||
return n * y;
|
||
case 'days':
|
||
case 'day':
|
||
case 'd':
|
||
return n * d;
|
||
case 'hours':
|
||
case 'hour':
|
||
case 'hrs':
|
||
case 'hr':
|
||
case 'h':
|
||
return n * h;
|
||
case 'minutes':
|
||
case 'minute':
|
||
case 'mins':
|
||
case 'min':
|
||
case 'm':
|
||
return n * m;
|
||
case 'seconds':
|
||
case 'second':
|
||
case 'secs':
|
||
case 'sec':
|
||
case 's':
|
||
return n * s;
|
||
case 'milliseconds':
|
||
case 'millisecond':
|
||
case 'msecs':
|
||
case 'msec':
|
||
case 'ms':
|
||
return n;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Short format for `ms`.
|
||
*
|
||
* @param {Number} ms
|
||
* @return {String}
|
||
* @api private
|
||
*/
|
||
|
||
function short(ms) {
|
||
if (ms >= d) return Math.round(ms / d) + 'd';
|
||
if (ms >= h) return Math.round(ms / h) + 'h';
|
||
if (ms >= m) return Math.round(ms / m) + 'm';
|
||
if (ms >= s) return Math.round(ms / s) + 's';
|
||
return ms + 'ms';
|
||
}
|
||
|
||
/**
|
||
* Long format for `ms`.
|
||
*
|
||
* @param {Number} ms
|
||
* @return {String}
|
||
* @api private
|
||
*/
|
||
|
||
function long(ms) {
|
||
return plural(ms, d, 'day')
|
||
|| plural(ms, h, 'hour')
|
||
|| plural(ms, m, 'minute')
|
||
|| plural(ms, s, 'second')
|
||
|| ms + ' ms';
|
||
}
|
||
|
||
/**
|
||
* Pluralization helper.
|
||
*/
|
||
|
||
function plural(ms, n, name) {
|
||
if (ms < n) return;
|
||
if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name;
|
||
return Math.ceil(ms / n) + ' ' + name + 's';
|
||
}
|
||
|
||
|
||
/***/ },
|
||
/* 74 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
|
||
/**
|
||
* Module dependencies.
|
||
*/
|
||
|
||
var debug = __webpack_require__(71)('socket.io-parser');
|
||
var json = __webpack_require__(75);
|
||
var isArray = __webpack_require__(78);
|
||
var Emitter = __webpack_require__(79);
|
||
var binary = __webpack_require__(80);
|
||
var isBuf = __webpack_require__(81);
|
||
|
||
/**
|
||
* Protocol version.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
exports.protocol = 4;
|
||
|
||
/**
|
||
* Packet types.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
exports.types = [
|
||
'CONNECT',
|
||
'DISCONNECT',
|
||
'EVENT',
|
||
'ACK',
|
||
'ERROR',
|
||
'BINARY_EVENT',
|
||
'BINARY_ACK'
|
||
];
|
||
|
||
/**
|
||
* Packet type `connect`.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
exports.CONNECT = 0;
|
||
|
||
/**
|
||
* Packet type `disconnect`.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
exports.DISCONNECT = 1;
|
||
|
||
/**
|
||
* Packet type `event`.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
exports.EVENT = 2;
|
||
|
||
/**
|
||
* Packet type `ack`.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
exports.ACK = 3;
|
||
|
||
/**
|
||
* Packet type `error`.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
exports.ERROR = 4;
|
||
|
||
/**
|
||
* Packet type 'binary event'
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
exports.BINARY_EVENT = 5;
|
||
|
||
/**
|
||
* Packet type `binary ack`. For acks with binary arguments.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
exports.BINARY_ACK = 6;
|
||
|
||
/**
|
||
* Encoder constructor.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
exports.Encoder = Encoder;
|
||
|
||
/**
|
||
* Decoder constructor.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
exports.Decoder = Decoder;
|
||
|
||
/**
|
||
* A socket.io Encoder instance
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
function Encoder() {}
|
||
|
||
/**
|
||
* Encode a packet as a single string if non-binary, or as a
|
||
* buffer sequence, depending on packet type.
|
||
*
|
||
* @param {Object} obj - packet object
|
||
* @param {Function} callback - function to handle encodings (likely engine.write)
|
||
* @return Calls callback with Array of encodings
|
||
* @api public
|
||
*/
|
||
|
||
Encoder.prototype.encode = function(obj, callback){
|
||
debug('encoding packet %j', obj);
|
||
|
||
if (exports.BINARY_EVENT == obj.type || exports.BINARY_ACK == obj.type) {
|
||
encodeAsBinary(obj, callback);
|
||
}
|
||
else {
|
||
var encoding = encodeAsString(obj);
|
||
callback([encoding]);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Encode packet as string.
|
||
*
|
||
* @param {Object} packet
|
||
* @return {String} encoded
|
||
* @api private
|
||
*/
|
||
|
||
function encodeAsString(obj) {
|
||
var str = '';
|
||
var nsp = false;
|
||
|
||
// first is type
|
||
str += obj.type;
|
||
|
||
// attachments if we have them
|
||
if (exports.BINARY_EVENT == obj.type || exports.BINARY_ACK == obj.type) {
|
||
str += obj.attachments;
|
||
str += '-';
|
||
}
|
||
|
||
// if we have a namespace other than `/`
|
||
// we append it followed by a comma `,`
|
||
if (obj.nsp && '/' != obj.nsp) {
|
||
nsp = true;
|
||
str += obj.nsp;
|
||
}
|
||
|
||
// immediately followed by the id
|
||
if (null != obj.id) {
|
||
if (nsp) {
|
||
str += ',';
|
||
nsp = false;
|
||
}
|
||
str += obj.id;
|
||
}
|
||
|
||
// json data
|
||
if (null != obj.data) {
|
||
if (nsp) str += ',';
|
||
str += json.stringify(obj.data);
|
||
}
|
||
|
||
debug('encoded %j as %s', obj, str);
|
||
return str;
|
||
}
|
||
|
||
/**
|
||
* Encode packet as 'buffer sequence' by removing blobs, and
|
||
* deconstructing packet into object with placeholders and
|
||
* a list of buffers.
|
||
*
|
||
* @param {Object} packet
|
||
* @return {Buffer} encoded
|
||
* @api private
|
||
*/
|
||
|
||
function encodeAsBinary(obj, callback) {
|
||
|
||
function writeEncoding(bloblessData) {
|
||
var deconstruction = binary.deconstructPacket(bloblessData);
|
||
var pack = encodeAsString(deconstruction.packet);
|
||
var buffers = deconstruction.buffers;
|
||
|
||
buffers.unshift(pack); // add packet info to beginning of data list
|
||
callback(buffers); // write all the buffers
|
||
}
|
||
|
||
binary.removeBlobs(obj, writeEncoding);
|
||
}
|
||
|
||
/**
|
||
* A socket.io Decoder instance
|
||
*
|
||
* @return {Object} decoder
|
||
* @api public
|
||
*/
|
||
|
||
function Decoder() {
|
||
this.reconstructor = null;
|
||
}
|
||
|
||
/**
|
||
* Mix in `Emitter` with Decoder.
|
||
*/
|
||
|
||
Emitter(Decoder.prototype);
|
||
|
||
/**
|
||
* Decodes an ecoded packet string into packet JSON.
|
||
*
|
||
* @param {String} obj - encoded packet
|
||
* @return {Object} packet
|
||
* @api public
|
||
*/
|
||
|
||
Decoder.prototype.add = function(obj) {
|
||
var packet;
|
||
if ('string' == typeof obj) {
|
||
packet = decodeString(obj);
|
||
if (exports.BINARY_EVENT == packet.type || exports.BINARY_ACK == packet.type) { // binary packet's json
|
||
this.reconstructor = new BinaryReconstructor(packet);
|
||
|
||
// no attachments, labeled binary but no binary data to follow
|
||
if (this.reconstructor.reconPack.attachments === 0) {
|
||
this.emit('decoded', packet);
|
||
}
|
||
} else { // non-binary full packet
|
||
this.emit('decoded', packet);
|
||
}
|
||
}
|
||
else if (isBuf(obj) || obj.base64) { // raw binary data
|
||
if (!this.reconstructor) {
|
||
throw new Error('got binary data when not reconstructing a packet');
|
||
} else {
|
||
packet = this.reconstructor.takeBinaryData(obj);
|
||
if (packet) { // received final buffer
|
||
this.reconstructor = null;
|
||
this.emit('decoded', packet);
|
||
}
|
||
}
|
||
}
|
||
else {
|
||
throw new Error('Unknown type: ' + obj);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Decode a packet String (JSON data)
|
||
*
|
||
* @param {String} str
|
||
* @return {Object} packet
|
||
* @api private
|
||
*/
|
||
|
||
function decodeString(str) {
|
||
var p = {};
|
||
var i = 0;
|
||
|
||
// look up type
|
||
p.type = Number(str.charAt(0));
|
||
if (null == exports.types[p.type]) return error();
|
||
|
||
// look up attachments if type binary
|
||
if (exports.BINARY_EVENT == p.type || exports.BINARY_ACK == p.type) {
|
||
var buf = '';
|
||
while (str.charAt(++i) != '-') {
|
||
buf += str.charAt(i);
|
||
if (i == str.length) break;
|
||
}
|
||
if (buf != Number(buf) || str.charAt(i) != '-') {
|
||
throw new Error('Illegal attachments');
|
||
}
|
||
p.attachments = Number(buf);
|
||
}
|
||
|
||
// look up namespace (if any)
|
||
if ('/' == str.charAt(i + 1)) {
|
||
p.nsp = '';
|
||
while (++i) {
|
||
var c = str.charAt(i);
|
||
if (',' == c) break;
|
||
p.nsp += c;
|
||
if (i == str.length) break;
|
||
}
|
||
} else {
|
||
p.nsp = '/';
|
||
}
|
||
|
||
// look up id
|
||
var next = str.charAt(i + 1);
|
||
if ('' !== next && Number(next) == next) {
|
||
p.id = '';
|
||
while (++i) {
|
||
var c = str.charAt(i);
|
||
if (null == c || Number(c) != c) {
|
||
--i;
|
||
break;
|
||
}
|
||
p.id += str.charAt(i);
|
||
if (i == str.length) break;
|
||
}
|
||
p.id = Number(p.id);
|
||
}
|
||
|
||
// look up json data
|
||
if (str.charAt(++i)) {
|
||
try {
|
||
p.data = json.parse(str.substr(i));
|
||
} catch(e){
|
||
return error();
|
||
}
|
||
}
|
||
|
||
debug('decoded %s as %j', str, p);
|
||
return p;
|
||
}
|
||
|
||
/**
|
||
* Deallocates a parser's resources
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
Decoder.prototype.destroy = function() {
|
||
if (this.reconstructor) {
|
||
this.reconstructor.finishedReconstruction();
|
||
}
|
||
};
|
||
|
||
/**
|
||
* A manager of a binary event's 'buffer sequence'. Should
|
||
* be constructed whenever a packet of type BINARY_EVENT is
|
||
* decoded.
|
||
*
|
||
* @param {Object} packet
|
||
* @return {BinaryReconstructor} initialized reconstructor
|
||
* @api private
|
||
*/
|
||
|
||
function BinaryReconstructor(packet) {
|
||
this.reconPack = packet;
|
||
this.buffers = [];
|
||
}
|
||
|
||
/**
|
||
* Method to be called when binary data received from connection
|
||
* after a BINARY_EVENT packet.
|
||
*
|
||
* @param {Buffer | ArrayBuffer} binData - the raw binary data received
|
||
* @return {null | Object} returns null if more binary data is expected or
|
||
* a reconstructed packet object if all buffers have been received.
|
||
* @api private
|
||
*/
|
||
|
||
BinaryReconstructor.prototype.takeBinaryData = function(binData) {
|
||
this.buffers.push(binData);
|
||
if (this.buffers.length == this.reconPack.attachments) { // done with buffer list
|
||
var packet = binary.reconstructPacket(this.reconPack, this.buffers);
|
||
this.finishedReconstruction();
|
||
return packet;
|
||
}
|
||
return null;
|
||
};
|
||
|
||
/**
|
||
* Cleans up binary packet reconstruction variables.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
BinaryReconstructor.prototype.finishedReconstruction = function() {
|
||
this.reconPack = null;
|
||
this.buffers = [];
|
||
};
|
||
|
||
function error(data){
|
||
return {
|
||
type: exports.ERROR,
|
||
data: 'parser error'
|
||
};
|
||
}
|
||
|
||
|
||
/***/ },
|
||
/* 75 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(module, global) {/*! JSON v3.3.2 | http://bestiejs.github.io/json3 | Copyright 2012-2014, Kit Cambridge | http://kit.mit-license.org */
|
||
;(function () {
|
||
// Detect the `define` function exposed by asynchronous module loaders. The
|
||
// strict `define` check is necessary for compatibility with `r.js`.
|
||
var isLoader = "function" === "function" && __webpack_require__(77);
|
||
|
||
// A set of types used to distinguish objects from primitives.
|
||
var objectTypes = {
|
||
"function": true,
|
||
"object": true
|
||
};
|
||
|
||
// Detect the `exports` object exposed by CommonJS implementations.
|
||
var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
|
||
|
||
// Use the `global` object exposed by Node (including Browserify via
|
||
// `insert-module-globals`), Narwhal, and Ringo as the default context,
|
||
// and the `window` object in browsers. Rhino exports a `global` function
|
||
// instead.
|
||
var root = objectTypes[typeof window] && window || this,
|
||
freeGlobal = freeExports && objectTypes[typeof module] && module && !module.nodeType && typeof global == "object" && global;
|
||
|
||
if (freeGlobal && (freeGlobal["global"] === freeGlobal || freeGlobal["window"] === freeGlobal || freeGlobal["self"] === freeGlobal)) {
|
||
root = freeGlobal;
|
||
}
|
||
|
||
// Public: Initializes JSON 3 using the given `context` object, attaching the
|
||
// `stringify` and `parse` functions to the specified `exports` object.
|
||
function runInContext(context, exports) {
|
||
context || (context = root["Object"]());
|
||
exports || (exports = root["Object"]());
|
||
|
||
// Native constructor aliases.
|
||
var Number = context["Number"] || root["Number"],
|
||
String = context["String"] || root["String"],
|
||
Object = context["Object"] || root["Object"],
|
||
Date = context["Date"] || root["Date"],
|
||
SyntaxError = context["SyntaxError"] || root["SyntaxError"],
|
||
TypeError = context["TypeError"] || root["TypeError"],
|
||
Math = context["Math"] || root["Math"],
|
||
nativeJSON = context["JSON"] || root["JSON"];
|
||
|
||
// Delegate to the native `stringify` and `parse` implementations.
|
||
if (typeof nativeJSON == "object" && nativeJSON) {
|
||
exports.stringify = nativeJSON.stringify;
|
||
exports.parse = nativeJSON.parse;
|
||
}
|
||
|
||
// Convenience aliases.
|
||
var objectProto = Object.prototype,
|
||
getClass = objectProto.toString,
|
||
isProperty, forEach, undef;
|
||
|
||
// Test the `Date#getUTC*` methods. Based on work by @Yaffle.
|
||
var isExtended = new Date(-3509827334573292);
|
||
try {
|
||
// The `getUTCFullYear`, `Month`, and `Date` methods return nonsensical
|
||
// results for certain dates in Opera >= 10.53.
|
||
isExtended = isExtended.getUTCFullYear() == -109252 && isExtended.getUTCMonth() === 0 && isExtended.getUTCDate() === 1 &&
|
||
// Safari < 2.0.2 stores the internal millisecond time value correctly,
|
||
// but clips the values returned by the date methods to the range of
|
||
// signed 32-bit integers ([-2 ** 31, 2 ** 31 - 1]).
|
||
isExtended.getUTCHours() == 10 && isExtended.getUTCMinutes() == 37 && isExtended.getUTCSeconds() == 6 && isExtended.getUTCMilliseconds() == 708;
|
||
} catch (exception) {}
|
||
|
||
// Internal: Determines whether the native `JSON.stringify` and `parse`
|
||
// implementations are spec-compliant. Based on work by Ken Snyder.
|
||
function has(name) {
|
||
if (has[name] !== undef) {
|
||
// Return cached feature test result.
|
||
return has[name];
|
||
}
|
||
var isSupported;
|
||
if (name == "bug-string-char-index") {
|
||
// IE <= 7 doesn't support accessing string characters using square
|
||
// bracket notation. IE 8 only supports this for primitives.
|
||
isSupported = "a"[0] != "a";
|
||
} else if (name == "json") {
|
||
// Indicates whether both `JSON.stringify` and `JSON.parse` are
|
||
// supported.
|
||
isSupported = has("json-stringify") && has("json-parse");
|
||
} else {
|
||
var value, serialized = '{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}';
|
||
// Test `JSON.stringify`.
|
||
if (name == "json-stringify") {
|
||
var stringify = exports.stringify, stringifySupported = typeof stringify == "function" && isExtended;
|
||
if (stringifySupported) {
|
||
// A test function object with a custom `toJSON` method.
|
||
(value = function () {
|
||
return 1;
|
||
}).toJSON = value;
|
||
try {
|
||
stringifySupported =
|
||
// Firefox 3.1b1 and b2 serialize string, number, and boolean
|
||
// primitives as object literals.
|
||
stringify(0) === "0" &&
|
||
// FF 3.1b1, b2, and JSON 2 serialize wrapped primitives as object
|
||
// literals.
|
||
stringify(new Number()) === "0" &&
|
||
stringify(new String()) == '""' &&
|
||
// FF 3.1b1, 2 throw an error if the value is `null`, `undefined`, or
|
||
// does not define a canonical JSON representation (this applies to
|
||
// objects with `toJSON` properties as well, *unless* they are nested
|
||
// within an object or array).
|
||
stringify(getClass) === undef &&
|
||
// IE 8 serializes `undefined` as `"undefined"`. Safari <= 5.1.7 and
|
||
// FF 3.1b3 pass this test.
|
||
stringify(undef) === undef &&
|
||
// Safari <= 5.1.7 and FF 3.1b3 throw `Error`s and `TypeError`s,
|
||
// respectively, if the value is omitted entirely.
|
||
stringify() === undef &&
|
||
// FF 3.1b1, 2 throw an error if the given value is not a number,
|
||
// string, array, object, Boolean, or `null` literal. This applies to
|
||
// objects with custom `toJSON` methods as well, unless they are nested
|
||
// inside object or array literals. YUI 3.0.0b1 ignores custom `toJSON`
|
||
// methods entirely.
|
||
stringify(value) === "1" &&
|
||
stringify([value]) == "[1]" &&
|
||
// Prototype <= 1.6.1 serializes `[undefined]` as `"[]"` instead of
|
||
// `"[null]"`.
|
||
stringify([undef]) == "[null]" &&
|
||
// YUI 3.0.0b1 fails to serialize `null` literals.
|
||
stringify(null) == "null" &&
|
||
// FF 3.1b1, 2 halts serialization if an array contains a function:
|
||
// `[1, true, getClass, 1]` serializes as "[1,true,],". FF 3.1b3
|
||
// elides non-JSON values from objects and arrays, unless they
|
||
// define custom `toJSON` methods.
|
||
stringify([undef, getClass, null]) == "[null,null,null]" &&
|
||
// Simple serialization test. FF 3.1b1 uses Unicode escape sequences
|
||
// where character escape codes are expected (e.g., `\b` => `\u0008`).
|
||
stringify({ "a": [value, true, false, null, "\x00\b\n\f\r\t"] }) == serialized &&
|
||
// FF 3.1b1 and b2 ignore the `filter` and `width` arguments.
|
||
stringify(null, value) === "1" &&
|
||
stringify([1, 2], null, 1) == "[\n 1,\n 2\n]" &&
|
||
// JSON 2, Prototype <= 1.7, and older WebKit builds incorrectly
|
||
// serialize extended years.
|
||
stringify(new Date(-8.64e15)) == '"-271821-04-20T00:00:00.000Z"' &&
|
||
// The milliseconds are optional in ES 5, but required in 5.1.
|
||
stringify(new Date(8.64e15)) == '"+275760-09-13T00:00:00.000Z"' &&
|
||
// Firefox <= 11.0 incorrectly serializes years prior to 0 as negative
|
||
// four-digit years instead of six-digit years. Credits: @Yaffle.
|
||
stringify(new Date(-621987552e5)) == '"-000001-01-01T00:00:00.000Z"' &&
|
||
// Safari <= 5.1.5 and Opera >= 10.53 incorrectly serialize millisecond
|
||
// values less than 1000. Credits: @Yaffle.
|
||
stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"';
|
||
} catch (exception) {
|
||
stringifySupported = false;
|
||
}
|
||
}
|
||
isSupported = stringifySupported;
|
||
}
|
||
// Test `JSON.parse`.
|
||
if (name == "json-parse") {
|
||
var parse = exports.parse;
|
||
if (typeof parse == "function") {
|
||
try {
|
||
// FF 3.1b1, b2 will throw an exception if a bare literal is provided.
|
||
// Conforming implementations should also coerce the initial argument to
|
||
// a string prior to parsing.
|
||
if (parse("0") === 0 && !parse(false)) {
|
||
// Simple parsing test.
|
||
value = parse(serialized);
|
||
var parseSupported = value["a"].length == 5 && value["a"][0] === 1;
|
||
if (parseSupported) {
|
||
try {
|
||
// Safari <= 5.1.2 and FF 3.1b1 allow unescaped tabs in strings.
|
||
parseSupported = !parse('"\t"');
|
||
} catch (exception) {}
|
||
if (parseSupported) {
|
||
try {
|
||
// FF 4.0 and 4.0.1 allow leading `+` signs and leading
|
||
// decimal points. FF 4.0, 4.0.1, and IE 9-10 also allow
|
||
// certain octal literals.
|
||
parseSupported = parse("01") !== 1;
|
||
} catch (exception) {}
|
||
}
|
||
if (parseSupported) {
|
||
try {
|
||
// FF 4.0, 4.0.1, and Rhino 1.7R3-R4 allow trailing decimal
|
||
// points. These environments, along with FF 3.1b1 and 2,
|
||
// also allow trailing commas in JSON objects and arrays.
|
||
parseSupported = parse("1.") !== 1;
|
||
} catch (exception) {}
|
||
}
|
||
}
|
||
}
|
||
} catch (exception) {
|
||
parseSupported = false;
|
||
}
|
||
}
|
||
isSupported = parseSupported;
|
||
}
|
||
}
|
||
return has[name] = !!isSupported;
|
||
}
|
||
|
||
if (!has("json")) {
|
||
// Common `[[Class]]` name aliases.
|
||
var functionClass = "[object Function]",
|
||
dateClass = "[object Date]",
|
||
numberClass = "[object Number]",
|
||
stringClass = "[object String]",
|
||
arrayClass = "[object Array]",
|
||
booleanClass = "[object Boolean]";
|
||
|
||
// Detect incomplete support for accessing string characters by index.
|
||
var charIndexBuggy = has("bug-string-char-index");
|
||
|
||
// Define additional utility methods if the `Date` methods are buggy.
|
||
if (!isExtended) {
|
||
var floor = Math.floor;
|
||
// A mapping between the months of the year and the number of days between
|
||
// January 1st and the first of the respective month.
|
||
var Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
|
||
// Internal: Calculates the number of days between the Unix epoch and the
|
||
// first day of the given month.
|
||
var getDay = function (year, month) {
|
||
return Months[month] + 365 * (year - 1970) + floor((year - 1969 + (month = +(month > 1))) / 4) - floor((year - 1901 + month) / 100) + floor((year - 1601 + month) / 400);
|
||
};
|
||
}
|
||
|
||
// Internal: Determines if a property is a direct property of the given
|
||
// object. Delegates to the native `Object#hasOwnProperty` method.
|
||
if (!(isProperty = objectProto.hasOwnProperty)) {
|
||
isProperty = function (property) {
|
||
var members = {}, constructor;
|
||
if ((members.__proto__ = null, members.__proto__ = {
|
||
// The *proto* property cannot be set multiple times in recent
|
||
// versions of Firefox and SeaMonkey.
|
||
"toString": 1
|
||
}, members).toString != getClass) {
|
||
// Safari <= 2.0.3 doesn't implement `Object#hasOwnProperty`, but
|
||
// supports the mutable *proto* property.
|
||
isProperty = function (property) {
|
||
// Capture and break the object's prototype chain (see section 8.6.2
|
||
// of the ES 5.1 spec). The parenthesized expression prevents an
|
||
// unsafe transformation by the Closure Compiler.
|
||
var original = this.__proto__, result = property in (this.__proto__ = null, this);
|
||
// Restore the original prototype chain.
|
||
this.__proto__ = original;
|
||
return result;
|
||
};
|
||
} else {
|
||
// Capture a reference to the top-level `Object` constructor.
|
||
constructor = members.constructor;
|
||
// Use the `constructor` property to simulate `Object#hasOwnProperty` in
|
||
// other environments.
|
||
isProperty = function (property) {
|
||
var parent = (this.constructor || constructor).prototype;
|
||
return property in this && !(property in parent && this[property] === parent[property]);
|
||
};
|
||
}
|
||
members = null;
|
||
return isProperty.call(this, property);
|
||
};
|
||
}
|
||
|
||
// Internal: Normalizes the `for...in` iteration algorithm across
|
||
// environments. Each enumerated key is yielded to a `callback` function.
|
||
forEach = function (object, callback) {
|
||
var size = 0, Properties, members, property;
|
||
|
||
// Tests for bugs in the current environment's `for...in` algorithm. The
|
||
// `valueOf` property inherits the non-enumerable flag from
|
||
// `Object.prototype` in older versions of IE, Netscape, and Mozilla.
|
||
(Properties = function () {
|
||
this.valueOf = 0;
|
||
}).prototype.valueOf = 0;
|
||
|
||
// Iterate over a new instance of the `Properties` class.
|
||
members = new Properties();
|
||
for (property in members) {
|
||
// Ignore all properties inherited from `Object.prototype`.
|
||
if (isProperty.call(members, property)) {
|
||
size++;
|
||
}
|
||
}
|
||
Properties = members = null;
|
||
|
||
// Normalize the iteration algorithm.
|
||
if (!size) {
|
||
// A list of non-enumerable properties inherited from `Object.prototype`.
|
||
members = ["valueOf", "toString", "toLocaleString", "propertyIsEnumerable", "isPrototypeOf", "hasOwnProperty", "constructor"];
|
||
// IE <= 8, Mozilla 1.0, and Netscape 6.2 ignore shadowed non-enumerable
|
||
// properties.
|
||
forEach = function (object, callback) {
|
||
var isFunction = getClass.call(object) == functionClass, property, length;
|
||
var hasProperty = !isFunction && typeof object.constructor != "function" && objectTypes[typeof object.hasOwnProperty] && object.hasOwnProperty || isProperty;
|
||
for (property in object) {
|
||
// Gecko <= 1.0 enumerates the `prototype` property of functions under
|
||
// certain conditions; IE does not.
|
||
if (!(isFunction && property == "prototype") && hasProperty.call(object, property)) {
|
||
callback(property);
|
||
}
|
||
}
|
||
// Manually invoke the callback for each non-enumerable property.
|
||
for (length = members.length; property = members[--length]; hasProperty.call(object, property) && callback(property));
|
||
};
|
||
} else if (size == 2) {
|
||
// Safari <= 2.0.4 enumerates shadowed properties twice.
|
||
forEach = function (object, callback) {
|
||
// Create a set of iterated properties.
|
||
var members = {}, isFunction = getClass.call(object) == functionClass, property;
|
||
for (property in object) {
|
||
// Store each property name to prevent double enumeration. The
|
||
// `prototype` property of functions is not enumerated due to cross-
|
||
// environment inconsistencies.
|
||
if (!(isFunction && property == "prototype") && !isProperty.call(members, property) && (members[property] = 1) && isProperty.call(object, property)) {
|
||
callback(property);
|
||
}
|
||
}
|
||
};
|
||
} else {
|
||
// No bugs detected; use the standard `for...in` algorithm.
|
||
forEach = function (object, callback) {
|
||
var isFunction = getClass.call(object) == functionClass, property, isConstructor;
|
||
for (property in object) {
|
||
if (!(isFunction && property == "prototype") && isProperty.call(object, property) && !(isConstructor = property === "constructor")) {
|
||
callback(property);
|
||
}
|
||
}
|
||
// Manually invoke the callback for the `constructor` property due to
|
||
// cross-environment inconsistencies.
|
||
if (isConstructor || isProperty.call(object, (property = "constructor"))) {
|
||
callback(property);
|
||
}
|
||
};
|
||
}
|
||
return forEach(object, callback);
|
||
};
|
||
|
||
// Public: Serializes a JavaScript `value` as a JSON string. The optional
|
||
// `filter` argument may specify either a function that alters how object and
|
||
// array members are serialized, or an array of strings and numbers that
|
||
// indicates which properties should be serialized. The optional `width`
|
||
// argument may be either a string or number that specifies the indentation
|
||
// level of the output.
|
||
if (!has("json-stringify")) {
|
||
// Internal: A map of control characters and their escaped equivalents.
|
||
var Escapes = {
|
||
92: "\\\\",
|
||
34: '\\"',
|
||
8: "\\b",
|
||
12: "\\f",
|
||
10: "\\n",
|
||
13: "\\r",
|
||
9: "\\t"
|
||
};
|
||
|
||
// Internal: Converts `value` into a zero-padded string such that its
|
||
// length is at least equal to `width`. The `width` must be <= 6.
|
||
var leadingZeroes = "000000";
|
||
var toPaddedString = function (width, value) {
|
||
// The `|| 0` expression is necessary to work around a bug in
|
||
// Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== "0"`.
|
||
return (leadingZeroes + (value || 0)).slice(-width);
|
||
};
|
||
|
||
// Internal: Double-quotes a string `value`, replacing all ASCII control
|
||
// characters (characters with code unit values between 0 and 31) with
|
||
// their escaped equivalents. This is an implementation of the
|
||
// `Quote(value)` operation defined in ES 5.1 section 15.12.3.
|
||
var unicodePrefix = "\\u00";
|
||
var quote = function (value) {
|
||
var result = '"', index = 0, length = value.length, useCharIndex = !charIndexBuggy || length > 10;
|
||
var symbols = useCharIndex && (charIndexBuggy ? value.split("") : value);
|
||
for (; index < length; index++) {
|
||
var charCode = value.charCodeAt(index);
|
||
// If the character is a control character, append its Unicode or
|
||
// shorthand escape sequence; otherwise, append the character as-is.
|
||
switch (charCode) {
|
||
case 8: case 9: case 10: case 12: case 13: case 34: case 92:
|
||
result += Escapes[charCode];
|
||
break;
|
||
default:
|
||
if (charCode < 32) {
|
||
result += unicodePrefix + toPaddedString(2, charCode.toString(16));
|
||
break;
|
||
}
|
||
result += useCharIndex ? symbols[index] : value.charAt(index);
|
||
}
|
||
}
|
||
return result + '"';
|
||
};
|
||
|
||
// Internal: Recursively serializes an object. Implements the
|
||
// `Str(key, holder)`, `JO(value)`, and `JA(value)` operations.
|
||
var serialize = function (property, object, callback, properties, whitespace, indentation, stack) {
|
||
var value, className, year, month, date, time, hours, minutes, seconds, milliseconds, results, element, index, length, prefix, result;
|
||
try {
|
||
// Necessary for host object support.
|
||
value = object[property];
|
||
} catch (exception) {}
|
||
if (typeof value == "object" && value) {
|
||
className = getClass.call(value);
|
||
if (className == dateClass && !isProperty.call(value, "toJSON")) {
|
||
if (value > -1 / 0 && value < 1 / 0) {
|
||
// Dates are serialized according to the `Date#toJSON` method
|
||
// specified in ES 5.1 section 15.9.5.44. See section 15.9.1.15
|
||
// for the ISO 8601 date time string format.
|
||
if (getDay) {
|
||
// Manually compute the year, month, date, hours, minutes,
|
||
// seconds, and milliseconds if the `getUTC*` methods are
|
||
// buggy. Adapted from @Yaffle's `date-shim` project.
|
||
date = floor(value / 864e5);
|
||
for (year = floor(date / 365.2425) + 1970 - 1; getDay(year + 1, 0) <= date; year++);
|
||
for (month = floor((date - getDay(year, 0)) / 30.42); getDay(year, month + 1) <= date; month++);
|
||
date = 1 + date - getDay(year, month);
|
||
// The `time` value specifies the time within the day (see ES
|
||
// 5.1 section 15.9.1.2). The formula `(A % B + B) % B` is used
|
||
// to compute `A modulo B`, as the `%` operator does not
|
||
// correspond to the `modulo` operation for negative numbers.
|
||
time = (value % 864e5 + 864e5) % 864e5;
|
||
// The hours, minutes, seconds, and milliseconds are obtained by
|
||
// decomposing the time within the day. See section 15.9.1.10.
|
||
hours = floor(time / 36e5) % 24;
|
||
minutes = floor(time / 6e4) % 60;
|
||
seconds = floor(time / 1e3) % 60;
|
||
milliseconds = time % 1e3;
|
||
} else {
|
||
year = value.getUTCFullYear();
|
||
month = value.getUTCMonth();
|
||
date = value.getUTCDate();
|
||
hours = value.getUTCHours();
|
||
minutes = value.getUTCMinutes();
|
||
seconds = value.getUTCSeconds();
|
||
milliseconds = value.getUTCMilliseconds();
|
||
}
|
||
// Serialize extended years correctly.
|
||
value = (year <= 0 || year >= 1e4 ? (year < 0 ? "-" : "+") + toPaddedString(6, year < 0 ? -year : year) : toPaddedString(4, year)) +
|
||
"-" + toPaddedString(2, month + 1) + "-" + toPaddedString(2, date) +
|
||
// Months, dates, hours, minutes, and seconds should have two
|
||
// digits; milliseconds should have three.
|
||
"T" + toPaddedString(2, hours) + ":" + toPaddedString(2, minutes) + ":" + toPaddedString(2, seconds) +
|
||
// Milliseconds are optional in ES 5.0, but required in 5.1.
|
||
"." + toPaddedString(3, milliseconds) + "Z";
|
||
} else {
|
||
value = null;
|
||
}
|
||
} else if (typeof value.toJSON == "function" && ((className != numberClass && className != stringClass && className != arrayClass) || isProperty.call(value, "toJSON"))) {
|
||
// Prototype <= 1.6.1 adds non-standard `toJSON` methods to the
|
||
// `Number`, `String`, `Date`, and `Array` prototypes. JSON 3
|
||
// ignores all `toJSON` methods on these objects unless they are
|
||
// defined directly on an instance.
|
||
value = value.toJSON(property);
|
||
}
|
||
}
|
||
if (callback) {
|
||
// If a replacement function was provided, call it to obtain the value
|
||
// for serialization.
|
||
value = callback.call(object, property, value);
|
||
}
|
||
if (value === null) {
|
||
return "null";
|
||
}
|
||
className = getClass.call(value);
|
||
if (className == booleanClass) {
|
||
// Booleans are represented literally.
|
||
return "" + value;
|
||
} else if (className == numberClass) {
|
||
// JSON numbers must be finite. `Infinity` and `NaN` are serialized as
|
||
// `"null"`.
|
||
return value > -1 / 0 && value < 1 / 0 ? "" + value : "null";
|
||
} else if (className == stringClass) {
|
||
// Strings are double-quoted and escaped.
|
||
return quote("" + value);
|
||
}
|
||
// Recursively serialize objects and arrays.
|
||
if (typeof value == "object") {
|
||
// Check for cyclic structures. This is a linear search; performance
|
||
// is inversely proportional to the number of unique nested objects.
|
||
for (length = stack.length; length--;) {
|
||
if (stack[length] === value) {
|
||
// Cyclic structures cannot be serialized by `JSON.stringify`.
|
||
throw TypeError();
|
||
}
|
||
}
|
||
// Add the object to the stack of traversed objects.
|
||
stack.push(value);
|
||
results = [];
|
||
// Save the current indentation level and indent one additional level.
|
||
prefix = indentation;
|
||
indentation += whitespace;
|
||
if (className == arrayClass) {
|
||
// Recursively serialize array elements.
|
||
for (index = 0, length = value.length; index < length; index++) {
|
||
element = serialize(index, value, callback, properties, whitespace, indentation, stack);
|
||
results.push(element === undef ? "null" : element);
|
||
}
|
||
result = results.length ? (whitespace ? "[\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "]" : ("[" + results.join(",") + "]")) : "[]";
|
||
} else {
|
||
// Recursively serialize object members. Members are selected from
|
||
// either a user-specified list of property names, or the object
|
||
// itself.
|
||
forEach(properties || value, function (property) {
|
||
var element = serialize(property, value, callback, properties, whitespace, indentation, stack);
|
||
if (element !== undef) {
|
||
// According to ES 5.1 section 15.12.3: "If `gap` {whitespace}
|
||
// is not the empty string, let `member` {quote(property) + ":"}
|
||
// be the concatenation of `member` and the `space` character."
|
||
// The "`space` character" refers to the literal space
|
||
// character, not the `space` {width} argument provided to
|
||
// `JSON.stringify`.
|
||
results.push(quote(property) + ":" + (whitespace ? " " : "") + element);
|
||
}
|
||
});
|
||
result = results.length ? (whitespace ? "{\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "}" : ("{" + results.join(",") + "}")) : "{}";
|
||
}
|
||
// Remove the object from the traversed object stack.
|
||
stack.pop();
|
||
return result;
|
||
}
|
||
};
|
||
|
||
// Public: `JSON.stringify`. See ES 5.1 section 15.12.3.
|
||
exports.stringify = function (source, filter, width) {
|
||
var whitespace, callback, properties, className;
|
||
if (objectTypes[typeof filter] && filter) {
|
||
if ((className = getClass.call(filter)) == functionClass) {
|
||
callback = filter;
|
||
} else if (className == arrayClass) {
|
||
// Convert the property names array into a makeshift set.
|
||
properties = {};
|
||
for (var index = 0, length = filter.length, value; index < length; value = filter[index++], ((className = getClass.call(value)), className == stringClass || className == numberClass) && (properties[value] = 1));
|
||
}
|
||
}
|
||
if (width) {
|
||
if ((className = getClass.call(width)) == numberClass) {
|
||
// Convert the `width` to an integer and create a string containing
|
||
// `width` number of space characters.
|
||
if ((width -= width % 1) > 0) {
|
||
for (whitespace = "", width > 10 && (width = 10); whitespace.length < width; whitespace += " ");
|
||
}
|
||
} else if (className == stringClass) {
|
||
whitespace = width.length <= 10 ? width : width.slice(0, 10);
|
||
}
|
||
}
|
||
// Opera <= 7.54u2 discards the values associated with empty string keys
|
||
// (`""`) only if they are used directly within an object member list
|
||
// (e.g., `!("" in { "": 1})`).
|
||
return serialize("", (value = {}, value[""] = source, value), callback, properties, whitespace, "", []);
|
||
};
|
||
}
|
||
|
||
// Public: Parses a JSON source string.
|
||
if (!has("json-parse")) {
|
||
var fromCharCode = String.fromCharCode;
|
||
|
||
// Internal: A map of escaped control characters and their unescaped
|
||
// equivalents.
|
||
var Unescapes = {
|
||
92: "\\",
|
||
34: '"',
|
||
47: "/",
|
||
98: "\b",
|
||
116: "\t",
|
||
110: "\n",
|
||
102: "\f",
|
||
114: "\r"
|
||
};
|
||
|
||
// Internal: Stores the parser state.
|
||
var Index, Source;
|
||
|
||
// Internal: Resets the parser state and throws a `SyntaxError`.
|
||
var abort = function () {
|
||
Index = Source = null;
|
||
throw SyntaxError();
|
||
};
|
||
|
||
// Internal: Returns the next token, or `"$"` if the parser has reached
|
||
// the end of the source string. A token may be a string, number, `null`
|
||
// literal, or Boolean literal.
|
||
var lex = function () {
|
||
var source = Source, length = source.length, value, begin, position, isSigned, charCode;
|
||
while (Index < length) {
|
||
charCode = source.charCodeAt(Index);
|
||
switch (charCode) {
|
||
case 9: case 10: case 13: case 32:
|
||
// Skip whitespace tokens, including tabs, carriage returns, line
|
||
// feeds, and space characters.
|
||
Index++;
|
||
break;
|
||
case 123: case 125: case 91: case 93: case 58: case 44:
|
||
// Parse a punctuator token (`{`, `}`, `[`, `]`, `:`, or `,`) at
|
||
// the current position.
|
||
value = charIndexBuggy ? source.charAt(Index) : source[Index];
|
||
Index++;
|
||
return value;
|
||
case 34:
|
||
// `"` delimits a JSON string; advance to the next character and
|
||
// begin parsing the string. String tokens are prefixed with the
|
||
// sentinel `@` character to distinguish them from punctuators and
|
||
// end-of-string tokens.
|
||
for (value = "@", Index++; Index < length;) {
|
||
charCode = source.charCodeAt(Index);
|
||
if (charCode < 32) {
|
||
// Unescaped ASCII control characters (those with a code unit
|
||
// less than the space character) are not permitted.
|
||
abort();
|
||
} else if (charCode == 92) {
|
||
// A reverse solidus (`\`) marks the beginning of an escaped
|
||
// control character (including `"`, `\`, and `/`) or Unicode
|
||
// escape sequence.
|
||
charCode = source.charCodeAt(++Index);
|
||
switch (charCode) {
|
||
case 92: case 34: case 47: case 98: case 116: case 110: case 102: case 114:
|
||
// Revive escaped control characters.
|
||
value += Unescapes[charCode];
|
||
Index++;
|
||
break;
|
||
case 117:
|
||
// `\u` marks the beginning of a Unicode escape sequence.
|
||
// Advance to the first character and validate the
|
||
// four-digit code point.
|
||
begin = ++Index;
|
||
for (position = Index + 4; Index < position; Index++) {
|
||
charCode = source.charCodeAt(Index);
|
||
// A valid sequence comprises four hexdigits (case-
|
||
// insensitive) that form a single hexadecimal value.
|
||
if (!(charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70)) {
|
||
// Invalid Unicode escape sequence.
|
||
abort();
|
||
}
|
||
}
|
||
// Revive the escaped character.
|
||
value += fromCharCode("0x" + source.slice(begin, Index));
|
||
break;
|
||
default:
|
||
// Invalid escape sequence.
|
||
abort();
|
||
}
|
||
} else {
|
||
if (charCode == 34) {
|
||
// An unescaped double-quote character marks the end of the
|
||
// string.
|
||
break;
|
||
}
|
||
charCode = source.charCodeAt(Index);
|
||
begin = Index;
|
||
// Optimize for the common case where a string is valid.
|
||
while (charCode >= 32 && charCode != 92 && charCode != 34) {
|
||
charCode = source.charCodeAt(++Index);
|
||
}
|
||
// Append the string as-is.
|
||
value += source.slice(begin, Index);
|
||
}
|
||
}
|
||
if (source.charCodeAt(Index) == 34) {
|
||
// Advance to the next character and return the revived string.
|
||
Index++;
|
||
return value;
|
||
}
|
||
// Unterminated string.
|
||
abort();
|
||
default:
|
||
// Parse numbers and literals.
|
||
begin = Index;
|
||
// Advance past the negative sign, if one is specified.
|
||
if (charCode == 45) {
|
||
isSigned = true;
|
||
charCode = source.charCodeAt(++Index);
|
||
}
|
||
// Parse an integer or floating-point value.
|
||
if (charCode >= 48 && charCode <= 57) {
|
||
// Leading zeroes are interpreted as octal literals.
|
||
if (charCode == 48 && ((charCode = source.charCodeAt(Index + 1)), charCode >= 48 && charCode <= 57)) {
|
||
// Illegal octal literal.
|
||
abort();
|
||
}
|
||
isSigned = false;
|
||
// Parse the integer component.
|
||
for (; Index < length && ((charCode = source.charCodeAt(Index)), charCode >= 48 && charCode <= 57); Index++);
|
||
// Floats cannot contain a leading decimal point; however, this
|
||
// case is already accounted for by the parser.
|
||
if (source.charCodeAt(Index) == 46) {
|
||
position = ++Index;
|
||
// Parse the decimal component.
|
||
for (; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++);
|
||
if (position == Index) {
|
||
// Illegal trailing decimal.
|
||
abort();
|
||
}
|
||
Index = position;
|
||
}
|
||
// Parse exponents. The `e` denoting the exponent is
|
||
// case-insensitive.
|
||
charCode = source.charCodeAt(Index);
|
||
if (charCode == 101 || charCode == 69) {
|
||
charCode = source.charCodeAt(++Index);
|
||
// Skip past the sign following the exponent, if one is
|
||
// specified.
|
||
if (charCode == 43 || charCode == 45) {
|
||
Index++;
|
||
}
|
||
// Parse the exponential component.
|
||
for (position = Index; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++);
|
||
if (position == Index) {
|
||
// Illegal empty exponent.
|
||
abort();
|
||
}
|
||
Index = position;
|
||
}
|
||
// Coerce the parsed value to a JavaScript number.
|
||
return +source.slice(begin, Index);
|
||
}
|
||
// A negative sign may only precede numbers.
|
||
if (isSigned) {
|
||
abort();
|
||
}
|
||
// `true`, `false`, and `null` literals.
|
||
if (source.slice(Index, Index + 4) == "true") {
|
||
Index += 4;
|
||
return true;
|
||
} else if (source.slice(Index, Index + 5) == "false") {
|
||
Index += 5;
|
||
return false;
|
||
} else if (source.slice(Index, Index + 4) == "null") {
|
||
Index += 4;
|
||
return null;
|
||
}
|
||
// Unrecognized token.
|
||
abort();
|
||
}
|
||
}
|
||
// Return the sentinel `$` character if the parser has reached the end
|
||
// of the source string.
|
||
return "$";
|
||
};
|
||
|
||
// Internal: Parses a JSON `value` token.
|
||
var get = function (value) {
|
||
var results, hasMembers;
|
||
if (value == "$") {
|
||
// Unexpected end of input.
|
||
abort();
|
||
}
|
||
if (typeof value == "string") {
|
||
if ((charIndexBuggy ? value.charAt(0) : value[0]) == "@") {
|
||
// Remove the sentinel `@` character.
|
||
return value.slice(1);
|
||
}
|
||
// Parse object and array literals.
|
||
if (value == "[") {
|
||
// Parses a JSON array, returning a new JavaScript array.
|
||
results = [];
|
||
for (;; hasMembers || (hasMembers = true)) {
|
||
value = lex();
|
||
// A closing square bracket marks the end of the array literal.
|
||
if (value == "]") {
|
||
break;
|
||
}
|
||
// If the array literal contains elements, the current token
|
||
// should be a comma separating the previous element from the
|
||
// next.
|
||
if (hasMembers) {
|
||
if (value == ",") {
|
||
value = lex();
|
||
if (value == "]") {
|
||
// Unexpected trailing `,` in array literal.
|
||
abort();
|
||
}
|
||
} else {
|
||
// A `,` must separate each array element.
|
||
abort();
|
||
}
|
||
}
|
||
// Elisions and leading commas are not permitted.
|
||
if (value == ",") {
|
||
abort();
|
||
}
|
||
results.push(get(value));
|
||
}
|
||
return results;
|
||
} else if (value == "{") {
|
||
// Parses a JSON object, returning a new JavaScript object.
|
||
results = {};
|
||
for (;; hasMembers || (hasMembers = true)) {
|
||
value = lex();
|
||
// A closing curly brace marks the end of the object literal.
|
||
if (value == "}") {
|
||
break;
|
||
}
|
||
// If the object literal contains members, the current token
|
||
// should be a comma separator.
|
||
if (hasMembers) {
|
||
if (value == ",") {
|
||
value = lex();
|
||
if (value == "}") {
|
||
// Unexpected trailing `,` in object literal.
|
||
abort();
|
||
}
|
||
} else {
|
||
// A `,` must separate each object member.
|
||
abort();
|
||
}
|
||
}
|
||
// Leading commas are not permitted, object property names must be
|
||
// double-quoted strings, and a `:` must separate each property
|
||
// name and value.
|
||
if (value == "," || typeof value != "string" || (charIndexBuggy ? value.charAt(0) : value[0]) != "@" || lex() != ":") {
|
||
abort();
|
||
}
|
||
results[value.slice(1)] = get(lex());
|
||
}
|
||
return results;
|
||
}
|
||
// Unexpected token encountered.
|
||
abort();
|
||
}
|
||
return value;
|
||
};
|
||
|
||
// Internal: Updates a traversed object member.
|
||
var update = function (source, property, callback) {
|
||
var element = walk(source, property, callback);
|
||
if (element === undef) {
|
||
delete source[property];
|
||
} else {
|
||
source[property] = element;
|
||
}
|
||
};
|
||
|
||
// Internal: Recursively traverses a parsed JSON object, invoking the
|
||
// `callback` function for each value. This is an implementation of the
|
||
// `Walk(holder, name)` operation defined in ES 5.1 section 15.12.2.
|
||
var walk = function (source, property, callback) {
|
||
var value = source[property], length;
|
||
if (typeof value == "object" && value) {
|
||
// `forEach` can't be used to traverse an array in Opera <= 8.54
|
||
// because its `Object#hasOwnProperty` implementation returns `false`
|
||
// for array indices (e.g., `![1, 2, 3].hasOwnProperty("0")`).
|
||
if (getClass.call(value) == arrayClass) {
|
||
for (length = value.length; length--;) {
|
||
update(value, length, callback);
|
||
}
|
||
} else {
|
||
forEach(value, function (property) {
|
||
update(value, property, callback);
|
||
});
|
||
}
|
||
}
|
||
return callback.call(source, property, value);
|
||
};
|
||
|
||
// Public: `JSON.parse`. See ES 5.1 section 15.12.2.
|
||
exports.parse = function (source, callback) {
|
||
var result, value;
|
||
Index = 0;
|
||
Source = "" + source;
|
||
result = get(lex());
|
||
// If a JSON string contains multiple tokens, it is invalid.
|
||
if (lex() != "$") {
|
||
abort();
|
||
}
|
||
// Reset the parser state.
|
||
Index = Source = null;
|
||
return callback && getClass.call(callback) == functionClass ? walk((value = {}, value[""] = result, value), "", callback) : result;
|
||
};
|
||
}
|
||
}
|
||
|
||
exports["runInContext"] = runInContext;
|
||
return exports;
|
||
}
|
||
|
||
if (freeExports && !isLoader) {
|
||
// Export for CommonJS environments.
|
||
runInContext(root, freeExports);
|
||
} else {
|
||
// Export for web browsers and JavaScript engines.
|
||
var nativeJSON = root.JSON,
|
||
previousJSON = root["JSON3"],
|
||
isRestored = false;
|
||
|
||
var JSON3 = runInContext(root, (root["JSON3"] = {
|
||
// Public: Restores the original value of the global `JSON` object and
|
||
// returns a reference to the `JSON3` object.
|
||
"noConflict": function () {
|
||
if (!isRestored) {
|
||
isRestored = true;
|
||
root.JSON = nativeJSON;
|
||
root["JSON3"] = previousJSON;
|
||
nativeJSON = previousJSON = null;
|
||
}
|
||
return JSON3;
|
||
}
|
||
}));
|
||
|
||
root.JSON = {
|
||
"parse": JSON3.parse,
|
||
"stringify": JSON3.stringify
|
||
};
|
||
}
|
||
|
||
// Export for asynchronous module loaders.
|
||
if (isLoader) {
|
||
!(__WEBPACK_AMD_DEFINE_RESULT__ = function () {
|
||
return JSON3;
|
||
}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
|
||
}
|
||
}).call(this);
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(76)(module), (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 76 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = function(module) {
|
||
if(!module.webpackPolyfill) {
|
||
module.deprecate = function() {};
|
||
module.paths = [];
|
||
// module.parent = undefined by default
|
||
module.children = [];
|
||
module.webpackPolyfill = 1;
|
||
}
|
||
return module;
|
||
}
|
||
|
||
|
||
/***/ },
|
||
/* 77 */
|
||
/***/ function(module, exports) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(__webpack_amd_options__) {module.exports = __webpack_amd_options__;
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, {}))
|
||
|
||
/***/ },
|
||
/* 78 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = Array.isArray || function (arr) {
|
||
return Object.prototype.toString.call(arr) == '[object Array]';
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 79 */
|
||
/***/ function(module, exports) {
|
||
|
||
|
||
/**
|
||
* Expose `Emitter`.
|
||
*/
|
||
|
||
module.exports = Emitter;
|
||
|
||
/**
|
||
* Initialize a new `Emitter`.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
function Emitter(obj) {
|
||
if (obj) return mixin(obj);
|
||
};
|
||
|
||
/**
|
||
* Mixin the emitter properties.
|
||
*
|
||
* @param {Object} obj
|
||
* @return {Object}
|
||
* @api private
|
||
*/
|
||
|
||
function mixin(obj) {
|
||
for (var key in Emitter.prototype) {
|
||
obj[key] = Emitter.prototype[key];
|
||
}
|
||
return obj;
|
||
}
|
||
|
||
/**
|
||
* Listen on the given `event` with `fn`.
|
||
*
|
||
* @param {String} event
|
||
* @param {Function} fn
|
||
* @return {Emitter}
|
||
* @api public
|
||
*/
|
||
|
||
Emitter.prototype.on =
|
||
Emitter.prototype.addEventListener = function(event, fn){
|
||
this._callbacks = this._callbacks || {};
|
||
(this._callbacks[event] = this._callbacks[event] || [])
|
||
.push(fn);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Adds an `event` listener that will be invoked a single
|
||
* time then automatically removed.
|
||
*
|
||
* @param {String} event
|
||
* @param {Function} fn
|
||
* @return {Emitter}
|
||
* @api public
|
||
*/
|
||
|
||
Emitter.prototype.once = function(event, fn){
|
||
var self = this;
|
||
this._callbacks = this._callbacks || {};
|
||
|
||
function on() {
|
||
self.off(event, on);
|
||
fn.apply(this, arguments);
|
||
}
|
||
|
||
on.fn = fn;
|
||
this.on(event, on);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Remove the given callback for `event` or all
|
||
* registered callbacks.
|
||
*
|
||
* @param {String} event
|
||
* @param {Function} fn
|
||
* @return {Emitter}
|
||
* @api public
|
||
*/
|
||
|
||
Emitter.prototype.off =
|
||
Emitter.prototype.removeListener =
|
||
Emitter.prototype.removeAllListeners =
|
||
Emitter.prototype.removeEventListener = function(event, fn){
|
||
this._callbacks = this._callbacks || {};
|
||
|
||
// all
|
||
if (0 == arguments.length) {
|
||
this._callbacks = {};
|
||
return this;
|
||
}
|
||
|
||
// specific event
|
||
var callbacks = this._callbacks[event];
|
||
if (!callbacks) return this;
|
||
|
||
// remove all handlers
|
||
if (1 == arguments.length) {
|
||
delete this._callbacks[event];
|
||
return this;
|
||
}
|
||
|
||
// remove specific handler
|
||
var cb;
|
||
for (var i = 0; i < callbacks.length; i++) {
|
||
cb = callbacks[i];
|
||
if (cb === fn || cb.fn === fn) {
|
||
callbacks.splice(i, 1);
|
||
break;
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Emit `event` with the given args.
|
||
*
|
||
* @param {String} event
|
||
* @param {Mixed} ...
|
||
* @return {Emitter}
|
||
*/
|
||
|
||
Emitter.prototype.emit = function(event){
|
||
this._callbacks = this._callbacks || {};
|
||
var args = [].slice.call(arguments, 1)
|
||
, callbacks = this._callbacks[event];
|
||
|
||
if (callbacks) {
|
||
callbacks = callbacks.slice(0);
|
||
for (var i = 0, len = callbacks.length; i < len; ++i) {
|
||
callbacks[i].apply(this, args);
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Return array of callbacks for `event`.
|
||
*
|
||
* @param {String} event
|
||
* @return {Array}
|
||
* @api public
|
||
*/
|
||
|
||
Emitter.prototype.listeners = function(event){
|
||
this._callbacks = this._callbacks || {};
|
||
return this._callbacks[event] || [];
|
||
};
|
||
|
||
/**
|
||
* Check if this emitter has `event` handlers.
|
||
*
|
||
* @param {String} event
|
||
* @return {Boolean}
|
||
* @api public
|
||
*/
|
||
|
||
Emitter.prototype.hasListeners = function(event){
|
||
return !! this.listeners(event).length;
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 80 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(global) {/*global Blob,File*/
|
||
|
||
/**
|
||
* Module requirements
|
||
*/
|
||
|
||
var isArray = __webpack_require__(78);
|
||
var isBuf = __webpack_require__(81);
|
||
|
||
/**
|
||
* Replaces every Buffer | ArrayBuffer in packet with a numbered placeholder.
|
||
* Anything with blobs or files should be fed through removeBlobs before coming
|
||
* here.
|
||
*
|
||
* @param {Object} packet - socket.io event packet
|
||
* @return {Object} with deconstructed packet and list of buffers
|
||
* @api public
|
||
*/
|
||
|
||
exports.deconstructPacket = function(packet){
|
||
var buffers = [];
|
||
var packetData = packet.data;
|
||
|
||
function _deconstructPacket(data) {
|
||
if (!data) return data;
|
||
|
||
if (isBuf(data)) {
|
||
var placeholder = { _placeholder: true, num: buffers.length };
|
||
buffers.push(data);
|
||
return placeholder;
|
||
} else if (isArray(data)) {
|
||
var newData = new Array(data.length);
|
||
for (var i = 0; i < data.length; i++) {
|
||
newData[i] = _deconstructPacket(data[i]);
|
||
}
|
||
return newData;
|
||
} else if ('object' == typeof data && !(data instanceof Date)) {
|
||
var newData = {};
|
||
for (var key in data) {
|
||
newData[key] = _deconstructPacket(data[key]);
|
||
}
|
||
return newData;
|
||
}
|
||
return data;
|
||
}
|
||
|
||
var pack = packet;
|
||
pack.data = _deconstructPacket(packetData);
|
||
pack.attachments = buffers.length; // number of binary 'attachments'
|
||
return {packet: pack, buffers: buffers};
|
||
};
|
||
|
||
/**
|
||
* Reconstructs a binary packet from its placeholder packet and buffers
|
||
*
|
||
* @param {Object} packet - event packet with placeholders
|
||
* @param {Array} buffers - binary buffers to put in placeholder positions
|
||
* @return {Object} reconstructed packet
|
||
* @api public
|
||
*/
|
||
|
||
exports.reconstructPacket = function(packet, buffers) {
|
||
var curPlaceHolder = 0;
|
||
|
||
function _reconstructPacket(data) {
|
||
if (data && data._placeholder) {
|
||
var buf = buffers[data.num]; // appropriate buffer (should be natural order anyway)
|
||
return buf;
|
||
} else if (isArray(data)) {
|
||
for (var i = 0; i < data.length; i++) {
|
||
data[i] = _reconstructPacket(data[i]);
|
||
}
|
||
return data;
|
||
} else if (data && 'object' == typeof data) {
|
||
for (var key in data) {
|
||
data[key] = _reconstructPacket(data[key]);
|
||
}
|
||
return data;
|
||
}
|
||
return data;
|
||
}
|
||
|
||
packet.data = _reconstructPacket(packet.data);
|
||
packet.attachments = undefined; // no longer useful
|
||
return packet;
|
||
};
|
||
|
||
/**
|
||
* Asynchronously removes Blobs or Files from data via
|
||
* FileReader's readAsArrayBuffer method. Used before encoding
|
||
* data as msgpack. Calls callback with the blobless data.
|
||
*
|
||
* @param {Object} data
|
||
* @param {Function} callback
|
||
* @api private
|
||
*/
|
||
|
||
exports.removeBlobs = function(data, callback) {
|
||
function _removeBlobs(obj, curKey, containingObject) {
|
||
if (!obj) return obj;
|
||
|
||
// convert any blob
|
||
if ((global.Blob && obj instanceof Blob) ||
|
||
(global.File && obj instanceof File)) {
|
||
pendingBlobs++;
|
||
|
||
// async filereader
|
||
var fileReader = new FileReader();
|
||
fileReader.onload = function() { // this.result == arraybuffer
|
||
if (containingObject) {
|
||
containingObject[curKey] = this.result;
|
||
}
|
||
else {
|
||
bloblessData = this.result;
|
||
}
|
||
|
||
// if nothing pending its callback time
|
||
if(! --pendingBlobs) {
|
||
callback(bloblessData);
|
||
}
|
||
};
|
||
|
||
fileReader.readAsArrayBuffer(obj); // blob -> arraybuffer
|
||
} else if (isArray(obj)) { // handle array
|
||
for (var i = 0; i < obj.length; i++) {
|
||
_removeBlobs(obj[i], i, obj);
|
||
}
|
||
} else if (obj && 'object' == typeof obj && !isBuf(obj)) { // and object
|
||
for (var key in obj) {
|
||
_removeBlobs(obj[key], key, obj);
|
||
}
|
||
}
|
||
}
|
||
|
||
var pendingBlobs = 0;
|
||
var bloblessData = data;
|
||
_removeBlobs(bloblessData);
|
||
if (!pendingBlobs) {
|
||
callback(bloblessData);
|
||
}
|
||
};
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 81 */
|
||
/***/ function(module, exports) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(global) {
|
||
module.exports = isBuf;
|
||
|
||
/**
|
||
* Returns true if obj is a buffer or an arraybuffer.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
function isBuf(obj) {
|
||
return (global.Buffer && global.Buffer.isBuffer(obj)) ||
|
||
(global.ArrayBuffer && obj instanceof ArrayBuffer);
|
||
}
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 82 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
|
||
/**
|
||
* Module dependencies.
|
||
*/
|
||
|
||
var eio = __webpack_require__(83);
|
||
var Socket = __webpack_require__(110);
|
||
var Emitter = __webpack_require__(111);
|
||
var parser = __webpack_require__(74);
|
||
var on = __webpack_require__(113);
|
||
var bind = __webpack_require__(114);
|
||
var debug = __webpack_require__(71)('socket.io-client:manager');
|
||
var indexOf = __webpack_require__(108);
|
||
var Backoff = __webpack_require__(117);
|
||
|
||
/**
|
||
* IE6+ hasOwnProperty
|
||
*/
|
||
|
||
var has = Object.prototype.hasOwnProperty;
|
||
|
||
/**
|
||
* Module exports
|
||
*/
|
||
|
||
module.exports = Manager;
|
||
|
||
/**
|
||
* `Manager` constructor.
|
||
*
|
||
* @param {String} engine instance or engine uri/opts
|
||
* @param {Object} options
|
||
* @api public
|
||
*/
|
||
|
||
function Manager(uri, opts){
|
||
if (!(this instanceof Manager)) return new Manager(uri, opts);
|
||
if (uri && ('object' == typeof uri)) {
|
||
opts = uri;
|
||
uri = undefined;
|
||
}
|
||
opts = opts || {};
|
||
|
||
opts.path = opts.path || '/socket.io';
|
||
this.nsps = {};
|
||
this.subs = [];
|
||
this.opts = opts;
|
||
this.reconnection(opts.reconnection !== false);
|
||
this.reconnectionAttempts(opts.reconnectionAttempts || Infinity);
|
||
this.reconnectionDelay(opts.reconnectionDelay || 1000);
|
||
this.reconnectionDelayMax(opts.reconnectionDelayMax || 5000);
|
||
this.randomizationFactor(opts.randomizationFactor || 0.5);
|
||
this.backoff = new Backoff({
|
||
min: this.reconnectionDelay(),
|
||
max: this.reconnectionDelayMax(),
|
||
jitter: this.randomizationFactor()
|
||
});
|
||
this.timeout(null == opts.timeout ? 20000 : opts.timeout);
|
||
this.readyState = 'closed';
|
||
this.uri = uri;
|
||
this.connecting = [];
|
||
this.lastPing = null;
|
||
this.encoding = false;
|
||
this.packetBuffer = [];
|
||
this.encoder = new parser.Encoder();
|
||
this.decoder = new parser.Decoder();
|
||
this.autoConnect = opts.autoConnect !== false;
|
||
if (this.autoConnect) this.open();
|
||
}
|
||
|
||
/**
|
||
* Propagate given event to sockets and emit on `this`
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.emitAll = function() {
|
||
this.emit.apply(this, arguments);
|
||
for (var nsp in this.nsps) {
|
||
if (has.call(this.nsps, nsp)) {
|
||
this.nsps[nsp].emit.apply(this.nsps[nsp], arguments);
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Update `socket.id` of all sockets
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.updateSocketIds = function(){
|
||
for (var nsp in this.nsps) {
|
||
if (has.call(this.nsps, nsp)) {
|
||
this.nsps[nsp].id = this.engine.id;
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Mix in `Emitter`.
|
||
*/
|
||
|
||
Emitter(Manager.prototype);
|
||
|
||
/**
|
||
* Sets the `reconnection` config.
|
||
*
|
||
* @param {Boolean} true/false if it should automatically reconnect
|
||
* @return {Manager} self or value
|
||
* @api public
|
||
*/
|
||
|
||
Manager.prototype.reconnection = function(v){
|
||
if (!arguments.length) return this._reconnection;
|
||
this._reconnection = !!v;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the reconnection attempts config.
|
||
*
|
||
* @param {Number} max reconnection attempts before giving up
|
||
* @return {Manager} self or value
|
||
* @api public
|
||
*/
|
||
|
||
Manager.prototype.reconnectionAttempts = function(v){
|
||
if (!arguments.length) return this._reconnectionAttempts;
|
||
this._reconnectionAttempts = v;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the delay between reconnections.
|
||
*
|
||
* @param {Number} delay
|
||
* @return {Manager} self or value
|
||
* @api public
|
||
*/
|
||
|
||
Manager.prototype.reconnectionDelay = function(v){
|
||
if (!arguments.length) return this._reconnectionDelay;
|
||
this._reconnectionDelay = v;
|
||
this.backoff && this.backoff.setMin(v);
|
||
return this;
|
||
};
|
||
|
||
Manager.prototype.randomizationFactor = function(v){
|
||
if (!arguments.length) return this._randomizationFactor;
|
||
this._randomizationFactor = v;
|
||
this.backoff && this.backoff.setJitter(v);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the maximum delay between reconnections.
|
||
*
|
||
* @param {Number} delay
|
||
* @return {Manager} self or value
|
||
* @api public
|
||
*/
|
||
|
||
Manager.prototype.reconnectionDelayMax = function(v){
|
||
if (!arguments.length) return this._reconnectionDelayMax;
|
||
this._reconnectionDelayMax = v;
|
||
this.backoff && this.backoff.setMax(v);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the connection timeout. `false` to disable
|
||
*
|
||
* @return {Manager} self or value
|
||
* @api public
|
||
*/
|
||
|
||
Manager.prototype.timeout = function(v){
|
||
if (!arguments.length) return this._timeout;
|
||
this._timeout = v;
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Starts trying to reconnect if reconnection is enabled and we have not
|
||
* started reconnecting yet
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.maybeReconnectOnOpen = function() {
|
||
// Only try to reconnect if it's the first time we're connecting
|
||
if (!this.reconnecting && this._reconnection && this.backoff.attempts === 0) {
|
||
// keeps reconnection from firing twice for the same reconnection loop
|
||
this.reconnect();
|
||
}
|
||
};
|
||
|
||
|
||
/**
|
||
* Sets the current transport `socket`.
|
||
*
|
||
* @param {Function} optional, callback
|
||
* @return {Manager} self
|
||
* @api public
|
||
*/
|
||
|
||
Manager.prototype.open =
|
||
Manager.prototype.connect = function(fn){
|
||
debug('readyState %s', this.readyState);
|
||
if (~this.readyState.indexOf('open')) return this;
|
||
|
||
debug('opening %s', this.uri);
|
||
this.engine = eio(this.uri, this.opts);
|
||
var socket = this.engine;
|
||
var self = this;
|
||
this.readyState = 'opening';
|
||
this.skipReconnect = false;
|
||
|
||
// emit `open`
|
||
var openSub = on(socket, 'open', function() {
|
||
self.onopen();
|
||
fn && fn();
|
||
});
|
||
|
||
// emit `connect_error`
|
||
var errorSub = on(socket, 'error', function(data){
|
||
debug('connect_error');
|
||
self.cleanup();
|
||
self.readyState = 'closed';
|
||
self.emitAll('connect_error', data);
|
||
if (fn) {
|
||
var err = new Error('Connection error');
|
||
err.data = data;
|
||
fn(err);
|
||
} else {
|
||
// Only do this if there is no fn to handle the error
|
||
self.maybeReconnectOnOpen();
|
||
}
|
||
});
|
||
|
||
// emit `connect_timeout`
|
||
if (false !== this._timeout) {
|
||
var timeout = this._timeout;
|
||
debug('connect attempt will timeout after %d', timeout);
|
||
|
||
// set timer
|
||
var timer = setTimeout(function(){
|
||
debug('connect attempt timed out after %d', timeout);
|
||
openSub.destroy();
|
||
socket.close();
|
||
socket.emit('error', 'timeout');
|
||
self.emitAll('connect_timeout', timeout);
|
||
}, timeout);
|
||
|
||
this.subs.push({
|
||
destroy: function(){
|
||
clearTimeout(timer);
|
||
}
|
||
});
|
||
}
|
||
|
||
this.subs.push(openSub);
|
||
this.subs.push(errorSub);
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Called upon transport open.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.onopen = function(){
|
||
debug('open');
|
||
|
||
// clear old subs
|
||
this.cleanup();
|
||
|
||
// mark as open
|
||
this.readyState = 'open';
|
||
this.emit('open');
|
||
|
||
// add new subs
|
||
var socket = this.engine;
|
||
this.subs.push(on(socket, 'data', bind(this, 'ondata')));
|
||
this.subs.push(on(socket, 'ping', bind(this, 'onping')));
|
||
this.subs.push(on(socket, 'pong', bind(this, 'onpong')));
|
||
this.subs.push(on(socket, 'error', bind(this, 'onerror')));
|
||
this.subs.push(on(socket, 'close', bind(this, 'onclose')));
|
||
this.subs.push(on(this.decoder, 'decoded', bind(this, 'ondecoded')));
|
||
};
|
||
|
||
/**
|
||
* Called upon a ping.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.onping = function(){
|
||
this.lastPing = new Date;
|
||
this.emitAll('ping');
|
||
};
|
||
|
||
/**
|
||
* Called upon a packet.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.onpong = function(){
|
||
this.emitAll('pong', new Date - this.lastPing);
|
||
};
|
||
|
||
/**
|
||
* Called with data.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.ondata = function(data){
|
||
this.decoder.add(data);
|
||
};
|
||
|
||
/**
|
||
* Called when parser fully decodes a packet.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.ondecoded = function(packet) {
|
||
this.emit('packet', packet);
|
||
};
|
||
|
||
/**
|
||
* Called upon socket error.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.onerror = function(err){
|
||
debug('error', err);
|
||
this.emitAll('error', err);
|
||
};
|
||
|
||
/**
|
||
* Creates a new socket for the given `nsp`.
|
||
*
|
||
* @return {Socket}
|
||
* @api public
|
||
*/
|
||
|
||
Manager.prototype.socket = function(nsp){
|
||
var socket = this.nsps[nsp];
|
||
if (!socket) {
|
||
socket = new Socket(this, nsp);
|
||
this.nsps[nsp] = socket;
|
||
var self = this;
|
||
socket.on('connecting', onConnecting);
|
||
socket.on('connect', function(){
|
||
socket.id = self.engine.id;
|
||
});
|
||
|
||
if (this.autoConnect) {
|
||
// manually call here since connecting evnet is fired before listening
|
||
onConnecting();
|
||
}
|
||
}
|
||
|
||
function onConnecting() {
|
||
if (!~indexOf(self.connecting, socket)) {
|
||
self.connecting.push(socket);
|
||
}
|
||
}
|
||
|
||
return socket;
|
||
};
|
||
|
||
/**
|
||
* Called upon a socket close.
|
||
*
|
||
* @param {Socket} socket
|
||
*/
|
||
|
||
Manager.prototype.destroy = function(socket){
|
||
var index = indexOf(this.connecting, socket);
|
||
if (~index) this.connecting.splice(index, 1);
|
||
if (this.connecting.length) return;
|
||
|
||
this.close();
|
||
};
|
||
|
||
/**
|
||
* Writes a packet.
|
||
*
|
||
* @param {Object} packet
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.packet = function(packet){
|
||
debug('writing packet %j', packet);
|
||
var self = this;
|
||
|
||
if (!self.encoding) {
|
||
// encode, then write to engine with result
|
||
self.encoding = true;
|
||
this.encoder.encode(packet, function(encodedPackets) {
|
||
for (var i = 0; i < encodedPackets.length; i++) {
|
||
self.engine.write(encodedPackets[i], packet.options);
|
||
}
|
||
self.encoding = false;
|
||
self.processPacketQueue();
|
||
});
|
||
} else { // add packet to the queue
|
||
self.packetBuffer.push(packet);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* If packet buffer is non-empty, begins encoding the
|
||
* next packet in line.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.processPacketQueue = function() {
|
||
if (this.packetBuffer.length > 0 && !this.encoding) {
|
||
var pack = this.packetBuffer.shift();
|
||
this.packet(pack);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Clean up transport subscriptions and packet buffer.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.cleanup = function(){
|
||
debug('cleanup');
|
||
|
||
var sub;
|
||
while (sub = this.subs.shift()) sub.destroy();
|
||
|
||
this.packetBuffer = [];
|
||
this.encoding = false;
|
||
this.lastPing = null;
|
||
|
||
this.decoder.destroy();
|
||
};
|
||
|
||
/**
|
||
* Close the current socket.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.close =
|
||
Manager.prototype.disconnect = function(){
|
||
debug('disconnect');
|
||
this.skipReconnect = true;
|
||
this.reconnecting = false;
|
||
if ('opening' == this.readyState) {
|
||
// `onclose` will not fire because
|
||
// an open event never happened
|
||
this.cleanup();
|
||
}
|
||
this.backoff.reset();
|
||
this.readyState = 'closed';
|
||
if (this.engine) this.engine.close();
|
||
};
|
||
|
||
/**
|
||
* Called upon engine close.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.onclose = function(reason){
|
||
debug('onclose');
|
||
|
||
this.cleanup();
|
||
this.backoff.reset();
|
||
this.readyState = 'closed';
|
||
this.emit('close', reason);
|
||
|
||
if (this._reconnection && !this.skipReconnect) {
|
||
this.reconnect();
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Attempt a reconnection.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.reconnect = function(){
|
||
if (this.reconnecting || this.skipReconnect) return this;
|
||
|
||
var self = this;
|
||
|
||
if (this.backoff.attempts >= this._reconnectionAttempts) {
|
||
debug('reconnect failed');
|
||
this.backoff.reset();
|
||
this.emitAll('reconnect_failed');
|
||
this.reconnecting = false;
|
||
} else {
|
||
var delay = this.backoff.duration();
|
||
debug('will wait %dms before reconnect attempt', delay);
|
||
|
||
this.reconnecting = true;
|
||
var timer = setTimeout(function(){
|
||
if (self.skipReconnect) return;
|
||
|
||
debug('attempting reconnect');
|
||
self.emitAll('reconnect_attempt', self.backoff.attempts);
|
||
self.emitAll('reconnecting', self.backoff.attempts);
|
||
|
||
// check again for the case socket closed in above events
|
||
if (self.skipReconnect) return;
|
||
|
||
self.open(function(err){
|
||
if (err) {
|
||
debug('reconnect attempt error');
|
||
self.reconnecting = false;
|
||
self.reconnect();
|
||
self.emitAll('reconnect_error', err.data);
|
||
} else {
|
||
debug('reconnect success');
|
||
self.onreconnect();
|
||
}
|
||
});
|
||
}, delay);
|
||
|
||
this.subs.push({
|
||
destroy: function(){
|
||
clearTimeout(timer);
|
||
}
|
||
});
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Called upon successful reconnect.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Manager.prototype.onreconnect = function(){
|
||
var attempt = this.backoff.attempts;
|
||
this.reconnecting = false;
|
||
this.backoff.reset();
|
||
this.updateSocketIds();
|
||
this.emitAll('reconnect', attempt);
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 83 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
|
||
module.exports = __webpack_require__(84);
|
||
|
||
|
||
/***/ },
|
||
/* 84 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
|
||
module.exports = __webpack_require__(85);
|
||
|
||
/**
|
||
* Exports parser
|
||
*
|
||
* @api public
|
||
*
|
||
*/
|
||
module.exports.parser = __webpack_require__(92);
|
||
|
||
|
||
/***/ },
|
||
/* 85 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(global) {/**
|
||
* Module dependencies.
|
||
*/
|
||
|
||
var transports = __webpack_require__(86);
|
||
var Emitter = __webpack_require__(101);
|
||
var debug = __webpack_require__(71)('engine.io-client:socket');
|
||
var index = __webpack_require__(108);
|
||
var parser = __webpack_require__(92);
|
||
var parseuri = __webpack_require__(70);
|
||
var parsejson = __webpack_require__(109);
|
||
var parseqs = __webpack_require__(102);
|
||
|
||
/**
|
||
* Module exports.
|
||
*/
|
||
|
||
module.exports = Socket;
|
||
|
||
/**
|
||
* Noop function.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
function noop(){}
|
||
|
||
/**
|
||
* Socket constructor.
|
||
*
|
||
* @param {String|Object} uri or options
|
||
* @param {Object} options
|
||
* @api public
|
||
*/
|
||
|
||
function Socket(uri, opts){
|
||
if (!(this instanceof Socket)) return new Socket(uri, opts);
|
||
|
||
opts = opts || {};
|
||
|
||
if (uri && 'object' == typeof uri) {
|
||
opts = uri;
|
||
uri = null;
|
||
}
|
||
|
||
if (uri) {
|
||
uri = parseuri(uri);
|
||
opts.hostname = uri.host;
|
||
opts.secure = uri.protocol == 'https' || uri.protocol == 'wss';
|
||
opts.port = uri.port;
|
||
if (uri.query) opts.query = uri.query;
|
||
} else if (opts.host) {
|
||
opts.hostname = parseuri(opts.host).host;
|
||
}
|
||
|
||
this.secure = null != opts.secure ? opts.secure :
|
||
(global.location && 'https:' == location.protocol);
|
||
|
||
if (opts.hostname && !opts.port) {
|
||
// if no port is specified manually, use the protocol default
|
||
opts.port = this.secure ? '443' : '80';
|
||
}
|
||
|
||
this.agent = opts.agent || false;
|
||
this.hostname = opts.hostname ||
|
||
(global.location ? location.hostname : 'localhost');
|
||
this.port = opts.port || (global.location && location.port ?
|
||
location.port :
|
||
(this.secure ? 443 : 80));
|
||
this.query = opts.query || {};
|
||
if ('string' == typeof this.query) this.query = parseqs.decode(this.query);
|
||
this.upgrade = false !== opts.upgrade;
|
||
this.path = (opts.path || '/engine.io').replace(/\/$/, '') + '/';
|
||
this.forceJSONP = !!opts.forceJSONP;
|
||
this.jsonp = false !== opts.jsonp;
|
||
this.forceBase64 = !!opts.forceBase64;
|
||
this.enablesXDR = !!opts.enablesXDR;
|
||
this.timestampParam = opts.timestampParam || 't';
|
||
this.timestampRequests = opts.timestampRequests;
|
||
this.transports = opts.transports || ['polling', 'websocket'];
|
||
this.readyState = '';
|
||
this.writeBuffer = [];
|
||
this.policyPort = opts.policyPort || 843;
|
||
this.rememberUpgrade = opts.rememberUpgrade || false;
|
||
this.binaryType = null;
|
||
this.onlyBinaryUpgrades = opts.onlyBinaryUpgrades;
|
||
this.perMessageDeflate = false !== opts.perMessageDeflate ? (opts.perMessageDeflate || {}) : false;
|
||
|
||
if (true === this.perMessageDeflate) this.perMessageDeflate = {};
|
||
if (this.perMessageDeflate && null == this.perMessageDeflate.threshold) {
|
||
this.perMessageDeflate.threshold = 1024;
|
||
}
|
||
|
||
// SSL options for Node.js client
|
||
this.pfx = opts.pfx || null;
|
||
this.key = opts.key || null;
|
||
this.passphrase = opts.passphrase || null;
|
||
this.cert = opts.cert || null;
|
||
this.ca = opts.ca || null;
|
||
this.ciphers = opts.ciphers || null;
|
||
this.rejectUnauthorized = opts.rejectUnauthorized === undefined ? null : opts.rejectUnauthorized;
|
||
|
||
// other options for Node.js client
|
||
var freeGlobal = typeof global == 'object' && global;
|
||
if (freeGlobal.global === freeGlobal) {
|
||
if (opts.extraHeaders && Object.keys(opts.extraHeaders).length > 0) {
|
||
this.extraHeaders = opts.extraHeaders;
|
||
}
|
||
}
|
||
|
||
this.open();
|
||
}
|
||
|
||
Socket.priorWebsocketSuccess = false;
|
||
|
||
/**
|
||
* Mix in `Emitter`.
|
||
*/
|
||
|
||
Emitter(Socket.prototype);
|
||
|
||
/**
|
||
* Protocol version.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
Socket.protocol = parser.protocol; // this is an int
|
||
|
||
/**
|
||
* Expose deps for legacy compatibility
|
||
* and standalone browser access.
|
||
*/
|
||
|
||
Socket.Socket = Socket;
|
||
Socket.Transport = __webpack_require__(91);
|
||
Socket.transports = __webpack_require__(86);
|
||
Socket.parser = __webpack_require__(92);
|
||
|
||
/**
|
||
* Creates transport of the given type.
|
||
*
|
||
* @param {String} transport name
|
||
* @return {Transport}
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.createTransport = function (name) {
|
||
debug('creating transport "%s"', name);
|
||
var query = clone(this.query);
|
||
|
||
// append engine.io protocol identifier
|
||
query.EIO = parser.protocol;
|
||
|
||
// transport name
|
||
query.transport = name;
|
||
|
||
// session id if we already have one
|
||
if (this.id) query.sid = this.id;
|
||
|
||
var transport = new transports[name]({
|
||
agent: this.agent,
|
||
hostname: this.hostname,
|
||
port: this.port,
|
||
secure: this.secure,
|
||
path: this.path,
|
||
query: query,
|
||
forceJSONP: this.forceJSONP,
|
||
jsonp: this.jsonp,
|
||
forceBase64: this.forceBase64,
|
||
enablesXDR: this.enablesXDR,
|
||
timestampRequests: this.timestampRequests,
|
||
timestampParam: this.timestampParam,
|
||
policyPort: this.policyPort,
|
||
socket: this,
|
||
pfx: this.pfx,
|
||
key: this.key,
|
||
passphrase: this.passphrase,
|
||
cert: this.cert,
|
||
ca: this.ca,
|
||
ciphers: this.ciphers,
|
||
rejectUnauthorized: this.rejectUnauthorized,
|
||
perMessageDeflate: this.perMessageDeflate,
|
||
extraHeaders: this.extraHeaders
|
||
});
|
||
|
||
return transport;
|
||
};
|
||
|
||
function clone (obj) {
|
||
var o = {};
|
||
for (var i in obj) {
|
||
if (obj.hasOwnProperty(i)) {
|
||
o[i] = obj[i];
|
||
}
|
||
}
|
||
return o;
|
||
}
|
||
|
||
/**
|
||
* Initializes transport to use and starts probe.
|
||
*
|
||
* @api private
|
||
*/
|
||
Socket.prototype.open = function () {
|
||
var transport;
|
||
if (this.rememberUpgrade && Socket.priorWebsocketSuccess && this.transports.indexOf('websocket') != -1) {
|
||
transport = 'websocket';
|
||
} else if (0 === this.transports.length) {
|
||
// Emit error on next tick so it can be listened to
|
||
var self = this;
|
||
setTimeout(function() {
|
||
self.emit('error', 'No transports available');
|
||
}, 0);
|
||
return;
|
||
} else {
|
||
transport = this.transports[0];
|
||
}
|
||
this.readyState = 'opening';
|
||
|
||
// Retry with the next transport if the transport is disabled (jsonp: false)
|
||
try {
|
||
transport = this.createTransport(transport);
|
||
} catch (e) {
|
||
this.transports.shift();
|
||
this.open();
|
||
return;
|
||
}
|
||
|
||
transport.open();
|
||
this.setTransport(transport);
|
||
};
|
||
|
||
/**
|
||
* Sets the current transport. Disables the existing one (if any).
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.setTransport = function(transport){
|
||
debug('setting transport %s', transport.name);
|
||
var self = this;
|
||
|
||
if (this.transport) {
|
||
debug('clearing existing transport %s', this.transport.name);
|
||
this.transport.removeAllListeners();
|
||
}
|
||
|
||
// set up transport
|
||
this.transport = transport;
|
||
|
||
// set up transport listeners
|
||
transport
|
||
.on('drain', function(){
|
||
self.onDrain();
|
||
})
|
||
.on('packet', function(packet){
|
||
self.onPacket(packet);
|
||
})
|
||
.on('error', function(e){
|
||
self.onError(e);
|
||
})
|
||
.on('close', function(){
|
||
self.onClose('transport close');
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Probes a transport.
|
||
*
|
||
* @param {String} transport name
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.probe = function (name) {
|
||
debug('probing transport "%s"', name);
|
||
var transport = this.createTransport(name, { probe: 1 })
|
||
, failed = false
|
||
, self = this;
|
||
|
||
Socket.priorWebsocketSuccess = false;
|
||
|
||
function onTransportOpen(){
|
||
if (self.onlyBinaryUpgrades) {
|
||
var upgradeLosesBinary = !this.supportsBinary && self.transport.supportsBinary;
|
||
failed = failed || upgradeLosesBinary;
|
||
}
|
||
if (failed) return;
|
||
|
||
debug('probe transport "%s" opened', name);
|
||
transport.send([{ type: 'ping', data: 'probe' }]);
|
||
transport.once('packet', function (msg) {
|
||
if (failed) return;
|
||
if ('pong' == msg.type && 'probe' == msg.data) {
|
||
debug('probe transport "%s" pong', name);
|
||
self.upgrading = true;
|
||
self.emit('upgrading', transport);
|
||
if (!transport) return;
|
||
Socket.priorWebsocketSuccess = 'websocket' == transport.name;
|
||
|
||
debug('pausing current transport "%s"', self.transport.name);
|
||
self.transport.pause(function () {
|
||
if (failed) return;
|
||
if ('closed' == self.readyState) return;
|
||
debug('changing transport and sending upgrade packet');
|
||
|
||
cleanup();
|
||
|
||
self.setTransport(transport);
|
||
transport.send([{ type: 'upgrade' }]);
|
||
self.emit('upgrade', transport);
|
||
transport = null;
|
||
self.upgrading = false;
|
||
self.flush();
|
||
});
|
||
} else {
|
||
debug('probe transport "%s" failed', name);
|
||
var err = new Error('probe error');
|
||
err.transport = transport.name;
|
||
self.emit('upgradeError', err);
|
||
}
|
||
});
|
||
}
|
||
|
||
function freezeTransport() {
|
||
if (failed) return;
|
||
|
||
// Any callback called by transport should be ignored since now
|
||
failed = true;
|
||
|
||
cleanup();
|
||
|
||
transport.close();
|
||
transport = null;
|
||
}
|
||
|
||
//Handle any error that happens while probing
|
||
function onerror(err) {
|
||
var error = new Error('probe error: ' + err);
|
||
error.transport = transport.name;
|
||
|
||
freezeTransport();
|
||
|
||
debug('probe transport "%s" failed because of error: %s', name, err);
|
||
|
||
self.emit('upgradeError', error);
|
||
}
|
||
|
||
function onTransportClose(){
|
||
onerror("transport closed");
|
||
}
|
||
|
||
//When the socket is closed while we're probing
|
||
function onclose(){
|
||
onerror("socket closed");
|
||
}
|
||
|
||
//When the socket is upgraded while we're probing
|
||
function onupgrade(to){
|
||
if (transport && to.name != transport.name) {
|
||
debug('"%s" works - aborting "%s"', to.name, transport.name);
|
||
freezeTransport();
|
||
}
|
||
}
|
||
|
||
//Remove all listeners on the transport and on self
|
||
function cleanup(){
|
||
transport.removeListener('open', onTransportOpen);
|
||
transport.removeListener('error', onerror);
|
||
transport.removeListener('close', onTransportClose);
|
||
self.removeListener('close', onclose);
|
||
self.removeListener('upgrading', onupgrade);
|
||
}
|
||
|
||
transport.once('open', onTransportOpen);
|
||
transport.once('error', onerror);
|
||
transport.once('close', onTransportClose);
|
||
|
||
this.once('close', onclose);
|
||
this.once('upgrading', onupgrade);
|
||
|
||
transport.open();
|
||
|
||
};
|
||
|
||
/**
|
||
* Called when connection is deemed open.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
Socket.prototype.onOpen = function () {
|
||
debug('socket open');
|
||
this.readyState = 'open';
|
||
Socket.priorWebsocketSuccess = 'websocket' == this.transport.name;
|
||
this.emit('open');
|
||
this.flush();
|
||
|
||
// we check for `readyState` in case an `open`
|
||
// listener already closed the socket
|
||
if ('open' == this.readyState && this.upgrade && this.transport.pause) {
|
||
debug('starting upgrade probes');
|
||
for (var i = 0, l = this.upgrades.length; i < l; i++) {
|
||
this.probe(this.upgrades[i]);
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Handles a packet.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.onPacket = function (packet) {
|
||
if ('opening' == this.readyState || 'open' == this.readyState) {
|
||
debug('socket receive: type "%s", data "%s"', packet.type, packet.data);
|
||
|
||
this.emit('packet', packet);
|
||
|
||
// Socket is live - any packet counts
|
||
this.emit('heartbeat');
|
||
|
||
switch (packet.type) {
|
||
case 'open':
|
||
this.onHandshake(parsejson(packet.data));
|
||
break;
|
||
|
||
case 'pong':
|
||
this.setPing();
|
||
this.emit('pong');
|
||
break;
|
||
|
||
case 'error':
|
||
var err = new Error('server error');
|
||
err.code = packet.data;
|
||
this.onError(err);
|
||
break;
|
||
|
||
case 'message':
|
||
this.emit('data', packet.data);
|
||
this.emit('message', packet.data);
|
||
break;
|
||
}
|
||
} else {
|
||
debug('packet received with socket readyState "%s"', this.readyState);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Called upon handshake completion.
|
||
*
|
||
* @param {Object} handshake obj
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.onHandshake = function (data) {
|
||
this.emit('handshake', data);
|
||
this.id = data.sid;
|
||
this.transport.query.sid = data.sid;
|
||
this.upgrades = this.filterUpgrades(data.upgrades);
|
||
this.pingInterval = data.pingInterval;
|
||
this.pingTimeout = data.pingTimeout;
|
||
this.onOpen();
|
||
// In case open handler closes socket
|
||
if ('closed' == this.readyState) return;
|
||
this.setPing();
|
||
|
||
// Prolong liveness of socket on heartbeat
|
||
this.removeListener('heartbeat', this.onHeartbeat);
|
||
this.on('heartbeat', this.onHeartbeat);
|
||
};
|
||
|
||
/**
|
||
* Resets ping timeout.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.onHeartbeat = function (timeout) {
|
||
clearTimeout(this.pingTimeoutTimer);
|
||
var self = this;
|
||
self.pingTimeoutTimer = setTimeout(function () {
|
||
if ('closed' == self.readyState) return;
|
||
self.onClose('ping timeout');
|
||
}, timeout || (self.pingInterval + self.pingTimeout));
|
||
};
|
||
|
||
/**
|
||
* Pings server every `this.pingInterval` and expects response
|
||
* within `this.pingTimeout` or closes connection.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.setPing = function () {
|
||
var self = this;
|
||
clearTimeout(self.pingIntervalTimer);
|
||
self.pingIntervalTimer = setTimeout(function () {
|
||
debug('writing ping packet - expecting pong within %sms', self.pingTimeout);
|
||
self.ping();
|
||
self.onHeartbeat(self.pingTimeout);
|
||
}, self.pingInterval);
|
||
};
|
||
|
||
/**
|
||
* Sends a ping packet.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.ping = function () {
|
||
var self = this;
|
||
this.sendPacket('ping', function(){
|
||
self.emit('ping');
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Called on `drain` event
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.onDrain = function() {
|
||
this.writeBuffer.splice(0, this.prevBufferLen);
|
||
|
||
// setting prevBufferLen = 0 is very important
|
||
// for example, when upgrading, upgrade packet is sent over,
|
||
// and a nonzero prevBufferLen could cause problems on `drain`
|
||
this.prevBufferLen = 0;
|
||
|
||
if (0 === this.writeBuffer.length) {
|
||
this.emit('drain');
|
||
} else {
|
||
this.flush();
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Flush write buffers.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.flush = function () {
|
||
if ('closed' != this.readyState && this.transport.writable &&
|
||
!this.upgrading && this.writeBuffer.length) {
|
||
debug('flushing %d packets in socket', this.writeBuffer.length);
|
||
this.transport.send(this.writeBuffer);
|
||
// keep track of current length of writeBuffer
|
||
// splice writeBuffer and callbackBuffer on `drain`
|
||
this.prevBufferLen = this.writeBuffer.length;
|
||
this.emit('flush');
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Sends a message.
|
||
*
|
||
* @param {String} message.
|
||
* @param {Function} callback function.
|
||
* @param {Object} options.
|
||
* @return {Socket} for chaining.
|
||
* @api public
|
||
*/
|
||
|
||
Socket.prototype.write =
|
||
Socket.prototype.send = function (msg, options, fn) {
|
||
this.sendPacket('message', msg, options, fn);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sends a packet.
|
||
*
|
||
* @param {String} packet type.
|
||
* @param {String} data.
|
||
* @param {Object} options.
|
||
* @param {Function} callback function.
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.sendPacket = function (type, data, options, fn) {
|
||
if('function' == typeof data) {
|
||
fn = data;
|
||
data = undefined;
|
||
}
|
||
|
||
if ('function' == typeof options) {
|
||
fn = options;
|
||
options = null;
|
||
}
|
||
|
||
if ('closing' == this.readyState || 'closed' == this.readyState) {
|
||
return;
|
||
}
|
||
|
||
options = options || {};
|
||
options.compress = false !== options.compress;
|
||
|
||
var packet = {
|
||
type: type,
|
||
data: data,
|
||
options: options
|
||
};
|
||
this.emit('packetCreate', packet);
|
||
this.writeBuffer.push(packet);
|
||
if (fn) this.once('flush', fn);
|
||
this.flush();
|
||
};
|
||
|
||
/**
|
||
* Closes the connection.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.close = function () {
|
||
if ('opening' == this.readyState || 'open' == this.readyState) {
|
||
this.readyState = 'closing';
|
||
|
||
var self = this;
|
||
|
||
if (this.writeBuffer.length) {
|
||
this.once('drain', function() {
|
||
if (this.upgrading) {
|
||
waitForUpgrade();
|
||
} else {
|
||
close();
|
||
}
|
||
});
|
||
} else if (this.upgrading) {
|
||
waitForUpgrade();
|
||
} else {
|
||
close();
|
||
}
|
||
}
|
||
|
||
function close() {
|
||
self.onClose('forced close');
|
||
debug('socket closing - telling transport to close');
|
||
self.transport.close();
|
||
}
|
||
|
||
function cleanupAndClose() {
|
||
self.removeListener('upgrade', cleanupAndClose);
|
||
self.removeListener('upgradeError', cleanupAndClose);
|
||
close();
|
||
}
|
||
|
||
function waitForUpgrade() {
|
||
// wait for upgrade to finish since we can't send packets while pausing a transport
|
||
self.once('upgrade', cleanupAndClose);
|
||
self.once('upgradeError', cleanupAndClose);
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Called upon transport error
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.onError = function (err) {
|
||
debug('socket error %j', err);
|
||
Socket.priorWebsocketSuccess = false;
|
||
this.emit('error', err);
|
||
this.onClose('transport error', err);
|
||
};
|
||
|
||
/**
|
||
* Called upon transport close.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.onClose = function (reason, desc) {
|
||
if ('opening' == this.readyState || 'open' == this.readyState || 'closing' == this.readyState) {
|
||
debug('socket close with reason: "%s"', reason);
|
||
var self = this;
|
||
|
||
// clear timers
|
||
clearTimeout(this.pingIntervalTimer);
|
||
clearTimeout(this.pingTimeoutTimer);
|
||
|
||
// stop event from firing again for transport
|
||
this.transport.removeAllListeners('close');
|
||
|
||
// ensure transport won't stay open
|
||
this.transport.close();
|
||
|
||
// ignore further transport communication
|
||
this.transport.removeAllListeners();
|
||
|
||
// set ready state
|
||
this.readyState = 'closed';
|
||
|
||
// clear session id
|
||
this.id = null;
|
||
|
||
// emit close event
|
||
this.emit('close', reason, desc);
|
||
|
||
// clean buffers after, so users can still
|
||
// grab the buffers on `close` event
|
||
self.writeBuffer = [];
|
||
self.prevBufferLen = 0;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Filters upgrades, returning only those matching client transports.
|
||
*
|
||
* @param {Array} server upgrades
|
||
* @api private
|
||
*
|
||
*/
|
||
|
||
Socket.prototype.filterUpgrades = function (upgrades) {
|
||
var filteredUpgrades = [];
|
||
for (var i = 0, j = upgrades.length; i<j; i++) {
|
||
if (~index(this.transports, upgrades[i])) filteredUpgrades.push(upgrades[i]);
|
||
}
|
||
return filteredUpgrades;
|
||
};
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 86 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(global) {/**
|
||
* Module dependencies
|
||
*/
|
||
|
||
var XMLHttpRequest = __webpack_require__(87);
|
||
var XHR = __webpack_require__(89);
|
||
var JSONP = __webpack_require__(105);
|
||
var websocket = __webpack_require__(106);
|
||
|
||
/**
|
||
* Export transports.
|
||
*/
|
||
|
||
exports.polling = polling;
|
||
exports.websocket = websocket;
|
||
|
||
/**
|
||
* Polling transport polymorphic constructor.
|
||
* Decides on xhr vs jsonp based on feature detection.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
function polling(opts){
|
||
var xhr;
|
||
var xd = false;
|
||
var xs = false;
|
||
var jsonp = false !== opts.jsonp;
|
||
|
||
if (global.location) {
|
||
var isSSL = 'https:' == location.protocol;
|
||
var port = location.port;
|
||
|
||
// some user agents have empty `location.port`
|
||
if (!port) {
|
||
port = isSSL ? 443 : 80;
|
||
}
|
||
|
||
xd = opts.hostname != location.hostname || port != opts.port;
|
||
xs = opts.secure != isSSL;
|
||
}
|
||
|
||
opts.xdomain = xd;
|
||
opts.xscheme = xs;
|
||
xhr = new XMLHttpRequest(opts);
|
||
|
||
if ('open' in xhr && !opts.forceJSONP) {
|
||
return new XHR(opts);
|
||
} else {
|
||
if (!jsonp) throw new Error('JSONP disabled');
|
||
return new JSONP(opts);
|
||
}
|
||
}
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 87 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// browser shim for xmlhttprequest module
|
||
var hasCORS = __webpack_require__(88);
|
||
|
||
module.exports = function(opts) {
|
||
var xdomain = opts.xdomain;
|
||
|
||
// scheme must be same when usign XDomainRequest
|
||
// http://blogs.msdn.com/b/ieinternals/archive/2010/05/13/xdomainrequest-restrictions-limitations-and-workarounds.aspx
|
||
var xscheme = opts.xscheme;
|
||
|
||
// XDomainRequest has a flow of not sending cookie, therefore it should be disabled as a default.
|
||
// https://github.com/Automattic/engine.io-client/pull/217
|
||
var enablesXDR = opts.enablesXDR;
|
||
|
||
// XMLHttpRequest can be disabled on IE
|
||
try {
|
||
if ('undefined' != typeof XMLHttpRequest && (!xdomain || hasCORS)) {
|
||
return new XMLHttpRequest();
|
||
}
|
||
} catch (e) { }
|
||
|
||
// Use XDomainRequest for IE8 if enablesXDR is true
|
||
// because loading bar keeps flashing when using jsonp-polling
|
||
// https://github.com/yujiosaka/socke.io-ie8-loading-example
|
||
try {
|
||
if ('undefined' != typeof XDomainRequest && !xscheme && enablesXDR) {
|
||
return new XDomainRequest();
|
||
}
|
||
} catch (e) { }
|
||
|
||
if (!xdomain) {
|
||
try {
|
||
return new ActiveXObject('Microsoft.XMLHTTP');
|
||
} catch(e) { }
|
||
}
|
||
}
|
||
|
||
|
||
/***/ },
|
||
/* 88 */
|
||
/***/ function(module, exports) {
|
||
|
||
|
||
/**
|
||
* Module exports.
|
||
*
|
||
* Logic borrowed from Modernizr:
|
||
*
|
||
* - https://github.com/Modernizr/Modernizr/blob/master/feature-detects/cors.js
|
||
*/
|
||
|
||
try {
|
||
module.exports = typeof XMLHttpRequest !== 'undefined' &&
|
||
'withCredentials' in new XMLHttpRequest();
|
||
} catch (err) {
|
||
// if XMLHttp support is disabled in IE then it will throw
|
||
// when trying to create
|
||
module.exports = false;
|
||
}
|
||
|
||
|
||
/***/ },
|
||
/* 89 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(global) {/**
|
||
* Module requirements.
|
||
*/
|
||
|
||
var XMLHttpRequest = __webpack_require__(87);
|
||
var Polling = __webpack_require__(90);
|
||
var Emitter = __webpack_require__(101);
|
||
var inherit = __webpack_require__(103);
|
||
var debug = __webpack_require__(71)('engine.io-client:polling-xhr');
|
||
|
||
/**
|
||
* Module exports.
|
||
*/
|
||
|
||
module.exports = XHR;
|
||
module.exports.Request = Request;
|
||
|
||
/**
|
||
* Empty function
|
||
*/
|
||
|
||
function empty(){}
|
||
|
||
/**
|
||
* XHR Polling constructor.
|
||
*
|
||
* @param {Object} opts
|
||
* @api public
|
||
*/
|
||
|
||
function XHR(opts){
|
||
Polling.call(this, opts);
|
||
|
||
if (global.location) {
|
||
var isSSL = 'https:' == location.protocol;
|
||
var port = location.port;
|
||
|
||
// some user agents have empty `location.port`
|
||
if (!port) {
|
||
port = isSSL ? 443 : 80;
|
||
}
|
||
|
||
this.xd = opts.hostname != global.location.hostname ||
|
||
port != opts.port;
|
||
this.xs = opts.secure != isSSL;
|
||
} else {
|
||
this.extraHeaders = opts.extraHeaders;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Inherits from Polling.
|
||
*/
|
||
|
||
inherit(XHR, Polling);
|
||
|
||
/**
|
||
* XHR supports binary
|
||
*/
|
||
|
||
XHR.prototype.supportsBinary = true;
|
||
|
||
/**
|
||
* Creates a request.
|
||
*
|
||
* @param {String} method
|
||
* @api private
|
||
*/
|
||
|
||
XHR.prototype.request = function(opts){
|
||
opts = opts || {};
|
||
opts.uri = this.uri();
|
||
opts.xd = this.xd;
|
||
opts.xs = this.xs;
|
||
opts.agent = this.agent || false;
|
||
opts.supportsBinary = this.supportsBinary;
|
||
opts.enablesXDR = this.enablesXDR;
|
||
|
||
// SSL options for Node.js client
|
||
opts.pfx = this.pfx;
|
||
opts.key = this.key;
|
||
opts.passphrase = this.passphrase;
|
||
opts.cert = this.cert;
|
||
opts.ca = this.ca;
|
||
opts.ciphers = this.ciphers;
|
||
opts.rejectUnauthorized = this.rejectUnauthorized;
|
||
|
||
// other options for Node.js client
|
||
opts.extraHeaders = this.extraHeaders;
|
||
|
||
return new Request(opts);
|
||
};
|
||
|
||
/**
|
||
* Sends data.
|
||
*
|
||
* @param {String} data to send.
|
||
* @param {Function} called upon flush.
|
||
* @api private
|
||
*/
|
||
|
||
XHR.prototype.doWrite = function(data, fn){
|
||
var isBinary = typeof data !== 'string' && data !== undefined;
|
||
var req = this.request({ method: 'POST', data: data, isBinary: isBinary });
|
||
var self = this;
|
||
req.on('success', fn);
|
||
req.on('error', function(err){
|
||
self.onError('xhr post error', err);
|
||
});
|
||
this.sendXhr = req;
|
||
};
|
||
|
||
/**
|
||
* Starts a poll cycle.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
XHR.prototype.doPoll = function(){
|
||
debug('xhr poll');
|
||
var req = this.request();
|
||
var self = this;
|
||
req.on('data', function(data){
|
||
self.onData(data);
|
||
});
|
||
req.on('error', function(err){
|
||
self.onError('xhr poll error', err);
|
||
});
|
||
this.pollXhr = req;
|
||
};
|
||
|
||
/**
|
||
* Request constructor
|
||
*
|
||
* @param {Object} options
|
||
* @api public
|
||
*/
|
||
|
||
function Request(opts){
|
||
this.method = opts.method || 'GET';
|
||
this.uri = opts.uri;
|
||
this.xd = !!opts.xd;
|
||
this.xs = !!opts.xs;
|
||
this.async = false !== opts.async;
|
||
this.data = undefined != opts.data ? opts.data : null;
|
||
this.agent = opts.agent;
|
||
this.isBinary = opts.isBinary;
|
||
this.supportsBinary = opts.supportsBinary;
|
||
this.enablesXDR = opts.enablesXDR;
|
||
|
||
// SSL options for Node.js client
|
||
this.pfx = opts.pfx;
|
||
this.key = opts.key;
|
||
this.passphrase = opts.passphrase;
|
||
this.cert = opts.cert;
|
||
this.ca = opts.ca;
|
||
this.ciphers = opts.ciphers;
|
||
this.rejectUnauthorized = opts.rejectUnauthorized;
|
||
|
||
// other options for Node.js client
|
||
this.extraHeaders = opts.extraHeaders;
|
||
|
||
this.create();
|
||
}
|
||
|
||
/**
|
||
* Mix in `Emitter`.
|
||
*/
|
||
|
||
Emitter(Request.prototype);
|
||
|
||
/**
|
||
* Creates the XHR object and sends the request.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Request.prototype.create = function(){
|
||
var opts = { agent: this.agent, xdomain: this.xd, xscheme: this.xs, enablesXDR: this.enablesXDR };
|
||
|
||
// SSL options for Node.js client
|
||
opts.pfx = this.pfx;
|
||
opts.key = this.key;
|
||
opts.passphrase = this.passphrase;
|
||
opts.cert = this.cert;
|
||
opts.ca = this.ca;
|
||
opts.ciphers = this.ciphers;
|
||
opts.rejectUnauthorized = this.rejectUnauthorized;
|
||
|
||
var xhr = this.xhr = new XMLHttpRequest(opts);
|
||
var self = this;
|
||
|
||
try {
|
||
debug('xhr open %s: %s', this.method, this.uri);
|
||
xhr.open(this.method, this.uri, this.async);
|
||
try {
|
||
if (this.extraHeaders) {
|
||
xhr.setDisableHeaderCheck(true);
|
||
for (var i in this.extraHeaders) {
|
||
if (this.extraHeaders.hasOwnProperty(i)) {
|
||
xhr.setRequestHeader(i, this.extraHeaders[i]);
|
||
}
|
||
}
|
||
}
|
||
} catch (e) {}
|
||
if (this.supportsBinary) {
|
||
// This has to be done after open because Firefox is stupid
|
||
// http://stackoverflow.com/questions/13216903/get-binary-data-with-xmlhttprequest-in-a-firefox-extension
|
||
xhr.responseType = 'arraybuffer';
|
||
}
|
||
|
||
if ('POST' == this.method) {
|
||
try {
|
||
if (this.isBinary) {
|
||
xhr.setRequestHeader('Content-type', 'application/octet-stream');
|
||
} else {
|
||
xhr.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
|
||
}
|
||
} catch (e) {}
|
||
}
|
||
|
||
// ie6 check
|
||
if ('withCredentials' in xhr) {
|
||
xhr.withCredentials = true;
|
||
}
|
||
|
||
if (this.hasXDR()) {
|
||
xhr.onload = function(){
|
||
self.onLoad();
|
||
};
|
||
xhr.onerror = function(){
|
||
self.onError(xhr.responseText);
|
||
};
|
||
} else {
|
||
xhr.onreadystatechange = function(){
|
||
if (4 != xhr.readyState) return;
|
||
if (200 == xhr.status || 1223 == xhr.status) {
|
||
self.onLoad();
|
||
} else {
|
||
// make sure the `error` event handler that's user-set
|
||
// does not throw in the same tick and gets caught here
|
||
setTimeout(function(){
|
||
self.onError(xhr.status);
|
||
}, 0);
|
||
}
|
||
};
|
||
}
|
||
|
||
debug('xhr data %s', this.data);
|
||
xhr.send(this.data);
|
||
} catch (e) {
|
||
// Need to defer since .create() is called directly fhrom the constructor
|
||
// and thus the 'error' event can only be only bound *after* this exception
|
||
// occurs. Therefore, also, we cannot throw here at all.
|
||
setTimeout(function() {
|
||
self.onError(e);
|
||
}, 0);
|
||
return;
|
||
}
|
||
|
||
if (global.document) {
|
||
this.index = Request.requestsCount++;
|
||
Request.requests[this.index] = this;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Called upon successful response.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Request.prototype.onSuccess = function(){
|
||
this.emit('success');
|
||
this.cleanup();
|
||
};
|
||
|
||
/**
|
||
* Called if we have data.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Request.prototype.onData = function(data){
|
||
this.emit('data', data);
|
||
this.onSuccess();
|
||
};
|
||
|
||
/**
|
||
* Called upon error.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Request.prototype.onError = function(err){
|
||
this.emit('error', err);
|
||
this.cleanup(true);
|
||
};
|
||
|
||
/**
|
||
* Cleans up house.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Request.prototype.cleanup = function(fromError){
|
||
if ('undefined' == typeof this.xhr || null === this.xhr) {
|
||
return;
|
||
}
|
||
// xmlhttprequest
|
||
if (this.hasXDR()) {
|
||
this.xhr.onload = this.xhr.onerror = empty;
|
||
} else {
|
||
this.xhr.onreadystatechange = empty;
|
||
}
|
||
|
||
if (fromError) {
|
||
try {
|
||
this.xhr.abort();
|
||
} catch(e) {}
|
||
}
|
||
|
||
if (global.document) {
|
||
delete Request.requests[this.index];
|
||
}
|
||
|
||
this.xhr = null;
|
||
};
|
||
|
||
/**
|
||
* Called upon load.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Request.prototype.onLoad = function(){
|
||
var data;
|
||
try {
|
||
var contentType;
|
||
try {
|
||
contentType = this.xhr.getResponseHeader('Content-Type').split(';')[0];
|
||
} catch (e) {}
|
||
if (contentType === 'application/octet-stream') {
|
||
data = this.xhr.response;
|
||
} else {
|
||
if (!this.supportsBinary) {
|
||
data = this.xhr.responseText;
|
||
} else {
|
||
try {
|
||
data = String.fromCharCode.apply(null, new Uint8Array(this.xhr.response));
|
||
} catch (e) {
|
||
var ui8Arr = new Uint8Array(this.xhr.response);
|
||
var dataArray = [];
|
||
for (var idx = 0, length = ui8Arr.length; idx < length; idx++) {
|
||
dataArray.push(ui8Arr[idx]);
|
||
}
|
||
|
||
data = String.fromCharCode.apply(null, dataArray);
|
||
}
|
||
}
|
||
}
|
||
} catch (e) {
|
||
this.onError(e);
|
||
}
|
||
if (null != data) {
|
||
this.onData(data);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Check if it has XDomainRequest.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Request.prototype.hasXDR = function(){
|
||
return 'undefined' !== typeof global.XDomainRequest && !this.xs && this.enablesXDR;
|
||
};
|
||
|
||
/**
|
||
* Aborts the request.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
Request.prototype.abort = function(){
|
||
this.cleanup();
|
||
};
|
||
|
||
/**
|
||
* Aborts pending requests when unloading the window. This is needed to prevent
|
||
* memory leaks (e.g. when using IE) and to ensure that no spurious error is
|
||
* emitted.
|
||
*/
|
||
|
||
if (global.document) {
|
||
Request.requestsCount = 0;
|
||
Request.requests = {};
|
||
if (global.attachEvent) {
|
||
global.attachEvent('onunload', unloadHandler);
|
||
} else if (global.addEventListener) {
|
||
global.addEventListener('beforeunload', unloadHandler, false);
|
||
}
|
||
}
|
||
|
||
function unloadHandler() {
|
||
for (var i in Request.requests) {
|
||
if (Request.requests.hasOwnProperty(i)) {
|
||
Request.requests[i].abort();
|
||
}
|
||
}
|
||
}
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 90 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/**
|
||
* Module dependencies.
|
||
*/
|
||
|
||
var Transport = __webpack_require__(91);
|
||
var parseqs = __webpack_require__(102);
|
||
var parser = __webpack_require__(92);
|
||
var inherit = __webpack_require__(103);
|
||
var yeast = __webpack_require__(104);
|
||
var debug = __webpack_require__(71)('engine.io-client:polling');
|
||
|
||
/**
|
||
* Module exports.
|
||
*/
|
||
|
||
module.exports = Polling;
|
||
|
||
/**
|
||
* Is XHR2 supported?
|
||
*/
|
||
|
||
var hasXHR2 = (function() {
|
||
var XMLHttpRequest = __webpack_require__(87);
|
||
var xhr = new XMLHttpRequest({ xdomain: false });
|
||
return null != xhr.responseType;
|
||
})();
|
||
|
||
/**
|
||
* Polling interface.
|
||
*
|
||
* @param {Object} opts
|
||
* @api private
|
||
*/
|
||
|
||
function Polling(opts){
|
||
var forceBase64 = (opts && opts.forceBase64);
|
||
if (!hasXHR2 || forceBase64) {
|
||
this.supportsBinary = false;
|
||
}
|
||
Transport.call(this, opts);
|
||
}
|
||
|
||
/**
|
||
* Inherits from Transport.
|
||
*/
|
||
|
||
inherit(Polling, Transport);
|
||
|
||
/**
|
||
* Transport name.
|
||
*/
|
||
|
||
Polling.prototype.name = 'polling';
|
||
|
||
/**
|
||
* Opens the socket (triggers polling). We write a PING message to determine
|
||
* when the transport is open.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Polling.prototype.doOpen = function(){
|
||
this.poll();
|
||
};
|
||
|
||
/**
|
||
* Pauses polling.
|
||
*
|
||
* @param {Function} callback upon buffers are flushed and transport is paused
|
||
* @api private
|
||
*/
|
||
|
||
Polling.prototype.pause = function(onPause){
|
||
var pending = 0;
|
||
var self = this;
|
||
|
||
this.readyState = 'pausing';
|
||
|
||
function pause(){
|
||
debug('paused');
|
||
self.readyState = 'paused';
|
||
onPause();
|
||
}
|
||
|
||
if (this.polling || !this.writable) {
|
||
var total = 0;
|
||
|
||
if (this.polling) {
|
||
debug('we are currently polling - waiting to pause');
|
||
total++;
|
||
this.once('pollComplete', function(){
|
||
debug('pre-pause polling complete');
|
||
--total || pause();
|
||
});
|
||
}
|
||
|
||
if (!this.writable) {
|
||
debug('we are currently writing - waiting to pause');
|
||
total++;
|
||
this.once('drain', function(){
|
||
debug('pre-pause writing complete');
|
||
--total || pause();
|
||
});
|
||
}
|
||
} else {
|
||
pause();
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Starts polling cycle.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
Polling.prototype.poll = function(){
|
||
debug('polling');
|
||
this.polling = true;
|
||
this.doPoll();
|
||
this.emit('poll');
|
||
};
|
||
|
||
/**
|
||
* Overloads onData to detect payloads.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Polling.prototype.onData = function(data){
|
||
var self = this;
|
||
debug('polling got data %s', data);
|
||
var callback = function(packet, index, total) {
|
||
// if its the first message we consider the transport open
|
||
if ('opening' == self.readyState) {
|
||
self.onOpen();
|
||
}
|
||
|
||
// if its a close packet, we close the ongoing requests
|
||
if ('close' == packet.type) {
|
||
self.onClose();
|
||
return false;
|
||
}
|
||
|
||
// otherwise bypass onData and handle the message
|
||
self.onPacket(packet);
|
||
};
|
||
|
||
// decode payload
|
||
parser.decodePayload(data, this.socket.binaryType, callback);
|
||
|
||
// if an event did not trigger closing
|
||
if ('closed' != this.readyState) {
|
||
// if we got data we're not polling
|
||
this.polling = false;
|
||
this.emit('pollComplete');
|
||
|
||
if ('open' == this.readyState) {
|
||
this.poll();
|
||
} else {
|
||
debug('ignoring poll - transport state "%s"', this.readyState);
|
||
}
|
||
}
|
||
};
|
||
|
||
/**
|
||
* For polling, send a close packet.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Polling.prototype.doClose = function(){
|
||
var self = this;
|
||
|
||
function close(){
|
||
debug('writing close packet');
|
||
self.write([{ type: 'close' }]);
|
||
}
|
||
|
||
if ('open' == this.readyState) {
|
||
debug('transport open - closing');
|
||
close();
|
||
} else {
|
||
// in case we're trying to close while
|
||
// handshaking is in progress (GH-164)
|
||
debug('transport not open - deferring close');
|
||
this.once('open', close);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Writes a packets payload.
|
||
*
|
||
* @param {Array} data packets
|
||
* @param {Function} drain callback
|
||
* @api private
|
||
*/
|
||
|
||
Polling.prototype.write = function(packets){
|
||
var self = this;
|
||
this.writable = false;
|
||
var callbackfn = function() {
|
||
self.writable = true;
|
||
self.emit('drain');
|
||
};
|
||
|
||
var self = this;
|
||
parser.encodePayload(packets, this.supportsBinary, function(data) {
|
||
self.doWrite(data, callbackfn);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Generates uri for connection.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Polling.prototype.uri = function(){
|
||
var query = this.query || {};
|
||
var schema = this.secure ? 'https' : 'http';
|
||
var port = '';
|
||
|
||
// cache busting is forced
|
||
if (false !== this.timestampRequests) {
|
||
query[this.timestampParam] = yeast();
|
||
}
|
||
|
||
if (!this.supportsBinary && !query.sid) {
|
||
query.b64 = 1;
|
||
}
|
||
|
||
query = parseqs.encode(query);
|
||
|
||
// avoid port if default for schema
|
||
if (this.port && (('https' == schema && this.port != 443) ||
|
||
('http' == schema && this.port != 80))) {
|
||
port = ':' + this.port;
|
||
}
|
||
|
||
// prepend ? to query
|
||
if (query.length) {
|
||
query = '?' + query;
|
||
}
|
||
|
||
var ipv6 = this.hostname.indexOf(':') !== -1;
|
||
return schema + '://' + (ipv6 ? '[' + this.hostname + ']' : this.hostname) + port + this.path + query;
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 91 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/**
|
||
* Module dependencies.
|
||
*/
|
||
|
||
var parser = __webpack_require__(92);
|
||
var Emitter = __webpack_require__(101);
|
||
|
||
/**
|
||
* Module exports.
|
||
*/
|
||
|
||
module.exports = Transport;
|
||
|
||
/**
|
||
* Transport abstract constructor.
|
||
*
|
||
* @param {Object} options.
|
||
* @api private
|
||
*/
|
||
|
||
function Transport (opts) {
|
||
this.path = opts.path;
|
||
this.hostname = opts.hostname;
|
||
this.port = opts.port;
|
||
this.secure = opts.secure;
|
||
this.query = opts.query;
|
||
this.timestampParam = opts.timestampParam;
|
||
this.timestampRequests = opts.timestampRequests;
|
||
this.readyState = '';
|
||
this.agent = opts.agent || false;
|
||
this.socket = opts.socket;
|
||
this.enablesXDR = opts.enablesXDR;
|
||
|
||
// SSL options for Node.js client
|
||
this.pfx = opts.pfx;
|
||
this.key = opts.key;
|
||
this.passphrase = opts.passphrase;
|
||
this.cert = opts.cert;
|
||
this.ca = opts.ca;
|
||
this.ciphers = opts.ciphers;
|
||
this.rejectUnauthorized = opts.rejectUnauthorized;
|
||
|
||
// other options for Node.js client
|
||
this.extraHeaders = opts.extraHeaders;
|
||
}
|
||
|
||
/**
|
||
* Mix in `Emitter`.
|
||
*/
|
||
|
||
Emitter(Transport.prototype);
|
||
|
||
/**
|
||
* Emits an error.
|
||
*
|
||
* @param {String} str
|
||
* @return {Transport} for chaining
|
||
* @api public
|
||
*/
|
||
|
||
Transport.prototype.onError = function (msg, desc) {
|
||
var err = new Error(msg);
|
||
err.type = 'TransportError';
|
||
err.description = desc;
|
||
this.emit('error', err);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Opens the transport.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
Transport.prototype.open = function () {
|
||
if ('closed' == this.readyState || '' == this.readyState) {
|
||
this.readyState = 'opening';
|
||
this.doOpen();
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Closes the transport.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Transport.prototype.close = function () {
|
||
if ('opening' == this.readyState || 'open' == this.readyState) {
|
||
this.doClose();
|
||
this.onClose();
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sends multiple packets.
|
||
*
|
||
* @param {Array} packets
|
||
* @api private
|
||
*/
|
||
|
||
Transport.prototype.send = function(packets){
|
||
if ('open' == this.readyState) {
|
||
this.write(packets);
|
||
} else {
|
||
throw new Error('Transport not open');
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Called upon open
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Transport.prototype.onOpen = function () {
|
||
this.readyState = 'open';
|
||
this.writable = true;
|
||
this.emit('open');
|
||
};
|
||
|
||
/**
|
||
* Called with data.
|
||
*
|
||
* @param {String} data
|
||
* @api private
|
||
*/
|
||
|
||
Transport.prototype.onData = function(data){
|
||
var packet = parser.decodePacket(data, this.socket.binaryType);
|
||
this.onPacket(packet);
|
||
};
|
||
|
||
/**
|
||
* Called with a decoded packet.
|
||
*/
|
||
|
||
Transport.prototype.onPacket = function (packet) {
|
||
this.emit('packet', packet);
|
||
};
|
||
|
||
/**
|
||
* Called upon close.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Transport.prototype.onClose = function () {
|
||
this.readyState = 'closed';
|
||
this.emit('close');
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 92 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(global) {/**
|
||
* Module dependencies.
|
||
*/
|
||
|
||
var keys = __webpack_require__(93);
|
||
var hasBinary = __webpack_require__(94);
|
||
var sliceBuffer = __webpack_require__(96);
|
||
var base64encoder = __webpack_require__(97);
|
||
var after = __webpack_require__(98);
|
||
var utf8 = __webpack_require__(99);
|
||
|
||
/**
|
||
* Check if we are running an android browser. That requires us to use
|
||
* ArrayBuffer with polling transports...
|
||
*
|
||
* http://ghinda.net/jpeg-blob-ajax-android/
|
||
*/
|
||
|
||
var isAndroid = navigator.userAgent.match(/Android/i);
|
||
|
||
/**
|
||
* Check if we are running in PhantomJS.
|
||
* Uploading a Blob with PhantomJS does not work correctly, as reported here:
|
||
* https://github.com/ariya/phantomjs/issues/11395
|
||
* @type boolean
|
||
*/
|
||
var isPhantomJS = /PhantomJS/i.test(navigator.userAgent);
|
||
|
||
/**
|
||
* When true, avoids using Blobs to encode payloads.
|
||
* @type boolean
|
||
*/
|
||
var dontSendBlobs = isAndroid || isPhantomJS;
|
||
|
||
/**
|
||
* Current protocol version.
|
||
*/
|
||
|
||
exports.protocol = 3;
|
||
|
||
/**
|
||
* Packet types.
|
||
*/
|
||
|
||
var packets = exports.packets = {
|
||
open: 0 // non-ws
|
||
, close: 1 // non-ws
|
||
, ping: 2
|
||
, pong: 3
|
||
, message: 4
|
||
, upgrade: 5
|
||
, noop: 6
|
||
};
|
||
|
||
var packetslist = keys(packets);
|
||
|
||
/**
|
||
* Premade error packet.
|
||
*/
|
||
|
||
var err = { type: 'error', data: 'parser error' };
|
||
|
||
/**
|
||
* Create a blob api even for blob builder when vendor prefixes exist
|
||
*/
|
||
|
||
var Blob = __webpack_require__(100);
|
||
|
||
/**
|
||
* Encodes a packet.
|
||
*
|
||
* <packet type id> [ <data> ]
|
||
*
|
||
* Example:
|
||
*
|
||
* 5hello world
|
||
* 3
|
||
* 4
|
||
*
|
||
* Binary is encoded in an identical principle
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
exports.encodePacket = function (packet, supportsBinary, utf8encode, callback) {
|
||
if ('function' == typeof supportsBinary) {
|
||
callback = supportsBinary;
|
||
supportsBinary = false;
|
||
}
|
||
|
||
if ('function' == typeof utf8encode) {
|
||
callback = utf8encode;
|
||
utf8encode = null;
|
||
}
|
||
|
||
var data = (packet.data === undefined)
|
||
? undefined
|
||
: packet.data.buffer || packet.data;
|
||
|
||
if (global.ArrayBuffer && data instanceof ArrayBuffer) {
|
||
return encodeArrayBuffer(packet, supportsBinary, callback);
|
||
} else if (Blob && data instanceof global.Blob) {
|
||
return encodeBlob(packet, supportsBinary, callback);
|
||
}
|
||
|
||
// might be an object with { base64: true, data: dataAsBase64String }
|
||
if (data && data.base64) {
|
||
return encodeBase64Object(packet, callback);
|
||
}
|
||
|
||
// Sending data as a utf-8 string
|
||
var encoded = packets[packet.type];
|
||
|
||
// data fragment is optional
|
||
if (undefined !== packet.data) {
|
||
encoded += utf8encode ? utf8.encode(String(packet.data)) : String(packet.data);
|
||
}
|
||
|
||
return callback('' + encoded);
|
||
|
||
};
|
||
|
||
function encodeBase64Object(packet, callback) {
|
||
// packet data is an object { base64: true, data: dataAsBase64String }
|
||
var message = 'b' + exports.packets[packet.type] + packet.data.data;
|
||
return callback(message);
|
||
}
|
||
|
||
/**
|
||
* Encode packet helpers for binary types
|
||
*/
|
||
|
||
function encodeArrayBuffer(packet, supportsBinary, callback) {
|
||
if (!supportsBinary) {
|
||
return exports.encodeBase64Packet(packet, callback);
|
||
}
|
||
|
||
var data = packet.data;
|
||
var contentArray = new Uint8Array(data);
|
||
var resultBuffer = new Uint8Array(1 + data.byteLength);
|
||
|
||
resultBuffer[0] = packets[packet.type];
|
||
for (var i = 0; i < contentArray.length; i++) {
|
||
resultBuffer[i+1] = contentArray[i];
|
||
}
|
||
|
||
return callback(resultBuffer.buffer);
|
||
}
|
||
|
||
function encodeBlobAsArrayBuffer(packet, supportsBinary, callback) {
|
||
if (!supportsBinary) {
|
||
return exports.encodeBase64Packet(packet, callback);
|
||
}
|
||
|
||
var fr = new FileReader();
|
||
fr.onload = function() {
|
||
packet.data = fr.result;
|
||
exports.encodePacket(packet, supportsBinary, true, callback);
|
||
};
|
||
return fr.readAsArrayBuffer(packet.data);
|
||
}
|
||
|
||
function encodeBlob(packet, supportsBinary, callback) {
|
||
if (!supportsBinary) {
|
||
return exports.encodeBase64Packet(packet, callback);
|
||
}
|
||
|
||
if (dontSendBlobs) {
|
||
return encodeBlobAsArrayBuffer(packet, supportsBinary, callback);
|
||
}
|
||
|
||
var length = new Uint8Array(1);
|
||
length[0] = packets[packet.type];
|
||
var blob = new Blob([length.buffer, packet.data]);
|
||
|
||
return callback(blob);
|
||
}
|
||
|
||
/**
|
||
* Encodes a packet with binary data in a base64 string
|
||
*
|
||
* @param {Object} packet, has `type` and `data`
|
||
* @return {String} base64 encoded message
|
||
*/
|
||
|
||
exports.encodeBase64Packet = function(packet, callback) {
|
||
var message = 'b' + exports.packets[packet.type];
|
||
if (Blob && packet.data instanceof global.Blob) {
|
||
var fr = new FileReader();
|
||
fr.onload = function() {
|
||
var b64 = fr.result.split(',')[1];
|
||
callback(message + b64);
|
||
};
|
||
return fr.readAsDataURL(packet.data);
|
||
}
|
||
|
||
var b64data;
|
||
try {
|
||
b64data = String.fromCharCode.apply(null, new Uint8Array(packet.data));
|
||
} catch (e) {
|
||
// iPhone Safari doesn't let you apply with typed arrays
|
||
var typed = new Uint8Array(packet.data);
|
||
var basic = new Array(typed.length);
|
||
for (var i = 0; i < typed.length; i++) {
|
||
basic[i] = typed[i];
|
||
}
|
||
b64data = String.fromCharCode.apply(null, basic);
|
||
}
|
||
message += global.btoa(b64data);
|
||
return callback(message);
|
||
};
|
||
|
||
/**
|
||
* Decodes a packet. Changes format to Blob if requested.
|
||
*
|
||
* @return {Object} with `type` and `data` (if any)
|
||
* @api private
|
||
*/
|
||
|
||
exports.decodePacket = function (data, binaryType, utf8decode) {
|
||
// String data
|
||
if (typeof data == 'string' || data === undefined) {
|
||
if (data.charAt(0) == 'b') {
|
||
return exports.decodeBase64Packet(data.substr(1), binaryType);
|
||
}
|
||
|
||
if (utf8decode) {
|
||
try {
|
||
data = utf8.decode(data);
|
||
} catch (e) {
|
||
return err;
|
||
}
|
||
}
|
||
var type = data.charAt(0);
|
||
|
||
if (Number(type) != type || !packetslist[type]) {
|
||
return err;
|
||
}
|
||
|
||
if (data.length > 1) {
|
||
return { type: packetslist[type], data: data.substring(1) };
|
||
} else {
|
||
return { type: packetslist[type] };
|
||
}
|
||
}
|
||
|
||
var asArray = new Uint8Array(data);
|
||
var type = asArray[0];
|
||
var rest = sliceBuffer(data, 1);
|
||
if (Blob && binaryType === 'blob') {
|
||
rest = new Blob([rest]);
|
||
}
|
||
return { type: packetslist[type], data: rest };
|
||
};
|
||
|
||
/**
|
||
* Decodes a packet encoded in a base64 string
|
||
*
|
||
* @param {String} base64 encoded message
|
||
* @return {Object} with `type` and `data` (if any)
|
||
*/
|
||
|
||
exports.decodeBase64Packet = function(msg, binaryType) {
|
||
var type = packetslist[msg.charAt(0)];
|
||
if (!global.ArrayBuffer) {
|
||
return { type: type, data: { base64: true, data: msg.substr(1) } };
|
||
}
|
||
|
||
var data = base64encoder.decode(msg.substr(1));
|
||
|
||
if (binaryType === 'blob' && Blob) {
|
||
data = new Blob([data]);
|
||
}
|
||
|
||
return { type: type, data: data };
|
||
};
|
||
|
||
/**
|
||
* Encodes multiple messages (payload).
|
||
*
|
||
* <length>:data
|
||
*
|
||
* Example:
|
||
*
|
||
* 11:hello world2:hi
|
||
*
|
||
* If any contents are binary, they will be encoded as base64 strings. Base64
|
||
* encoded strings are marked with a b before the length specifier
|
||
*
|
||
* @param {Array} packets
|
||
* @api private
|
||
*/
|
||
|
||
exports.encodePayload = function (packets, supportsBinary, callback) {
|
||
if (typeof supportsBinary == 'function') {
|
||
callback = supportsBinary;
|
||
supportsBinary = null;
|
||
}
|
||
|
||
var isBinary = hasBinary(packets);
|
||
|
||
if (supportsBinary && isBinary) {
|
||
if (Blob && !dontSendBlobs) {
|
||
return exports.encodePayloadAsBlob(packets, callback);
|
||
}
|
||
|
||
return exports.encodePayloadAsArrayBuffer(packets, callback);
|
||
}
|
||
|
||
if (!packets.length) {
|
||
return callback('0:');
|
||
}
|
||
|
||
function setLengthHeader(message) {
|
||
return message.length + ':' + message;
|
||
}
|
||
|
||
function encodeOne(packet, doneCallback) {
|
||
exports.encodePacket(packet, !isBinary ? false : supportsBinary, true, function(message) {
|
||
doneCallback(null, setLengthHeader(message));
|
||
});
|
||
}
|
||
|
||
map(packets, encodeOne, function(err, results) {
|
||
return callback(results.join(''));
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Async array map using after
|
||
*/
|
||
|
||
function map(ary, each, done) {
|
||
var result = new Array(ary.length);
|
||
var next = after(ary.length, done);
|
||
|
||
var eachWithIndex = function(i, el, cb) {
|
||
each(el, function(error, msg) {
|
||
result[i] = msg;
|
||
cb(error, result);
|
||
});
|
||
};
|
||
|
||
for (var i = 0; i < ary.length; i++) {
|
||
eachWithIndex(i, ary[i], next);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Decodes data when a payload is maybe expected. Possible binary contents are
|
||
* decoded from their base64 representation
|
||
*
|
||
* @param {String} data, callback method
|
||
* @api public
|
||
*/
|
||
|
||
exports.decodePayload = function (data, binaryType, callback) {
|
||
if (typeof data != 'string') {
|
||
return exports.decodePayloadAsBinary(data, binaryType, callback);
|
||
}
|
||
|
||
if (typeof binaryType === 'function') {
|
||
callback = binaryType;
|
||
binaryType = null;
|
||
}
|
||
|
||
var packet;
|
||
if (data == '') {
|
||
// parser error - ignoring payload
|
||
return callback(err, 0, 1);
|
||
}
|
||
|
||
var length = ''
|
||
, n, msg;
|
||
|
||
for (var i = 0, l = data.length; i < l; i++) {
|
||
var chr = data.charAt(i);
|
||
|
||
if (':' != chr) {
|
||
length += chr;
|
||
} else {
|
||
if ('' == length || (length != (n = Number(length)))) {
|
||
// parser error - ignoring payload
|
||
return callback(err, 0, 1);
|
||
}
|
||
|
||
msg = data.substr(i + 1, n);
|
||
|
||
if (length != msg.length) {
|
||
// parser error - ignoring payload
|
||
return callback(err, 0, 1);
|
||
}
|
||
|
||
if (msg.length) {
|
||
packet = exports.decodePacket(msg, binaryType, true);
|
||
|
||
if (err.type == packet.type && err.data == packet.data) {
|
||
// parser error in individual packet - ignoring payload
|
||
return callback(err, 0, 1);
|
||
}
|
||
|
||
var ret = callback(packet, i + n, l);
|
||
if (false === ret) return;
|
||
}
|
||
|
||
// advance cursor
|
||
i += n;
|
||
length = '';
|
||
}
|
||
}
|
||
|
||
if (length != '') {
|
||
// parser error - ignoring payload
|
||
return callback(err, 0, 1);
|
||
}
|
||
|
||
};
|
||
|
||
/**
|
||
* Encodes multiple messages (payload) as binary.
|
||
*
|
||
* <1 = binary, 0 = string><number from 0-9><number from 0-9>[...]<number
|
||
* 255><data>
|
||
*
|
||
* Example:
|
||
* 1 3 255 1 2 3, if the binary contents are interpreted as 8 bit integers
|
||
*
|
||
* @param {Array} packets
|
||
* @return {ArrayBuffer} encoded payload
|
||
* @api private
|
||
*/
|
||
|
||
exports.encodePayloadAsArrayBuffer = function(packets, callback) {
|
||
if (!packets.length) {
|
||
return callback(new ArrayBuffer(0));
|
||
}
|
||
|
||
function encodeOne(packet, doneCallback) {
|
||
exports.encodePacket(packet, true, true, function(data) {
|
||
return doneCallback(null, data);
|
||
});
|
||
}
|
||
|
||
map(packets, encodeOne, function(err, encodedPackets) {
|
||
var totalLength = encodedPackets.reduce(function(acc, p) {
|
||
var len;
|
||
if (typeof p === 'string'){
|
||
len = p.length;
|
||
} else {
|
||
len = p.byteLength;
|
||
}
|
||
return acc + len.toString().length + len + 2; // string/binary identifier + separator = 2
|
||
}, 0);
|
||
|
||
var resultArray = new Uint8Array(totalLength);
|
||
|
||
var bufferIndex = 0;
|
||
encodedPackets.forEach(function(p) {
|
||
var isString = typeof p === 'string';
|
||
var ab = p;
|
||
if (isString) {
|
||
var view = new Uint8Array(p.length);
|
||
for (var i = 0; i < p.length; i++) {
|
||
view[i] = p.charCodeAt(i);
|
||
}
|
||
ab = view.buffer;
|
||
}
|
||
|
||
if (isString) { // not true binary
|
||
resultArray[bufferIndex++] = 0;
|
||
} else { // true binary
|
||
resultArray[bufferIndex++] = 1;
|
||
}
|
||
|
||
var lenStr = ab.byteLength.toString();
|
||
for (var i = 0; i < lenStr.length; i++) {
|
||
resultArray[bufferIndex++] = parseInt(lenStr[i]);
|
||
}
|
||
resultArray[bufferIndex++] = 255;
|
||
|
||
var view = new Uint8Array(ab);
|
||
for (var i = 0; i < view.length; i++) {
|
||
resultArray[bufferIndex++] = view[i];
|
||
}
|
||
});
|
||
|
||
return callback(resultArray.buffer);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Encode as Blob
|
||
*/
|
||
|
||
exports.encodePayloadAsBlob = function(packets, callback) {
|
||
function encodeOne(packet, doneCallback) {
|
||
exports.encodePacket(packet, true, true, function(encoded) {
|
||
var binaryIdentifier = new Uint8Array(1);
|
||
binaryIdentifier[0] = 1;
|
||
if (typeof encoded === 'string') {
|
||
var view = new Uint8Array(encoded.length);
|
||
for (var i = 0; i < encoded.length; i++) {
|
||
view[i] = encoded.charCodeAt(i);
|
||
}
|
||
encoded = view.buffer;
|
||
binaryIdentifier[0] = 0;
|
||
}
|
||
|
||
var len = (encoded instanceof ArrayBuffer)
|
||
? encoded.byteLength
|
||
: encoded.size;
|
||
|
||
var lenStr = len.toString();
|
||
var lengthAry = new Uint8Array(lenStr.length + 1);
|
||
for (var i = 0; i < lenStr.length; i++) {
|
||
lengthAry[i] = parseInt(lenStr[i]);
|
||
}
|
||
lengthAry[lenStr.length] = 255;
|
||
|
||
if (Blob) {
|
||
var blob = new Blob([binaryIdentifier.buffer, lengthAry.buffer, encoded]);
|
||
doneCallback(null, blob);
|
||
}
|
||
});
|
||
}
|
||
|
||
map(packets, encodeOne, function(err, results) {
|
||
return callback(new Blob(results));
|
||
});
|
||
};
|
||
|
||
/*
|
||
* Decodes data when a payload is maybe expected. Strings are decoded by
|
||
* interpreting each byte as a key code for entries marked to start with 0. See
|
||
* description of encodePayloadAsBinary
|
||
*
|
||
* @param {ArrayBuffer} data, callback method
|
||
* @api public
|
||
*/
|
||
|
||
exports.decodePayloadAsBinary = function (data, binaryType, callback) {
|
||
if (typeof binaryType === 'function') {
|
||
callback = binaryType;
|
||
binaryType = null;
|
||
}
|
||
|
||
var bufferTail = data;
|
||
var buffers = [];
|
||
|
||
var numberTooLong = false;
|
||
while (bufferTail.byteLength > 0) {
|
||
var tailArray = new Uint8Array(bufferTail);
|
||
var isString = tailArray[0] === 0;
|
||
var msgLength = '';
|
||
|
||
for (var i = 1; ; i++) {
|
||
if (tailArray[i] == 255) break;
|
||
|
||
if (msgLength.length > 310) {
|
||
numberTooLong = true;
|
||
break;
|
||
}
|
||
|
||
msgLength += tailArray[i];
|
||
}
|
||
|
||
if(numberTooLong) return callback(err, 0, 1);
|
||
|
||
bufferTail = sliceBuffer(bufferTail, 2 + msgLength.length);
|
||
msgLength = parseInt(msgLength);
|
||
|
||
var msg = sliceBuffer(bufferTail, 0, msgLength);
|
||
if (isString) {
|
||
try {
|
||
msg = String.fromCharCode.apply(null, new Uint8Array(msg));
|
||
} catch (e) {
|
||
// iPhone Safari doesn't let you apply to typed arrays
|
||
var typed = new Uint8Array(msg);
|
||
msg = '';
|
||
for (var i = 0; i < typed.length; i++) {
|
||
msg += String.fromCharCode(typed[i]);
|
||
}
|
||
}
|
||
}
|
||
|
||
buffers.push(msg);
|
||
bufferTail = sliceBuffer(bufferTail, msgLength);
|
||
}
|
||
|
||
var total = buffers.length;
|
||
buffers.forEach(function(buffer, i) {
|
||
callback(exports.decodePacket(buffer, binaryType, true), i, total);
|
||
});
|
||
};
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 93 */
|
||
/***/ function(module, exports) {
|
||
|
||
|
||
/**
|
||
* Gets the keys for an object.
|
||
*
|
||
* @return {Array} keys
|
||
* @api private
|
||
*/
|
||
|
||
module.exports = Object.keys || function keys (obj){
|
||
var arr = [];
|
||
var has = Object.prototype.hasOwnProperty;
|
||
|
||
for (var i in obj) {
|
||
if (has.call(obj, i)) {
|
||
arr.push(i);
|
||
}
|
||
}
|
||
return arr;
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 94 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(global) {
|
||
/*
|
||
* Module requirements.
|
||
*/
|
||
|
||
var isArray = __webpack_require__(95);
|
||
|
||
/**
|
||
* Module exports.
|
||
*/
|
||
|
||
module.exports = hasBinary;
|
||
|
||
/**
|
||
* Checks for binary data.
|
||
*
|
||
* Right now only Buffer and ArrayBuffer are supported..
|
||
*
|
||
* @param {Object} anything
|
||
* @api public
|
||
*/
|
||
|
||
function hasBinary(data) {
|
||
|
||
function _hasBinary(obj) {
|
||
if (!obj) return false;
|
||
|
||
if ( (global.Buffer && global.Buffer.isBuffer(obj)) ||
|
||
(global.ArrayBuffer && obj instanceof ArrayBuffer) ||
|
||
(global.Blob && obj instanceof Blob) ||
|
||
(global.File && obj instanceof File)
|
||
) {
|
||
return true;
|
||
}
|
||
|
||
if (isArray(obj)) {
|
||
for (var i = 0; i < obj.length; i++) {
|
||
if (_hasBinary(obj[i])) {
|
||
return true;
|
||
}
|
||
}
|
||
} else if (obj && 'object' == typeof obj) {
|
||
if (obj.toJSON) {
|
||
obj = obj.toJSON();
|
||
}
|
||
|
||
for (var key in obj) {
|
||
if (Object.prototype.hasOwnProperty.call(obj, key) && _hasBinary(obj[key])) {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
return _hasBinary(data);
|
||
}
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 95 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = Array.isArray || function (arr) {
|
||
return Object.prototype.toString.call(arr) == '[object Array]';
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 96 */
|
||
/***/ function(module, exports) {
|
||
|
||
/**
|
||
* An abstraction for slicing an arraybuffer even when
|
||
* ArrayBuffer.prototype.slice is not supported
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
module.exports = function(arraybuffer, start, end) {
|
||
var bytes = arraybuffer.byteLength;
|
||
start = start || 0;
|
||
end = end || bytes;
|
||
|
||
if (arraybuffer.slice) { return arraybuffer.slice(start, end); }
|
||
|
||
if (start < 0) { start += bytes; }
|
||
if (end < 0) { end += bytes; }
|
||
if (end > bytes) { end = bytes; }
|
||
|
||
if (start >= bytes || start >= end || bytes === 0) {
|
||
return new ArrayBuffer(0);
|
||
}
|
||
|
||
var abv = new Uint8Array(arraybuffer);
|
||
var result = new Uint8Array(end - start);
|
||
for (var i = start, ii = 0; i < end; i++, ii++) {
|
||
result[ii] = abv[i];
|
||
}
|
||
return result.buffer;
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 97 */
|
||
/***/ function(module, exports) {
|
||
|
||
/*
|
||
* base64-arraybuffer
|
||
* https://github.com/niklasvh/base64-arraybuffer
|
||
*
|
||
* Copyright (c) 2012 Niklas von Hertzen
|
||
* Licensed under the MIT license.
|
||
*/
|
||
(function(chars){
|
||
"use strict";
|
||
|
||
exports.encode = function(arraybuffer) {
|
||
var bytes = new Uint8Array(arraybuffer),
|
||
i, len = bytes.length, base64 = "";
|
||
|
||
for (i = 0; i < len; i+=3) {
|
||
base64 += chars[bytes[i] >> 2];
|
||
base64 += chars[((bytes[i] & 3) << 4) | (bytes[i + 1] >> 4)];
|
||
base64 += chars[((bytes[i + 1] & 15) << 2) | (bytes[i + 2] >> 6)];
|
||
base64 += chars[bytes[i + 2] & 63];
|
||
}
|
||
|
||
if ((len % 3) === 2) {
|
||
base64 = base64.substring(0, base64.length - 1) + "=";
|
||
} else if (len % 3 === 1) {
|
||
base64 = base64.substring(0, base64.length - 2) + "==";
|
||
}
|
||
|
||
return base64;
|
||
};
|
||
|
||
exports.decode = function(base64) {
|
||
var bufferLength = base64.length * 0.75,
|
||
len = base64.length, i, p = 0,
|
||
encoded1, encoded2, encoded3, encoded4;
|
||
|
||
if (base64[base64.length - 1] === "=") {
|
||
bufferLength--;
|
||
if (base64[base64.length - 2] === "=") {
|
||
bufferLength--;
|
||
}
|
||
}
|
||
|
||
var arraybuffer = new ArrayBuffer(bufferLength),
|
||
bytes = new Uint8Array(arraybuffer);
|
||
|
||
for (i = 0; i < len; i+=4) {
|
||
encoded1 = chars.indexOf(base64[i]);
|
||
encoded2 = chars.indexOf(base64[i+1]);
|
||
encoded3 = chars.indexOf(base64[i+2]);
|
||
encoded4 = chars.indexOf(base64[i+3]);
|
||
|
||
bytes[p++] = (encoded1 << 2) | (encoded2 >> 4);
|
||
bytes[p++] = ((encoded2 & 15) << 4) | (encoded3 >> 2);
|
||
bytes[p++] = ((encoded3 & 3) << 6) | (encoded4 & 63);
|
||
}
|
||
|
||
return arraybuffer;
|
||
};
|
||
})("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
|
||
|
||
|
||
/***/ },
|
||
/* 98 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = after
|
||
|
||
function after(count, callback, err_cb) {
|
||
var bail = false
|
||
err_cb = err_cb || noop
|
||
proxy.count = count
|
||
|
||
return (count === 0) ? callback() : proxy
|
||
|
||
function proxy(err, result) {
|
||
if (proxy.count <= 0) {
|
||
throw new Error('after called too many times')
|
||
}
|
||
--proxy.count
|
||
|
||
// after first error, rest are passed to err_cb
|
||
if (err) {
|
||
bail = true
|
||
callback(err)
|
||
// future error callbacks will go to error handler
|
||
callback = err_cb
|
||
} else if (proxy.count === 0 && !bail) {
|
||
callback(null, result)
|
||
}
|
||
}
|
||
}
|
||
|
||
function noop() {}
|
||
|
||
|
||
/***/ },
|
||
/* 99 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(module, global) {/*! https://mths.be/utf8js v2.0.0 by @mathias */
|
||
;(function(root) {
|
||
|
||
// Detect free variables `exports`
|
||
var freeExports = typeof exports == 'object' && exports;
|
||
|
||
// Detect free variable `module`
|
||
var freeModule = typeof module == 'object' && module &&
|
||
module.exports == freeExports && module;
|
||
|
||
// Detect free variable `global`, from Node.js or Browserified code,
|
||
// and use it as `root`
|
||
var freeGlobal = typeof global == 'object' && global;
|
||
if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
|
||
root = freeGlobal;
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------*/
|
||
|
||
var stringFromCharCode = String.fromCharCode;
|
||
|
||
// Taken from https://mths.be/punycode
|
||
function ucs2decode(string) {
|
||
var output = [];
|
||
var counter = 0;
|
||
var length = string.length;
|
||
var value;
|
||
var 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;
|
||
}
|
||
|
||
// Taken from https://mths.be/punycode
|
||
function ucs2encode(array) {
|
||
var length = array.length;
|
||
var index = -1;
|
||
var value;
|
||
var output = '';
|
||
while (++index < length) {
|
||
value = array[index];
|
||
if (value > 0xFFFF) {
|
||
value -= 0x10000;
|
||
output += stringFromCharCode(value >>> 10 & 0x3FF | 0xD800);
|
||
value = 0xDC00 | value & 0x3FF;
|
||
}
|
||
output += stringFromCharCode(value);
|
||
}
|
||
return output;
|
||
}
|
||
|
||
function checkScalarValue(codePoint) {
|
||
if (codePoint >= 0xD800 && codePoint <= 0xDFFF) {
|
||
throw Error(
|
||
'Lone surrogate U+' + codePoint.toString(16).toUpperCase() +
|
||
' is not a scalar value'
|
||
);
|
||
}
|
||
}
|
||
/*--------------------------------------------------------------------------*/
|
||
|
||
function createByte(codePoint, shift) {
|
||
return stringFromCharCode(((codePoint >> shift) & 0x3F) | 0x80);
|
||
}
|
||
|
||
function encodeCodePoint(codePoint) {
|
||
if ((codePoint & 0xFFFFFF80) == 0) { // 1-byte sequence
|
||
return stringFromCharCode(codePoint);
|
||
}
|
||
var symbol = '';
|
||
if ((codePoint & 0xFFFFF800) == 0) { // 2-byte sequence
|
||
symbol = stringFromCharCode(((codePoint >> 6) & 0x1F) | 0xC0);
|
||
}
|
||
else if ((codePoint & 0xFFFF0000) == 0) { // 3-byte sequence
|
||
checkScalarValue(codePoint);
|
||
symbol = stringFromCharCode(((codePoint >> 12) & 0x0F) | 0xE0);
|
||
symbol += createByte(codePoint, 6);
|
||
}
|
||
else if ((codePoint & 0xFFE00000) == 0) { // 4-byte sequence
|
||
symbol = stringFromCharCode(((codePoint >> 18) & 0x07) | 0xF0);
|
||
symbol += createByte(codePoint, 12);
|
||
symbol += createByte(codePoint, 6);
|
||
}
|
||
symbol += stringFromCharCode((codePoint & 0x3F) | 0x80);
|
||
return symbol;
|
||
}
|
||
|
||
function utf8encode(string) {
|
||
var codePoints = ucs2decode(string);
|
||
var length = codePoints.length;
|
||
var index = -1;
|
||
var codePoint;
|
||
var byteString = '';
|
||
while (++index < length) {
|
||
codePoint = codePoints[index];
|
||
byteString += encodeCodePoint(codePoint);
|
||
}
|
||
return byteString;
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------*/
|
||
|
||
function readContinuationByte() {
|
||
if (byteIndex >= byteCount) {
|
||
throw Error('Invalid byte index');
|
||
}
|
||
|
||
var continuationByte = byteArray[byteIndex] & 0xFF;
|
||
byteIndex++;
|
||
|
||
if ((continuationByte & 0xC0) == 0x80) {
|
||
return continuationByte & 0x3F;
|
||
}
|
||
|
||
// If we end up here, it’s not a continuation byte
|
||
throw Error('Invalid continuation byte');
|
||
}
|
||
|
||
function decodeSymbol() {
|
||
var byte1;
|
||
var byte2;
|
||
var byte3;
|
||
var byte4;
|
||
var codePoint;
|
||
|
||
if (byteIndex > byteCount) {
|
||
throw Error('Invalid byte index');
|
||
}
|
||
|
||
if (byteIndex == byteCount) {
|
||
return false;
|
||
}
|
||
|
||
// Read first byte
|
||
byte1 = byteArray[byteIndex] & 0xFF;
|
||
byteIndex++;
|
||
|
||
// 1-byte sequence (no continuation bytes)
|
||
if ((byte1 & 0x80) == 0) {
|
||
return byte1;
|
||
}
|
||
|
||
// 2-byte sequence
|
||
if ((byte1 & 0xE0) == 0xC0) {
|
||
var byte2 = readContinuationByte();
|
||
codePoint = ((byte1 & 0x1F) << 6) | byte2;
|
||
if (codePoint >= 0x80) {
|
||
return codePoint;
|
||
} else {
|
||
throw Error('Invalid continuation byte');
|
||
}
|
||
}
|
||
|
||
// 3-byte sequence (may include unpaired surrogates)
|
||
if ((byte1 & 0xF0) == 0xE0) {
|
||
byte2 = readContinuationByte();
|
||
byte3 = readContinuationByte();
|
||
codePoint = ((byte1 & 0x0F) << 12) | (byte2 << 6) | byte3;
|
||
if (codePoint >= 0x0800) {
|
||
checkScalarValue(codePoint);
|
||
return codePoint;
|
||
} else {
|
||
throw Error('Invalid continuation byte');
|
||
}
|
||
}
|
||
|
||
// 4-byte sequence
|
||
if ((byte1 & 0xF8) == 0xF0) {
|
||
byte2 = readContinuationByte();
|
||
byte3 = readContinuationByte();
|
||
byte4 = readContinuationByte();
|
||
codePoint = ((byte1 & 0x0F) << 0x12) | (byte2 << 0x0C) |
|
||
(byte3 << 0x06) | byte4;
|
||
if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {
|
||
return codePoint;
|
||
}
|
||
}
|
||
|
||
throw Error('Invalid UTF-8 detected');
|
||
}
|
||
|
||
var byteArray;
|
||
var byteCount;
|
||
var byteIndex;
|
||
function utf8decode(byteString) {
|
||
byteArray = ucs2decode(byteString);
|
||
byteCount = byteArray.length;
|
||
byteIndex = 0;
|
||
var codePoints = [];
|
||
var tmp;
|
||
while ((tmp = decodeSymbol()) !== false) {
|
||
codePoints.push(tmp);
|
||
}
|
||
return ucs2encode(codePoints);
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------*/
|
||
|
||
var utf8 = {
|
||
'version': '2.0.0',
|
||
'encode': utf8encode,
|
||
'decode': utf8decode
|
||
};
|
||
|
||
// Some AMD build optimizers, like r.js, check for specific condition patterns
|
||
// like the following:
|
||
if (
|
||
true
|
||
) {
|
||
!(__WEBPACK_AMD_DEFINE_RESULT__ = function() {
|
||
return utf8;
|
||
}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
|
||
} else if (freeExports && !freeExports.nodeType) {
|
||
if (freeModule) { // in Node.js or RingoJS v0.8.0+
|
||
freeModule.exports = utf8;
|
||
} else { // in Narwhal or RingoJS v0.7.0-
|
||
var object = {};
|
||
var hasOwnProperty = object.hasOwnProperty;
|
||
for (var key in utf8) {
|
||
hasOwnProperty.call(utf8, key) && (freeExports[key] = utf8[key]);
|
||
}
|
||
}
|
||
} else { // in Rhino or a web browser
|
||
root.utf8 = utf8;
|
||
}
|
||
|
||
}(this));
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(76)(module), (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 100 */
|
||
/***/ function(module, exports) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(global) {/**
|
||
* Create a blob builder even when vendor prefixes exist
|
||
*/
|
||
|
||
var BlobBuilder = global.BlobBuilder
|
||
|| global.WebKitBlobBuilder
|
||
|| global.MSBlobBuilder
|
||
|| global.MozBlobBuilder;
|
||
|
||
/**
|
||
* Check if Blob constructor is supported
|
||
*/
|
||
|
||
var blobSupported = (function() {
|
||
try {
|
||
var a = new Blob(['hi']);
|
||
return a.size === 2;
|
||
} catch(e) {
|
||
return false;
|
||
}
|
||
})();
|
||
|
||
/**
|
||
* Check if Blob constructor supports ArrayBufferViews
|
||
* Fails in Safari 6, so we need to map to ArrayBuffers there.
|
||
*/
|
||
|
||
var blobSupportsArrayBufferView = blobSupported && (function() {
|
||
try {
|
||
var b = new Blob([new Uint8Array([1,2])]);
|
||
return b.size === 2;
|
||
} catch(e) {
|
||
return false;
|
||
}
|
||
})();
|
||
|
||
/**
|
||
* Check if BlobBuilder is supported
|
||
*/
|
||
|
||
var blobBuilderSupported = BlobBuilder
|
||
&& BlobBuilder.prototype.append
|
||
&& BlobBuilder.prototype.getBlob;
|
||
|
||
/**
|
||
* Helper function that maps ArrayBufferViews to ArrayBuffers
|
||
* Used by BlobBuilder constructor and old browsers that didn't
|
||
* support it in the Blob constructor.
|
||
*/
|
||
|
||
function mapArrayBufferViews(ary) {
|
||
for (var i = 0; i < ary.length; i++) {
|
||
var chunk = ary[i];
|
||
if (chunk.buffer instanceof ArrayBuffer) {
|
||
var buf = chunk.buffer;
|
||
|
||
// if this is a subarray, make a copy so we only
|
||
// include the subarray region from the underlying buffer
|
||
if (chunk.byteLength !== buf.byteLength) {
|
||
var copy = new Uint8Array(chunk.byteLength);
|
||
copy.set(new Uint8Array(buf, chunk.byteOffset, chunk.byteLength));
|
||
buf = copy.buffer;
|
||
}
|
||
|
||
ary[i] = buf;
|
||
}
|
||
}
|
||
}
|
||
|
||
function BlobBuilderConstructor(ary, options) {
|
||
options = options || {};
|
||
|
||
var bb = new BlobBuilder();
|
||
mapArrayBufferViews(ary);
|
||
|
||
for (var i = 0; i < ary.length; i++) {
|
||
bb.append(ary[i]);
|
||
}
|
||
|
||
return (options.type) ? bb.getBlob(options.type) : bb.getBlob();
|
||
};
|
||
|
||
function BlobConstructor(ary, options) {
|
||
mapArrayBufferViews(ary);
|
||
return new Blob(ary, options || {});
|
||
};
|
||
|
||
module.exports = (function() {
|
||
if (blobSupported) {
|
||
return blobSupportsArrayBufferView ? global.Blob : BlobConstructor;
|
||
} else if (blobBuilderSupported) {
|
||
return BlobBuilderConstructor;
|
||
} else {
|
||
return undefined;
|
||
}
|
||
})();
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 101 */
|
||
/***/ function(module, exports) {
|
||
|
||
|
||
/**
|
||
* Expose `Emitter`.
|
||
*/
|
||
|
||
module.exports = Emitter;
|
||
|
||
/**
|
||
* Initialize a new `Emitter`.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
function Emitter(obj) {
|
||
if (obj) return mixin(obj);
|
||
};
|
||
|
||
/**
|
||
* Mixin the emitter properties.
|
||
*
|
||
* @param {Object} obj
|
||
* @return {Object}
|
||
* @api private
|
||
*/
|
||
|
||
function mixin(obj) {
|
||
for (var key in Emitter.prototype) {
|
||
obj[key] = Emitter.prototype[key];
|
||
}
|
||
return obj;
|
||
}
|
||
|
||
/**
|
||
* Listen on the given `event` with `fn`.
|
||
*
|
||
* @param {String} event
|
||
* @param {Function} fn
|
||
* @return {Emitter}
|
||
* @api public
|
||
*/
|
||
|
||
Emitter.prototype.on =
|
||
Emitter.prototype.addEventListener = function(event, fn){
|
||
this._callbacks = this._callbacks || {};
|
||
(this._callbacks[event] = this._callbacks[event] || [])
|
||
.push(fn);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Adds an `event` listener that will be invoked a single
|
||
* time then automatically removed.
|
||
*
|
||
* @param {String} event
|
||
* @param {Function} fn
|
||
* @return {Emitter}
|
||
* @api public
|
||
*/
|
||
|
||
Emitter.prototype.once = function(event, fn){
|
||
var self = this;
|
||
this._callbacks = this._callbacks || {};
|
||
|
||
function on() {
|
||
self.off(event, on);
|
||
fn.apply(this, arguments);
|
||
}
|
||
|
||
on.fn = fn;
|
||
this.on(event, on);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Remove the given callback for `event` or all
|
||
* registered callbacks.
|
||
*
|
||
* @param {String} event
|
||
* @param {Function} fn
|
||
* @return {Emitter}
|
||
* @api public
|
||
*/
|
||
|
||
Emitter.prototype.off =
|
||
Emitter.prototype.removeListener =
|
||
Emitter.prototype.removeAllListeners =
|
||
Emitter.prototype.removeEventListener = function(event, fn){
|
||
this._callbacks = this._callbacks || {};
|
||
|
||
// all
|
||
if (0 == arguments.length) {
|
||
this._callbacks = {};
|
||
return this;
|
||
}
|
||
|
||
// specific event
|
||
var callbacks = this._callbacks[event];
|
||
if (!callbacks) return this;
|
||
|
||
// remove all handlers
|
||
if (1 == arguments.length) {
|
||
delete this._callbacks[event];
|
||
return this;
|
||
}
|
||
|
||
// remove specific handler
|
||
var cb;
|
||
for (var i = 0; i < callbacks.length; i++) {
|
||
cb = callbacks[i];
|
||
if (cb === fn || cb.fn === fn) {
|
||
callbacks.splice(i, 1);
|
||
break;
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Emit `event` with the given args.
|
||
*
|
||
* @param {String} event
|
||
* @param {Mixed} ...
|
||
* @return {Emitter}
|
||
*/
|
||
|
||
Emitter.prototype.emit = function(event){
|
||
this._callbacks = this._callbacks || {};
|
||
var args = [].slice.call(arguments, 1)
|
||
, callbacks = this._callbacks[event];
|
||
|
||
if (callbacks) {
|
||
callbacks = callbacks.slice(0);
|
||
for (var i = 0, len = callbacks.length; i < len; ++i) {
|
||
callbacks[i].apply(this, args);
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Return array of callbacks for `event`.
|
||
*
|
||
* @param {String} event
|
||
* @return {Array}
|
||
* @api public
|
||
*/
|
||
|
||
Emitter.prototype.listeners = function(event){
|
||
this._callbacks = this._callbacks || {};
|
||
return this._callbacks[event] || [];
|
||
};
|
||
|
||
/**
|
||
* Check if this emitter has `event` handlers.
|
||
*
|
||
* @param {String} event
|
||
* @return {Boolean}
|
||
* @api public
|
||
*/
|
||
|
||
Emitter.prototype.hasListeners = function(event){
|
||
return !! this.listeners(event).length;
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 102 */
|
||
/***/ function(module, exports) {
|
||
|
||
/**
|
||
* Compiles a querystring
|
||
* Returns string representation of the object
|
||
*
|
||
* @param {Object}
|
||
* @api private
|
||
*/
|
||
|
||
exports.encode = function (obj) {
|
||
var str = '';
|
||
|
||
for (var i in obj) {
|
||
if (obj.hasOwnProperty(i)) {
|
||
if (str.length) str += '&';
|
||
str += encodeURIComponent(i) + '=' + encodeURIComponent(obj[i]);
|
||
}
|
||
}
|
||
|
||
return str;
|
||
};
|
||
|
||
/**
|
||
* Parses a simple querystring into an object
|
||
*
|
||
* @param {String} qs
|
||
* @api private
|
||
*/
|
||
|
||
exports.decode = function(qs){
|
||
var qry = {};
|
||
var pairs = qs.split('&');
|
||
for (var i = 0, l = pairs.length; i < l; i++) {
|
||
var pair = pairs[i].split('=');
|
||
qry[decodeURIComponent(pair[0])] = decodeURIComponent(pair[1]);
|
||
}
|
||
return qry;
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 103 */
|
||
/***/ function(module, exports) {
|
||
|
||
|
||
module.exports = function(a, b){
|
||
var fn = function(){};
|
||
fn.prototype = b.prototype;
|
||
a.prototype = new fn;
|
||
a.prototype.constructor = a;
|
||
};
|
||
|
||
/***/ },
|
||
/* 104 */
|
||
/***/ function(module, exports) {
|
||
|
||
'use strict';
|
||
|
||
var alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_'.split('')
|
||
, length = 64
|
||
, map = {}
|
||
, seed = 0
|
||
, i = 0
|
||
, prev;
|
||
|
||
/**
|
||
* Return a string representing the specified number.
|
||
*
|
||
* @param {Number} num The number to convert.
|
||
* @returns {String} The string representation of the number.
|
||
* @api public
|
||
*/
|
||
function encode(num) {
|
||
var encoded = '';
|
||
|
||
do {
|
||
encoded = alphabet[num % length] + encoded;
|
||
num = Math.floor(num / length);
|
||
} while (num > 0);
|
||
|
||
return encoded;
|
||
}
|
||
|
||
/**
|
||
* Return the integer value specified by the given string.
|
||
*
|
||
* @param {String} str The string to convert.
|
||
* @returns {Number} The integer value represented by the string.
|
||
* @api public
|
||
*/
|
||
function decode(str) {
|
||
var decoded = 0;
|
||
|
||
for (i = 0; i < str.length; i++) {
|
||
decoded = decoded * length + map[str.charAt(i)];
|
||
}
|
||
|
||
return decoded;
|
||
}
|
||
|
||
/**
|
||
* Yeast: A tiny growing id generator.
|
||
*
|
||
* @returns {String} A unique id.
|
||
* @api public
|
||
*/
|
||
function yeast() {
|
||
var now = encode(+new Date());
|
||
|
||
if (now !== prev) return seed = 0, prev = now;
|
||
return now +'.'+ encode(seed++);
|
||
}
|
||
|
||
//
|
||
// Map each character to its index.
|
||
//
|
||
for (; i < length; i++) map[alphabet[i]] = i;
|
||
|
||
//
|
||
// Expose the `yeast`, `encode` and `decode` functions.
|
||
//
|
||
yeast.encode = encode;
|
||
yeast.decode = decode;
|
||
module.exports = yeast;
|
||
|
||
|
||
/***/ },
|
||
/* 105 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(global) {
|
||
/**
|
||
* Module requirements.
|
||
*/
|
||
|
||
var Polling = __webpack_require__(90);
|
||
var inherit = __webpack_require__(103);
|
||
|
||
/**
|
||
* Module exports.
|
||
*/
|
||
|
||
module.exports = JSONPPolling;
|
||
|
||
/**
|
||
* Cached regular expressions.
|
||
*/
|
||
|
||
var rNewline = /\n/g;
|
||
var rEscapedNewline = /\\n/g;
|
||
|
||
/**
|
||
* Global JSONP callbacks.
|
||
*/
|
||
|
||
var callbacks;
|
||
|
||
/**
|
||
* Callbacks count.
|
||
*/
|
||
|
||
var index = 0;
|
||
|
||
/**
|
||
* Noop.
|
||
*/
|
||
|
||
function empty () { }
|
||
|
||
/**
|
||
* JSONP Polling constructor.
|
||
*
|
||
* @param {Object} opts.
|
||
* @api public
|
||
*/
|
||
|
||
function JSONPPolling (opts) {
|
||
Polling.call(this, opts);
|
||
|
||
this.query = this.query || {};
|
||
|
||
// define global callbacks array if not present
|
||
// we do this here (lazily) to avoid unneeded global pollution
|
||
if (!callbacks) {
|
||
// we need to consider multiple engines in the same page
|
||
if (!global.___eio) global.___eio = [];
|
||
callbacks = global.___eio;
|
||
}
|
||
|
||
// callback identifier
|
||
this.index = callbacks.length;
|
||
|
||
// add callback to jsonp global
|
||
var self = this;
|
||
callbacks.push(function (msg) {
|
||
self.onData(msg);
|
||
});
|
||
|
||
// append to query string
|
||
this.query.j = this.index;
|
||
|
||
// prevent spurious errors from being emitted when the window is unloaded
|
||
if (global.document && global.addEventListener) {
|
||
global.addEventListener('beforeunload', function () {
|
||
if (self.script) self.script.onerror = empty;
|
||
}, false);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Inherits from Polling.
|
||
*/
|
||
|
||
inherit(JSONPPolling, Polling);
|
||
|
||
/*
|
||
* JSONP only supports binary as base64 encoded strings
|
||
*/
|
||
|
||
JSONPPolling.prototype.supportsBinary = false;
|
||
|
||
/**
|
||
* Closes the socket.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
JSONPPolling.prototype.doClose = function () {
|
||
if (this.script) {
|
||
this.script.parentNode.removeChild(this.script);
|
||
this.script = null;
|
||
}
|
||
|
||
if (this.form) {
|
||
this.form.parentNode.removeChild(this.form);
|
||
this.form = null;
|
||
this.iframe = null;
|
||
}
|
||
|
||
Polling.prototype.doClose.call(this);
|
||
};
|
||
|
||
/**
|
||
* Starts a poll cycle.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
JSONPPolling.prototype.doPoll = function () {
|
||
var self = this;
|
||
var script = document.createElement('script');
|
||
|
||
if (this.script) {
|
||
this.script.parentNode.removeChild(this.script);
|
||
this.script = null;
|
||
}
|
||
|
||
script.async = true;
|
||
script.src = this.uri();
|
||
script.onerror = function(e){
|
||
self.onError('jsonp poll error',e);
|
||
};
|
||
|
||
var insertAt = document.getElementsByTagName('script')[0];
|
||
if (insertAt) {
|
||
insertAt.parentNode.insertBefore(script, insertAt);
|
||
}
|
||
else {
|
||
(document.head || document.body).appendChild(script);
|
||
}
|
||
this.script = script;
|
||
|
||
var isUAgecko = 'undefined' != typeof navigator && /gecko/i.test(navigator.userAgent);
|
||
|
||
if (isUAgecko) {
|
||
setTimeout(function () {
|
||
var iframe = document.createElement('iframe');
|
||
document.body.appendChild(iframe);
|
||
document.body.removeChild(iframe);
|
||
}, 100);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Writes with a hidden iframe.
|
||
*
|
||
* @param {String} data to send
|
||
* @param {Function} called upon flush.
|
||
* @api private
|
||
*/
|
||
|
||
JSONPPolling.prototype.doWrite = function (data, fn) {
|
||
var self = this;
|
||
|
||
if (!this.form) {
|
||
var form = document.createElement('form');
|
||
var area = document.createElement('textarea');
|
||
var id = this.iframeId = 'eio_iframe_' + this.index;
|
||
var iframe;
|
||
|
||
form.className = 'socketio';
|
||
form.style.position = 'absolute';
|
||
form.style.top = '-1000px';
|
||
form.style.left = '-1000px';
|
||
form.target = id;
|
||
form.method = 'POST';
|
||
form.setAttribute('accept-charset', 'utf-8');
|
||
area.name = 'd';
|
||
form.appendChild(area);
|
||
document.body.appendChild(form);
|
||
|
||
this.form = form;
|
||
this.area = area;
|
||
}
|
||
|
||
this.form.action = this.uri();
|
||
|
||
function complete () {
|
||
initIframe();
|
||
fn();
|
||
}
|
||
|
||
function initIframe () {
|
||
if (self.iframe) {
|
||
try {
|
||
self.form.removeChild(self.iframe);
|
||
} catch (e) {
|
||
self.onError('jsonp polling iframe removal error', e);
|
||
}
|
||
}
|
||
|
||
try {
|
||
// ie6 dynamic iframes with target="" support (thanks Chris Lambacher)
|
||
var html = '<iframe src="javascript:0" name="'+ self.iframeId +'">';
|
||
iframe = document.createElement(html);
|
||
} catch (e) {
|
||
iframe = document.createElement('iframe');
|
||
iframe.name = self.iframeId;
|
||
iframe.src = 'javascript:0';
|
||
}
|
||
|
||
iframe.id = self.iframeId;
|
||
|
||
self.form.appendChild(iframe);
|
||
self.iframe = iframe;
|
||
}
|
||
|
||
initIframe();
|
||
|
||
// escape \n to prevent it from being converted into \r\n by some UAs
|
||
// double escaping is required for escaped new lines because unescaping of new lines can be done safely on server-side
|
||
data = data.replace(rEscapedNewline, '\\\n');
|
||
this.area.value = data.replace(rNewline, '\\n');
|
||
|
||
try {
|
||
this.form.submit();
|
||
} catch(e) {}
|
||
|
||
if (this.iframe.attachEvent) {
|
||
this.iframe.onreadystatechange = function(){
|
||
if (self.iframe.readyState == 'complete') {
|
||
complete();
|
||
}
|
||
};
|
||
} else {
|
||
this.iframe.onload = complete;
|
||
}
|
||
};
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 106 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(global) {/**
|
||
* Module dependencies.
|
||
*/
|
||
|
||
var Transport = __webpack_require__(91);
|
||
var parser = __webpack_require__(92);
|
||
var parseqs = __webpack_require__(102);
|
||
var inherit = __webpack_require__(103);
|
||
var yeast = __webpack_require__(104);
|
||
var debug = __webpack_require__(71)('engine.io-client:websocket');
|
||
var BrowserWebSocket = global.WebSocket || global.MozWebSocket;
|
||
|
||
/**
|
||
* Get either the `WebSocket` or `MozWebSocket` globals
|
||
* in the browser or try to resolve WebSocket-compatible
|
||
* interface exposed by `ws` for Node-like environment.
|
||
*/
|
||
|
||
var WebSocket = BrowserWebSocket;
|
||
if (!WebSocket && typeof window === 'undefined') {
|
||
try {
|
||
WebSocket = __webpack_require__(107);
|
||
} catch (e) { }
|
||
}
|
||
|
||
/**
|
||
* Module exports.
|
||
*/
|
||
|
||
module.exports = WS;
|
||
|
||
/**
|
||
* WebSocket transport constructor.
|
||
*
|
||
* @api {Object} connection options
|
||
* @api public
|
||
*/
|
||
|
||
function WS(opts){
|
||
var forceBase64 = (opts && opts.forceBase64);
|
||
if (forceBase64) {
|
||
this.supportsBinary = false;
|
||
}
|
||
this.perMessageDeflate = opts.perMessageDeflate;
|
||
Transport.call(this, opts);
|
||
}
|
||
|
||
/**
|
||
* Inherits from Transport.
|
||
*/
|
||
|
||
inherit(WS, Transport);
|
||
|
||
/**
|
||
* Transport name.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
WS.prototype.name = 'websocket';
|
||
|
||
/*
|
||
* WebSockets support binary
|
||
*/
|
||
|
||
WS.prototype.supportsBinary = true;
|
||
|
||
/**
|
||
* Opens socket.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
WS.prototype.doOpen = function(){
|
||
if (!this.check()) {
|
||
// let probe timeout
|
||
return;
|
||
}
|
||
|
||
var self = this;
|
||
var uri = this.uri();
|
||
var protocols = void(0);
|
||
var opts = {
|
||
agent: this.agent,
|
||
perMessageDeflate: this.perMessageDeflate
|
||
};
|
||
|
||
// SSL options for Node.js client
|
||
opts.pfx = this.pfx;
|
||
opts.key = this.key;
|
||
opts.passphrase = this.passphrase;
|
||
opts.cert = this.cert;
|
||
opts.ca = this.ca;
|
||
opts.ciphers = this.ciphers;
|
||
opts.rejectUnauthorized = this.rejectUnauthorized;
|
||
if (this.extraHeaders) {
|
||
opts.headers = this.extraHeaders;
|
||
}
|
||
|
||
this.ws = BrowserWebSocket ? new WebSocket(uri) : new WebSocket(uri, protocols, opts);
|
||
|
||
if (this.ws.binaryType === undefined) {
|
||
this.supportsBinary = false;
|
||
}
|
||
|
||
if (this.ws.supports && this.ws.supports.binary) {
|
||
this.supportsBinary = true;
|
||
this.ws.binaryType = 'buffer';
|
||
} else {
|
||
this.ws.binaryType = 'arraybuffer';
|
||
}
|
||
|
||
this.addEventListeners();
|
||
};
|
||
|
||
/**
|
||
* Adds event listeners to the socket
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
WS.prototype.addEventListeners = function(){
|
||
var self = this;
|
||
|
||
this.ws.onopen = function(){
|
||
self.onOpen();
|
||
};
|
||
this.ws.onclose = function(){
|
||
self.onClose();
|
||
};
|
||
this.ws.onmessage = function(ev){
|
||
self.onData(ev.data);
|
||
};
|
||
this.ws.onerror = function(e){
|
||
self.onError('websocket error', e);
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Override `onData` to use a timer on iOS.
|
||
* See: https://gist.github.com/mloughran/2052006
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
if ('undefined' != typeof navigator
|
||
&& /iPad|iPhone|iPod/i.test(navigator.userAgent)) {
|
||
WS.prototype.onData = function(data){
|
||
var self = this;
|
||
setTimeout(function(){
|
||
Transport.prototype.onData.call(self, data);
|
||
}, 0);
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Writes data to socket.
|
||
*
|
||
* @param {Array} array of packets.
|
||
* @api private
|
||
*/
|
||
|
||
WS.prototype.write = function(packets){
|
||
var self = this;
|
||
this.writable = false;
|
||
|
||
// encodePacket efficient as it uses WS framing
|
||
// no need for encodePayload
|
||
var total = packets.length;
|
||
for (var i = 0, l = total; i < l; i++) {
|
||
(function(packet) {
|
||
parser.encodePacket(packet, self.supportsBinary, function(data) {
|
||
if (!BrowserWebSocket) {
|
||
// always create a new object (GH-437)
|
||
var opts = {};
|
||
if (packet.options) {
|
||
opts.compress = packet.options.compress;
|
||
}
|
||
|
||
if (self.perMessageDeflate) {
|
||
var len = 'string' == typeof data ? global.Buffer.byteLength(data) : data.length;
|
||
if (len < self.perMessageDeflate.threshold) {
|
||
opts.compress = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
//Sometimes the websocket has already been closed but the browser didn't
|
||
//have a chance of informing us about it yet, in that case send will
|
||
//throw an error
|
||
try {
|
||
if (BrowserWebSocket) {
|
||
// TypeError is thrown when passing the second argument on Safari
|
||
self.ws.send(data);
|
||
} else {
|
||
self.ws.send(data, opts);
|
||
}
|
||
} catch (e){
|
||
debug('websocket closed before onclose event');
|
||
}
|
||
|
||
--total || done();
|
||
});
|
||
})(packets[i]);
|
||
}
|
||
|
||
function done(){
|
||
self.emit('flush');
|
||
|
||
// fake drain
|
||
// defer to next tick to allow Socket to clear writeBuffer
|
||
setTimeout(function(){
|
||
self.writable = true;
|
||
self.emit('drain');
|
||
}, 0);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Called upon close
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
WS.prototype.onClose = function(){
|
||
Transport.prototype.onClose.call(this);
|
||
};
|
||
|
||
/**
|
||
* Closes socket.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
WS.prototype.doClose = function(){
|
||
if (typeof this.ws !== 'undefined') {
|
||
this.ws.close();
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Generates uri for connection.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
WS.prototype.uri = function(){
|
||
var query = this.query || {};
|
||
var schema = this.secure ? 'wss' : 'ws';
|
||
var port = '';
|
||
|
||
// avoid port if default for schema
|
||
if (this.port && (('wss' == schema && this.port != 443)
|
||
|| ('ws' == schema && this.port != 80))) {
|
||
port = ':' + this.port;
|
||
}
|
||
|
||
// append timestamp to URI
|
||
if (this.timestampRequests) {
|
||
query[this.timestampParam] = yeast();
|
||
}
|
||
|
||
// communicate binary support capabilities
|
||
if (!this.supportsBinary) {
|
||
query.b64 = 1;
|
||
}
|
||
|
||
query = parseqs.encode(query);
|
||
|
||
// prepend ? to query
|
||
if (query.length) {
|
||
query = '?' + query;
|
||
}
|
||
|
||
var ipv6 = this.hostname.indexOf(':') !== -1;
|
||
return schema + '://' + (ipv6 ? '[' + this.hostname + ']' : this.hostname) + port + this.path + query;
|
||
};
|
||
|
||
/**
|
||
* Feature detection for WebSocket.
|
||
*
|
||
* @return {Boolean} whether this transport is available.
|
||
* @api public
|
||
*/
|
||
|
||
WS.prototype.check = function(){
|
||
return !!WebSocket && !('__initialize' in WebSocket && this.name === WS.prototype.name);
|
||
};
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 107 */
|
||
/***/ function(module, exports) {
|
||
|
||
/* (ignored) */
|
||
|
||
/***/ },
|
||
/* 108 */
|
||
/***/ function(module, exports) {
|
||
|
||
|
||
var indexOf = [].indexOf;
|
||
|
||
module.exports = function(arr, obj){
|
||
if (indexOf) return arr.indexOf(obj);
|
||
for (var i = 0; i < arr.length; ++i) {
|
||
if (arr[i] === obj) return i;
|
||
}
|
||
return -1;
|
||
};
|
||
|
||
/***/ },
|
||
/* 109 */
|
||
/***/ function(module, exports) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(global) {/**
|
||
* JSON parse.
|
||
*
|
||
* @see Based on jQuery#parseJSON (MIT) and JSON2
|
||
* @api private
|
||
*/
|
||
|
||
var rvalidchars = /^[\],:{}\s]*$/;
|
||
var rvalidescape = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g;
|
||
var rvalidtokens = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g;
|
||
var rvalidbraces = /(?:^|:|,)(?:\s*\[)+/g;
|
||
var rtrimLeft = /^\s+/;
|
||
var rtrimRight = /\s+$/;
|
||
|
||
module.exports = function parsejson(data) {
|
||
if ('string' != typeof data || !data) {
|
||
return null;
|
||
}
|
||
|
||
data = data.replace(rtrimLeft, '').replace(rtrimRight, '');
|
||
|
||
// Attempt to parse using the native JSON parser first
|
||
if (global.JSON && JSON.parse) {
|
||
return JSON.parse(data);
|
||
}
|
||
|
||
if (rvalidchars.test(data.replace(rvalidescape, '@')
|
||
.replace(rvalidtokens, ']')
|
||
.replace(rvalidbraces, ''))) {
|
||
return (new Function('return ' + data))();
|
||
}
|
||
};
|
||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 110 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
|
||
/**
|
||
* Module dependencies.
|
||
*/
|
||
|
||
var parser = __webpack_require__(74);
|
||
var Emitter = __webpack_require__(111);
|
||
var toArray = __webpack_require__(112);
|
||
var on = __webpack_require__(113);
|
||
var bind = __webpack_require__(114);
|
||
var debug = __webpack_require__(71)('socket.io-client:socket');
|
||
var hasBin = __webpack_require__(115);
|
||
|
||
/**
|
||
* Module exports.
|
||
*/
|
||
|
||
module.exports = exports = Socket;
|
||
|
||
/**
|
||
* Internal events (blacklisted).
|
||
* These events can't be emitted by the user.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
var events = {
|
||
connect: 1,
|
||
connect_error: 1,
|
||
connect_timeout: 1,
|
||
connecting: 1,
|
||
disconnect: 1,
|
||
error: 1,
|
||
reconnect: 1,
|
||
reconnect_attempt: 1,
|
||
reconnect_failed: 1,
|
||
reconnect_error: 1,
|
||
reconnecting: 1,
|
||
ping: 1,
|
||
pong: 1
|
||
};
|
||
|
||
/**
|
||
* Shortcut to `Emitter#emit`.
|
||
*/
|
||
|
||
var emit = Emitter.prototype.emit;
|
||
|
||
/**
|
||
* `Socket` constructor.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
function Socket(io, nsp){
|
||
this.io = io;
|
||
this.nsp = nsp;
|
||
this.json = this; // compat
|
||
this.ids = 0;
|
||
this.acks = {};
|
||
this.receiveBuffer = [];
|
||
this.sendBuffer = [];
|
||
this.connected = false;
|
||
this.disconnected = true;
|
||
if (this.io.autoConnect) this.open();
|
||
}
|
||
|
||
/**
|
||
* Mix in `Emitter`.
|
||
*/
|
||
|
||
Emitter(Socket.prototype);
|
||
|
||
/**
|
||
* Subscribe to open, close and packet events
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.subEvents = function() {
|
||
if (this.subs) return;
|
||
|
||
var io = this.io;
|
||
this.subs = [
|
||
on(io, 'open', bind(this, 'onopen')),
|
||
on(io, 'packet', bind(this, 'onpacket')),
|
||
on(io, 'close', bind(this, 'onclose'))
|
||
];
|
||
};
|
||
|
||
/**
|
||
* "Opens" the socket.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
Socket.prototype.open =
|
||
Socket.prototype.connect = function(){
|
||
if (this.connected) return this;
|
||
|
||
this.subEvents();
|
||
this.io.open(); // ensure open
|
||
if ('open' == this.io.readyState) this.onopen();
|
||
this.emit('connecting');
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sends a `message` event.
|
||
*
|
||
* @return {Socket} self
|
||
* @api public
|
||
*/
|
||
|
||
Socket.prototype.send = function(){
|
||
var args = toArray(arguments);
|
||
args.unshift('message');
|
||
this.emit.apply(this, args);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Override `emit`.
|
||
* If the event is in `events`, it's emitted normally.
|
||
*
|
||
* @param {String} event name
|
||
* @return {Socket} self
|
||
* @api public
|
||
*/
|
||
|
||
Socket.prototype.emit = function(ev){
|
||
if (events.hasOwnProperty(ev)) {
|
||
emit.apply(this, arguments);
|
||
return this;
|
||
}
|
||
|
||
var args = toArray(arguments);
|
||
var parserType = parser.EVENT; // default
|
||
if (hasBin(args)) { parserType = parser.BINARY_EVENT; } // binary
|
||
var packet = { type: parserType, data: args };
|
||
|
||
packet.options = {};
|
||
packet.options.compress = !this.flags || false !== this.flags.compress;
|
||
|
||
// event ack callback
|
||
if ('function' == typeof args[args.length - 1]) {
|
||
debug('emitting packet with ack id %d', this.ids);
|
||
this.acks[this.ids] = args.pop();
|
||
packet.id = this.ids++;
|
||
}
|
||
|
||
if (this.connected) {
|
||
this.packet(packet);
|
||
} else {
|
||
this.sendBuffer.push(packet);
|
||
}
|
||
|
||
delete this.flags;
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sends a packet.
|
||
*
|
||
* @param {Object} packet
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.packet = function(packet){
|
||
packet.nsp = this.nsp;
|
||
this.io.packet(packet);
|
||
};
|
||
|
||
/**
|
||
* Called upon engine `open`.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.onopen = function(){
|
||
debug('transport is open - connecting');
|
||
|
||
// write connect packet if necessary
|
||
if ('/' != this.nsp) {
|
||
this.packet({ type: parser.CONNECT });
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Called upon engine `close`.
|
||
*
|
||
* @param {String} reason
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.onclose = function(reason){
|
||
debug('close (%s)', reason);
|
||
this.connected = false;
|
||
this.disconnected = true;
|
||
delete this.id;
|
||
this.emit('disconnect', reason);
|
||
};
|
||
|
||
/**
|
||
* Called with socket packet.
|
||
*
|
||
* @param {Object} packet
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.onpacket = function(packet){
|
||
if (packet.nsp != this.nsp) return;
|
||
|
||
switch (packet.type) {
|
||
case parser.CONNECT:
|
||
this.onconnect();
|
||
break;
|
||
|
||
case parser.EVENT:
|
||
this.onevent(packet);
|
||
break;
|
||
|
||
case parser.BINARY_EVENT:
|
||
this.onevent(packet);
|
||
break;
|
||
|
||
case parser.ACK:
|
||
this.onack(packet);
|
||
break;
|
||
|
||
case parser.BINARY_ACK:
|
||
this.onack(packet);
|
||
break;
|
||
|
||
case parser.DISCONNECT:
|
||
this.ondisconnect();
|
||
break;
|
||
|
||
case parser.ERROR:
|
||
this.emit('error', packet.data);
|
||
break;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Called upon a server event.
|
||
*
|
||
* @param {Object} packet
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.onevent = function(packet){
|
||
var args = packet.data || [];
|
||
debug('emitting event %j', args);
|
||
|
||
if (null != packet.id) {
|
||
debug('attaching ack callback to event');
|
||
args.push(this.ack(packet.id));
|
||
}
|
||
|
||
if (this.connected) {
|
||
emit.apply(this, args);
|
||
} else {
|
||
this.receiveBuffer.push(args);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Produces an ack callback to emit with an event.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.ack = function(id){
|
||
var self = this;
|
||
var sent = false;
|
||
return function(){
|
||
// prevent double callbacks
|
||
if (sent) return;
|
||
sent = true;
|
||
var args = toArray(arguments);
|
||
debug('sending ack %j', args);
|
||
|
||
var type = hasBin(args) ? parser.BINARY_ACK : parser.ACK;
|
||
self.packet({
|
||
type: type,
|
||
id: id,
|
||
data: args
|
||
});
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Called upon a server acknowlegement.
|
||
*
|
||
* @param {Object} packet
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.onack = function(packet){
|
||
var ack = this.acks[packet.id];
|
||
if ('function' == typeof ack) {
|
||
debug('calling ack %s with %j', packet.id, packet.data);
|
||
ack.apply(this, packet.data);
|
||
delete this.acks[packet.id];
|
||
} else {
|
||
debug('bad ack %s', packet.id);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Called upon server connect.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.onconnect = function(){
|
||
this.connected = true;
|
||
this.disconnected = false;
|
||
this.emit('connect');
|
||
this.emitBuffered();
|
||
};
|
||
|
||
/**
|
||
* Emit buffered events (received and emitted).
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.emitBuffered = function(){
|
||
var i;
|
||
for (i = 0; i < this.receiveBuffer.length; i++) {
|
||
emit.apply(this, this.receiveBuffer[i]);
|
||
}
|
||
this.receiveBuffer = [];
|
||
|
||
for (i = 0; i < this.sendBuffer.length; i++) {
|
||
this.packet(this.sendBuffer[i]);
|
||
}
|
||
this.sendBuffer = [];
|
||
};
|
||
|
||
/**
|
||
* Called upon server disconnect.
|
||
*
|
||
* @api private
|
||
*/
|
||
|
||
Socket.prototype.ondisconnect = function(){
|
||
debug('server disconnect (%s)', this.nsp);
|
||
this.destroy();
|
||
this.onclose('io server disconnect');
|
||
};
|
||
|
||
/**
|
||
* Called upon forced client/server side disconnections,
|
||
* this method ensures the manager stops tracking us and
|
||
* that reconnections don't get triggered for this.
|
||
*
|
||
* @api private.
|
||
*/
|
||
|
||
Socket.prototype.destroy = function(){
|
||
if (this.subs) {
|
||
// clean subscriptions to avoid reconnections
|
||
for (var i = 0; i < this.subs.length; i++) {
|
||
this.subs[i].destroy();
|
||
}
|
||
this.subs = null;
|
||
}
|
||
|
||
this.io.destroy(this);
|
||
};
|
||
|
||
/**
|
||
* Disconnects the socket manually.
|
||
*
|
||
* @return {Socket} self
|
||
* @api public
|
||
*/
|
||
|
||
Socket.prototype.close =
|
||
Socket.prototype.disconnect = function(){
|
||
if (this.connected) {
|
||
debug('performing disconnect (%s)', this.nsp);
|
||
this.packet({ type: parser.DISCONNECT });
|
||
}
|
||
|
||
// remove socket from pool
|
||
this.destroy();
|
||
|
||
if (this.connected) {
|
||
// fire events
|
||
this.onclose('io client disconnect');
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Sets the compress flag.
|
||
*
|
||
* @param {Boolean} if `true`, compresses the sending data
|
||
* @return {Socket} self
|
||
* @api public
|
||
*/
|
||
|
||
Socket.prototype.compress = function(compress){
|
||
this.flags = this.flags || {};
|
||
this.flags.compress = compress;
|
||
return this;
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 111 */
|
||
/***/ function(module, exports) {
|
||
|
||
|
||
/**
|
||
* Expose `Emitter`.
|
||
*/
|
||
|
||
module.exports = Emitter;
|
||
|
||
/**
|
||
* Initialize a new `Emitter`.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
function Emitter(obj) {
|
||
if (obj) return mixin(obj);
|
||
};
|
||
|
||
/**
|
||
* Mixin the emitter properties.
|
||
*
|
||
* @param {Object} obj
|
||
* @return {Object}
|
||
* @api private
|
||
*/
|
||
|
||
function mixin(obj) {
|
||
for (var key in Emitter.prototype) {
|
||
obj[key] = Emitter.prototype[key];
|
||
}
|
||
return obj;
|
||
}
|
||
|
||
/**
|
||
* Listen on the given `event` with `fn`.
|
||
*
|
||
* @param {String} event
|
||
* @param {Function} fn
|
||
* @return {Emitter}
|
||
* @api public
|
||
*/
|
||
|
||
Emitter.prototype.on =
|
||
Emitter.prototype.addEventListener = function(event, fn){
|
||
this._callbacks = this._callbacks || {};
|
||
(this._callbacks['$' + event] = this._callbacks['$' + event] || [])
|
||
.push(fn);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Adds an `event` listener that will be invoked a single
|
||
* time then automatically removed.
|
||
*
|
||
* @param {String} event
|
||
* @param {Function} fn
|
||
* @return {Emitter}
|
||
* @api public
|
||
*/
|
||
|
||
Emitter.prototype.once = function(event, fn){
|
||
function on() {
|
||
this.off(event, on);
|
||
fn.apply(this, arguments);
|
||
}
|
||
|
||
on.fn = fn;
|
||
this.on(event, on);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Remove the given callback for `event` or all
|
||
* registered callbacks.
|
||
*
|
||
* @param {String} event
|
||
* @param {Function} fn
|
||
* @return {Emitter}
|
||
* @api public
|
||
*/
|
||
|
||
Emitter.prototype.off =
|
||
Emitter.prototype.removeListener =
|
||
Emitter.prototype.removeAllListeners =
|
||
Emitter.prototype.removeEventListener = function(event, fn){
|
||
this._callbacks = this._callbacks || {};
|
||
|
||
// all
|
||
if (0 == arguments.length) {
|
||
this._callbacks = {};
|
||
return this;
|
||
}
|
||
|
||
// specific event
|
||
var callbacks = this._callbacks['$' + event];
|
||
if (!callbacks) return this;
|
||
|
||
// remove all handlers
|
||
if (1 == arguments.length) {
|
||
delete this._callbacks['$' + event];
|
||
return this;
|
||
}
|
||
|
||
// remove specific handler
|
||
var cb;
|
||
for (var i = 0; i < callbacks.length; i++) {
|
||
cb = callbacks[i];
|
||
if (cb === fn || cb.fn === fn) {
|
||
callbacks.splice(i, 1);
|
||
break;
|
||
}
|
||
}
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Emit `event` with the given args.
|
||
*
|
||
* @param {String} event
|
||
* @param {Mixed} ...
|
||
* @return {Emitter}
|
||
*/
|
||
|
||
Emitter.prototype.emit = function(event){
|
||
this._callbacks = this._callbacks || {};
|
||
var args = [].slice.call(arguments, 1)
|
||
, callbacks = this._callbacks['$' + event];
|
||
|
||
if (callbacks) {
|
||
callbacks = callbacks.slice(0);
|
||
for (var i = 0, len = callbacks.length; i < len; ++i) {
|
||
callbacks[i].apply(this, args);
|
||
}
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Return array of callbacks for `event`.
|
||
*
|
||
* @param {String} event
|
||
* @return {Array}
|
||
* @api public
|
||
*/
|
||
|
||
Emitter.prototype.listeners = function(event){
|
||
this._callbacks = this._callbacks || {};
|
||
return this._callbacks['$' + event] || [];
|
||
};
|
||
|
||
/**
|
||
* Check if this emitter has `event` handlers.
|
||
*
|
||
* @param {String} event
|
||
* @return {Boolean}
|
||
* @api public
|
||
*/
|
||
|
||
Emitter.prototype.hasListeners = function(event){
|
||
return !! this.listeners(event).length;
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 112 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = toArray
|
||
|
||
function toArray(list, index) {
|
||
var array = []
|
||
|
||
index = index || 0
|
||
|
||
for (var i = index || 0; i < list.length; i++) {
|
||
array[i - index] = list[i]
|
||
}
|
||
|
||
return array
|
||
}
|
||
|
||
|
||
/***/ },
|
||
/* 113 */
|
||
/***/ function(module, exports) {
|
||
|
||
|
||
/**
|
||
* Module exports.
|
||
*/
|
||
|
||
module.exports = on;
|
||
|
||
/**
|
||
* Helper for subscriptions.
|
||
*
|
||
* @param {Object|EventEmitter} obj with `Emitter` mixin or `EventEmitter`
|
||
* @param {String} event name
|
||
* @param {Function} callback
|
||
* @api public
|
||
*/
|
||
|
||
function on(obj, ev, fn) {
|
||
obj.on(ev, fn);
|
||
return {
|
||
destroy: function(){
|
||
obj.removeListener(ev, fn);
|
||
}
|
||
};
|
||
}
|
||
|
||
|
||
/***/ },
|
||
/* 114 */
|
||
/***/ function(module, exports) {
|
||
|
||
/**
|
||
* Slice reference.
|
||
*/
|
||
|
||
var slice = [].slice;
|
||
|
||
/**
|
||
* Bind `obj` to `fn`.
|
||
*
|
||
* @param {Object} obj
|
||
* @param {Function|String} fn or string
|
||
* @return {Function}
|
||
* @api public
|
||
*/
|
||
|
||
module.exports = function(obj, fn){
|
||
if ('string' == typeof fn) fn = obj[fn];
|
||
if ('function' != typeof fn) throw new Error('bind() requires a function');
|
||
var args = slice.call(arguments, 2);
|
||
return function(){
|
||
return fn.apply(obj, args.concat(slice.call(arguments)));
|
||
}
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 115 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(global) {
|
||
/*
|
||
* Module requirements.
|
||
*/
|
||
|
||
var isArray = __webpack_require__(116);
|
||
|
||
/**
|
||
* Module exports.
|
||
*/
|
||
|
||
module.exports = hasBinary;
|
||
|
||
/**
|
||
* Checks for binary data.
|
||
*
|
||
* Right now only Buffer and ArrayBuffer are supported..
|
||
*
|
||
* @param {Object} anything
|
||
* @api public
|
||
*/
|
||
|
||
function hasBinary(data) {
|
||
|
||
function _hasBinary(obj) {
|
||
if (!obj) return false;
|
||
|
||
if ( (global.Buffer && global.Buffer.isBuffer && global.Buffer.isBuffer(obj)) ||
|
||
(global.ArrayBuffer && obj instanceof ArrayBuffer) ||
|
||
(global.Blob && obj instanceof Blob) ||
|
||
(global.File && obj instanceof File)
|
||
) {
|
||
return true;
|
||
}
|
||
|
||
if (isArray(obj)) {
|
||
for (var i = 0; i < obj.length; i++) {
|
||
if (_hasBinary(obj[i])) {
|
||
return true;
|
||
}
|
||
}
|
||
} else if (obj && 'object' == typeof obj) {
|
||
// see: https://github.com/Automattic/has-binary/pull/4
|
||
if (obj.toJSON && 'function' == typeof obj.toJSON) {
|
||
obj = obj.toJSON();
|
||
}
|
||
|
||
for (var key in obj) {
|
||
if (Object.prototype.hasOwnProperty.call(obj, key) && _hasBinary(obj[key])) {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
return _hasBinary(data);
|
||
}
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 116 */
|
||
/***/ function(module, exports) {
|
||
|
||
module.exports = Array.isArray || function (arr) {
|
||
return Object.prototype.toString.call(arr) == '[object Array]';
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 117 */
|
||
/***/ function(module, exports) {
|
||
|
||
|
||
/**
|
||
* Expose `Backoff`.
|
||
*/
|
||
|
||
module.exports = Backoff;
|
||
|
||
/**
|
||
* Initialize backoff timer with `opts`.
|
||
*
|
||
* - `min` initial timeout in milliseconds [100]
|
||
* - `max` max timeout [10000]
|
||
* - `jitter` [0]
|
||
* - `factor` [2]
|
||
*
|
||
* @param {Object} opts
|
||
* @api public
|
||
*/
|
||
|
||
function Backoff(opts) {
|
||
opts = opts || {};
|
||
this.ms = opts.min || 100;
|
||
this.max = opts.max || 10000;
|
||
this.factor = opts.factor || 2;
|
||
this.jitter = opts.jitter > 0 && opts.jitter <= 1 ? opts.jitter : 0;
|
||
this.attempts = 0;
|
||
}
|
||
|
||
/**
|
||
* Return the backoff duration.
|
||
*
|
||
* @return {Number}
|
||
* @api public
|
||
*/
|
||
|
||
Backoff.prototype.duration = function(){
|
||
var ms = this.ms * Math.pow(this.factor, this.attempts++);
|
||
if (this.jitter) {
|
||
var rand = Math.random();
|
||
var deviation = Math.floor(rand * this.jitter * ms);
|
||
ms = (Math.floor(rand * 10) & 1) == 0 ? ms - deviation : ms + deviation;
|
||
}
|
||
return Math.min(ms, this.max) | 0;
|
||
};
|
||
|
||
/**
|
||
* Reset the number of attempts.
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
Backoff.prototype.reset = function(){
|
||
this.attempts = 0;
|
||
};
|
||
|
||
/**
|
||
* Set the minimum duration
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
Backoff.prototype.setMin = function(min){
|
||
this.ms = min;
|
||
};
|
||
|
||
/**
|
||
* Set the maximum duration
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
Backoff.prototype.setMax = function(max){
|
||
this.max = max;
|
||
};
|
||
|
||
/**
|
||
* Set the jitter
|
||
*
|
||
* @api public
|
||
*/
|
||
|
||
Backoff.prototype.setJitter = function(jitter){
|
||
this.jitter = jitter;
|
||
};
|
||
|
||
|
||
|
||
/***/ },
|
||
/* 118 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _getPrototypeOf = __webpack_require__(119);
|
||
|
||
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _createClass2 = __webpack_require__(57);
|
||
|
||
var _createClass3 = _interopRequireDefault(_createClass2);
|
||
|
||
var _possibleConstructorReturn2 = __webpack_require__(124);
|
||
|
||
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
|
||
|
||
var _get2 = __webpack_require__(133);
|
||
|
||
var _get3 = _interopRequireDefault(_get2);
|
||
|
||
var _inherits2 = __webpack_require__(137);
|
||
|
||
var _inherits3 = _interopRequireDefault(_inherits2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var Store = __webpack_require__(143);
|
||
var CounterIndex = __webpack_require__(171);
|
||
var OpTypes = __webpack_require__(160).Types;
|
||
|
||
var CounterStore = function (_Store) {
|
||
(0, _inherits3.default)(CounterStore, _Store);
|
||
|
||
function CounterStore(ipfs, options) {
|
||
(0, _classCallCheck3.default)(this, CounterStore);
|
||
|
||
var _this = (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(CounterStore).call(this, ipfs, options));
|
||
|
||
_this._index = new CounterIndex();
|
||
return _this;
|
||
}
|
||
|
||
(0, _createClass3.default)(CounterStore, [{
|
||
key: 'use',
|
||
value: function use(dbname, id) {
|
||
this._index.createCounter(dbname, id);
|
||
return (0, _get3.default)((0, _getPrototypeOf2.default)(CounterStore.prototype), 'use', this).call(this, dbname, id);
|
||
}
|
||
}, {
|
||
key: 'delete',
|
||
value: function _delete(dbname) {
|
||
(0, _get3.default)((0, _getPrototypeOf2.default)(CounterStore.prototype), 'delete', this).call(this, dbname);
|
||
this._index = new CounterIndex();
|
||
}
|
||
}, {
|
||
key: 'query',
|
||
value: function query(dbname) {
|
||
return this._index.get(dbname).value;
|
||
}
|
||
}, {
|
||
key: 'inc',
|
||
value: function inc(dbname, amount) {
|
||
var counter = this._index.get(dbname);
|
||
if (counter) {
|
||
counter.increment(amount);
|
||
return this._addOperation(dbname, OpTypes.Inc, null, counter.payload);
|
||
}
|
||
}
|
||
}]);
|
||
return CounterStore;
|
||
}(Store);
|
||
|
||
module.exports = CounterStore;
|
||
|
||
/***/ },
|
||
/* 119 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = { "default": __webpack_require__(120), __esModule: true };
|
||
|
||
/***/ },
|
||
/* 120 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
__webpack_require__(121);
|
||
module.exports = __webpack_require__(12).Object.getPrototypeOf;
|
||
|
||
/***/ },
|
||
/* 121 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// 19.1.2.9 Object.getPrototypeOf(O)
|
||
var toObject = __webpack_require__(122);
|
||
|
||
__webpack_require__(123)('getPrototypeOf', function($getPrototypeOf){
|
||
return function getPrototypeOf(it){
|
||
return $getPrototypeOf(toObject(it));
|
||
};
|
||
});
|
||
|
||
/***/ },
|
||
/* 122 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// 7.1.13 ToObject(argument)
|
||
var defined = __webpack_require__(7);
|
||
module.exports = function(it){
|
||
return Object(defined(it));
|
||
};
|
||
|
||
/***/ },
|
||
/* 123 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// most Object methods by ES6 should accept primitives
|
||
var $export = __webpack_require__(10)
|
||
, core = __webpack_require__(12)
|
||
, fails = __webpack_require__(20);
|
||
module.exports = function(KEY, exec){
|
||
var fn = (core.Object || {})[KEY] || Object[KEY]
|
||
, exp = {};
|
||
exp[KEY] = exec(fn);
|
||
$export($export.S + $export.F * fails(function(){ fn(1); }), 'Object', exp);
|
||
};
|
||
|
||
/***/ },
|
||
/* 124 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
exports.__esModule = true;
|
||
|
||
var _typeof2 = __webpack_require__(125);
|
||
|
||
var _typeof3 = _interopRequireDefault(_typeof2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
exports.default = function (self, call) {
|
||
if (!self) {
|
||
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
||
}
|
||
|
||
return call && ((typeof call === "undefined" ? "undefined" : (0, _typeof3.default)(call)) === "object" || typeof call === "function") ? call : self;
|
||
};
|
||
|
||
/***/ },
|
||
/* 125 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
var _Symbol = __webpack_require__(126)["default"];
|
||
|
||
exports["default"] = function (obj) {
|
||
return obj && obj.constructor === _Symbol ? "symbol" : typeof obj;
|
||
};
|
||
|
||
exports.__esModule = true;
|
||
|
||
/***/ },
|
||
/* 126 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = { "default": __webpack_require__(127), __esModule: true };
|
||
|
||
/***/ },
|
||
/* 127 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
__webpack_require__(128);
|
||
__webpack_require__(3);
|
||
module.exports = __webpack_require__(12).Symbol;
|
||
|
||
/***/ },
|
||
/* 128 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
// ECMAScript 6 symbols shim
|
||
var $ = __webpack_require__(17)
|
||
, global = __webpack_require__(11)
|
||
, has = __webpack_require__(21)
|
||
, DESCRIPTORS = __webpack_require__(19)
|
||
, $export = __webpack_require__(10)
|
||
, redefine = __webpack_require__(15)
|
||
, $fails = __webpack_require__(20)
|
||
, shared = __webpack_require__(26)
|
||
, setToStringTag = __webpack_require__(24)
|
||
, uid = __webpack_require__(27)
|
||
, wks = __webpack_require__(25)
|
||
, keyOf = __webpack_require__(129)
|
||
, $names = __webpack_require__(130)
|
||
, enumKeys = __webpack_require__(131)
|
||
, isArray = __webpack_require__(132)
|
||
, anObject = __webpack_require__(38)
|
||
, toIObject = __webpack_require__(32)
|
||
, createDesc = __webpack_require__(18)
|
||
, getDesc = $.getDesc
|
||
, setDesc = $.setDesc
|
||
, _create = $.create
|
||
, getNames = $names.get
|
||
, $Symbol = global.Symbol
|
||
, $JSON = global.JSON
|
||
, _stringify = $JSON && $JSON.stringify
|
||
, setter = false
|
||
, HIDDEN = wks('_hidden')
|
||
, isEnum = $.isEnum
|
||
, SymbolRegistry = shared('symbol-registry')
|
||
, AllSymbols = shared('symbols')
|
||
, useNative = typeof $Symbol == 'function'
|
||
, ObjectProto = Object.prototype;
|
||
|
||
// fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687
|
||
var setSymbolDesc = DESCRIPTORS && $fails(function(){
|
||
return _create(setDesc({}, 'a', {
|
||
get: function(){ return setDesc(this, 'a', {value: 7}).a; }
|
||
})).a != 7;
|
||
}) ? function(it, key, D){
|
||
var protoDesc = getDesc(ObjectProto, key);
|
||
if(protoDesc)delete ObjectProto[key];
|
||
setDesc(it, key, D);
|
||
if(protoDesc && it !== ObjectProto)setDesc(ObjectProto, key, protoDesc);
|
||
} : setDesc;
|
||
|
||
var wrap = function(tag){
|
||
var sym = AllSymbols[tag] = _create($Symbol.prototype);
|
||
sym._k = tag;
|
||
DESCRIPTORS && setter && setSymbolDesc(ObjectProto, tag, {
|
||
configurable: true,
|
||
set: function(value){
|
||
if(has(this, HIDDEN) && has(this[HIDDEN], tag))this[HIDDEN][tag] = false;
|
||
setSymbolDesc(this, tag, createDesc(1, value));
|
||
}
|
||
});
|
||
return sym;
|
||
};
|
||
|
||
var isSymbol = function(it){
|
||
return typeof it == 'symbol';
|
||
};
|
||
|
||
var $defineProperty = function defineProperty(it, key, D){
|
||
if(D && has(AllSymbols, key)){
|
||
if(!D.enumerable){
|
||
if(!has(it, HIDDEN))setDesc(it, HIDDEN, createDesc(1, {}));
|
||
it[HIDDEN][key] = true;
|
||
} else {
|
||
if(has(it, HIDDEN) && it[HIDDEN][key])it[HIDDEN][key] = false;
|
||
D = _create(D, {enumerable: createDesc(0, false)});
|
||
} return setSymbolDesc(it, key, D);
|
||
} return setDesc(it, key, D);
|
||
};
|
||
var $defineProperties = function defineProperties(it, P){
|
||
anObject(it);
|
||
var keys = enumKeys(P = toIObject(P))
|
||
, i = 0
|
||
, l = keys.length
|
||
, key;
|
||
while(l > i)$defineProperty(it, key = keys[i++], P[key]);
|
||
return it;
|
||
};
|
||
var $create = function create(it, P){
|
||
return P === undefined ? _create(it) : $defineProperties(_create(it), P);
|
||
};
|
||
var $propertyIsEnumerable = function propertyIsEnumerable(key){
|
||
var E = isEnum.call(this, key);
|
||
return E || !has(this, key) || !has(AllSymbols, key) || has(this, HIDDEN) && this[HIDDEN][key]
|
||
? E : true;
|
||
};
|
||
var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(it, key){
|
||
var D = getDesc(it = toIObject(it), key);
|
||
if(D && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key]))D.enumerable = true;
|
||
return D;
|
||
};
|
||
var $getOwnPropertyNames = function getOwnPropertyNames(it){
|
||
var names = getNames(toIObject(it))
|
||
, result = []
|
||
, i = 0
|
||
, key;
|
||
while(names.length > i)if(!has(AllSymbols, key = names[i++]) && key != HIDDEN)result.push(key);
|
||
return result;
|
||
};
|
||
var $getOwnPropertySymbols = function getOwnPropertySymbols(it){
|
||
var names = getNames(toIObject(it))
|
||
, result = []
|
||
, i = 0
|
||
, key;
|
||
while(names.length > i)if(has(AllSymbols, key = names[i++]))result.push(AllSymbols[key]);
|
||
return result;
|
||
};
|
||
var $stringify = function stringify(it){
|
||
if(it === undefined || isSymbol(it))return; // IE8 returns string on undefined
|
||
var args = [it]
|
||
, i = 1
|
||
, $$ = arguments
|
||
, replacer, $replacer;
|
||
while($$.length > i)args.push($$[i++]);
|
||
replacer = args[1];
|
||
if(typeof replacer == 'function')$replacer = replacer;
|
||
if($replacer || !isArray(replacer))replacer = function(key, value){
|
||
if($replacer)value = $replacer.call(this, key, value);
|
||
if(!isSymbol(value))return value;
|
||
};
|
||
args[1] = replacer;
|
||
return _stringify.apply($JSON, args);
|
||
};
|
||
var buggyJSON = $fails(function(){
|
||
var S = $Symbol();
|
||
// MS Edge converts symbol values to JSON as {}
|
||
// WebKit converts symbol values to JSON as null
|
||
// V8 throws on boxed symbols
|
||
return _stringify([S]) != '[null]' || _stringify({a: S}) != '{}' || _stringify(Object(S)) != '{}';
|
||
});
|
||
|
||
// 19.4.1.1 Symbol([description])
|
||
if(!useNative){
|
||
$Symbol = function Symbol(){
|
||
if(isSymbol(this))throw TypeError('Symbol is not a constructor');
|
||
return wrap(uid(arguments.length > 0 ? arguments[0] : undefined));
|
||
};
|
||
redefine($Symbol.prototype, 'toString', function toString(){
|
||
return this._k;
|
||
});
|
||
|
||
isSymbol = function(it){
|
||
return it instanceof $Symbol;
|
||
};
|
||
|
||
$.create = $create;
|
||
$.isEnum = $propertyIsEnumerable;
|
||
$.getDesc = $getOwnPropertyDescriptor;
|
||
$.setDesc = $defineProperty;
|
||
$.setDescs = $defineProperties;
|
||
$.getNames = $names.get = $getOwnPropertyNames;
|
||
$.getSymbols = $getOwnPropertySymbols;
|
||
|
||
if(DESCRIPTORS && !__webpack_require__(9)){
|
||
redefine(ObjectProto, 'propertyIsEnumerable', $propertyIsEnumerable, true);
|
||
}
|
||
}
|
||
|
||
var symbolStatics = {
|
||
// 19.4.2.1 Symbol.for(key)
|
||
'for': function(key){
|
||
return has(SymbolRegistry, key += '')
|
||
? SymbolRegistry[key]
|
||
: SymbolRegistry[key] = $Symbol(key);
|
||
},
|
||
// 19.4.2.5 Symbol.keyFor(sym)
|
||
keyFor: function keyFor(key){
|
||
return keyOf(SymbolRegistry, key);
|
||
},
|
||
useSetter: function(){ setter = true; },
|
||
useSimple: function(){ setter = false; }
|
||
};
|
||
// 19.4.2.2 Symbol.hasInstance
|
||
// 19.4.2.3 Symbol.isConcatSpreadable
|
||
// 19.4.2.4 Symbol.iterator
|
||
// 19.4.2.6 Symbol.match
|
||
// 19.4.2.8 Symbol.replace
|
||
// 19.4.2.9 Symbol.search
|
||
// 19.4.2.10 Symbol.species
|
||
// 19.4.2.11 Symbol.split
|
||
// 19.4.2.12 Symbol.toPrimitive
|
||
// 19.4.2.13 Symbol.toStringTag
|
||
// 19.4.2.14 Symbol.unscopables
|
||
$.each.call((
|
||
'hasInstance,isConcatSpreadable,iterator,match,replace,search,' +
|
||
'species,split,toPrimitive,toStringTag,unscopables'
|
||
).split(','), function(it){
|
||
var sym = wks(it);
|
||
symbolStatics[it] = useNative ? sym : wrap(sym);
|
||
});
|
||
|
||
setter = true;
|
||
|
||
$export($export.G + $export.W, {Symbol: $Symbol});
|
||
|
||
$export($export.S, 'Symbol', symbolStatics);
|
||
|
||
$export($export.S + $export.F * !useNative, 'Object', {
|
||
// 19.1.2.2 Object.create(O [, Properties])
|
||
create: $create,
|
||
// 19.1.2.4 Object.defineProperty(O, P, Attributes)
|
||
defineProperty: $defineProperty,
|
||
// 19.1.2.3 Object.defineProperties(O, Properties)
|
||
defineProperties: $defineProperties,
|
||
// 19.1.2.6 Object.getOwnPropertyDescriptor(O, P)
|
||
getOwnPropertyDescriptor: $getOwnPropertyDescriptor,
|
||
// 19.1.2.7 Object.getOwnPropertyNames(O)
|
||
getOwnPropertyNames: $getOwnPropertyNames,
|
||
// 19.1.2.8 Object.getOwnPropertySymbols(O)
|
||
getOwnPropertySymbols: $getOwnPropertySymbols
|
||
});
|
||
|
||
// 24.3.2 JSON.stringify(value [, replacer [, space]])
|
||
$JSON && $export($export.S + $export.F * (!useNative || buggyJSON), 'JSON', {stringify: $stringify});
|
||
|
||
// 19.4.3.5 Symbol.prototype[@@toStringTag]
|
||
setToStringTag($Symbol, 'Symbol');
|
||
// 20.2.1.9 Math[@@toStringTag]
|
||
setToStringTag(Math, 'Math', true);
|
||
// 24.3.3 JSON[@@toStringTag]
|
||
setToStringTag(global.JSON, 'JSON', true);
|
||
|
||
/***/ },
|
||
/* 129 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var $ = __webpack_require__(17)
|
||
, toIObject = __webpack_require__(32);
|
||
module.exports = function(object, el){
|
||
var O = toIObject(object)
|
||
, keys = $.getKeys(O)
|
||
, length = keys.length
|
||
, index = 0
|
||
, key;
|
||
while(length > index)if(O[key = keys[index++]] === el)return key;
|
||
};
|
||
|
||
/***/ },
|
||
/* 130 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window
|
||
var toIObject = __webpack_require__(32)
|
||
, getNames = __webpack_require__(17).getNames
|
||
, toString = {}.toString;
|
||
|
||
var windowNames = typeof window == 'object' && Object.getOwnPropertyNames
|
||
? Object.getOwnPropertyNames(window) : [];
|
||
|
||
var getWindowNames = function(it){
|
||
try {
|
||
return getNames(it);
|
||
} catch(e){
|
||
return windowNames.slice();
|
||
}
|
||
};
|
||
|
||
module.exports.get = function getOwnPropertyNames(it){
|
||
if(windowNames && toString.call(it) == '[object Window]')return getWindowNames(it);
|
||
return getNames(toIObject(it));
|
||
};
|
||
|
||
/***/ },
|
||
/* 131 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// all enumerable object keys, includes symbols
|
||
var $ = __webpack_require__(17);
|
||
module.exports = function(it){
|
||
var keys = $.getKeys(it)
|
||
, getSymbols = $.getSymbols;
|
||
if(getSymbols){
|
||
var symbols = getSymbols(it)
|
||
, isEnum = $.isEnum
|
||
, i = 0
|
||
, key;
|
||
while(symbols.length > i)if(isEnum.call(it, key = symbols[i++]))keys.push(key);
|
||
}
|
||
return keys;
|
||
};
|
||
|
||
/***/ },
|
||
/* 132 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// 7.2.2 IsArray(argument)
|
||
var cof = __webpack_require__(34);
|
||
module.exports = Array.isArray || function(arg){
|
||
return cof(arg) == 'Array';
|
||
};
|
||
|
||
/***/ },
|
||
/* 133 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
var _Object$getOwnPropertyDescriptor = __webpack_require__(134)["default"];
|
||
|
||
exports["default"] = function get(_x, _x2, _x3) {
|
||
var _again = true;
|
||
|
||
_function: while (_again) {
|
||
var object = _x,
|
||
property = _x2,
|
||
receiver = _x3;
|
||
_again = false;
|
||
if (object === null) object = Function.prototype;
|
||
|
||
var desc = _Object$getOwnPropertyDescriptor(object, property);
|
||
|
||
if (desc === undefined) {
|
||
var parent = Object.getPrototypeOf(object);
|
||
|
||
if (parent === null) {
|
||
return undefined;
|
||
} else {
|
||
_x = parent;
|
||
_x2 = property;
|
||
_x3 = receiver;
|
||
_again = true;
|
||
desc = parent = undefined;
|
||
continue _function;
|
||
}
|
||
} else if ("value" in desc) {
|
||
return desc.value;
|
||
} else {
|
||
var getter = desc.get;
|
||
|
||
if (getter === undefined) {
|
||
return undefined;
|
||
}
|
||
|
||
return getter.call(receiver);
|
||
}
|
||
}
|
||
};
|
||
|
||
exports.__esModule = true;
|
||
|
||
/***/ },
|
||
/* 134 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = { "default": __webpack_require__(135), __esModule: true };
|
||
|
||
/***/ },
|
||
/* 135 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var $ = __webpack_require__(17);
|
||
__webpack_require__(136);
|
||
module.exports = function getOwnPropertyDescriptor(it, key){
|
||
return $.getDesc(it, key);
|
||
};
|
||
|
||
/***/ },
|
||
/* 136 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// 19.1.2.6 Object.getOwnPropertyDescriptor(O, P)
|
||
var toIObject = __webpack_require__(32);
|
||
|
||
__webpack_require__(123)('getOwnPropertyDescriptor', function($getOwnPropertyDescriptor){
|
||
return function getOwnPropertyDescriptor(it, key){
|
||
return $getOwnPropertyDescriptor(toIObject(it), key);
|
||
};
|
||
});
|
||
|
||
/***/ },
|
||
/* 137 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
var _Object$create = __webpack_require__(138)["default"];
|
||
|
||
var _Object$setPrototypeOf = __webpack_require__(140)["default"];
|
||
|
||
exports["default"] = function (subClass, superClass) {
|
||
if (typeof superClass !== "function" && superClass !== null) {
|
||
throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
|
||
}
|
||
|
||
subClass.prototype = _Object$create(superClass && superClass.prototype, {
|
||
constructor: {
|
||
value: subClass,
|
||
enumerable: false,
|
||
writable: true,
|
||
configurable: true
|
||
}
|
||
});
|
||
if (superClass) _Object$setPrototypeOf ? _Object$setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
|
||
};
|
||
|
||
exports.__esModule = true;
|
||
|
||
/***/ },
|
||
/* 138 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = { "default": __webpack_require__(139), __esModule: true };
|
||
|
||
/***/ },
|
||
/* 139 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var $ = __webpack_require__(17);
|
||
module.exports = function create(P, D){
|
||
return $.create(P, D);
|
||
};
|
||
|
||
/***/ },
|
||
/* 140 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = { "default": __webpack_require__(141), __esModule: true };
|
||
|
||
/***/ },
|
||
/* 141 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
__webpack_require__(142);
|
||
module.exports = __webpack_require__(12).Object.setPrototypeOf;
|
||
|
||
/***/ },
|
||
/* 142 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// 19.1.3.19 Object.setPrototypeOf(O, proto)
|
||
var $export = __webpack_require__(10);
|
||
$export($export.S, 'Object', {setPrototypeOf: __webpack_require__(45).set});
|
||
|
||
/***/ },
|
||
/* 143 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _promise = __webpack_require__(1);
|
||
|
||
var _promise2 = _interopRequireDefault(_promise);
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _createClass2 = __webpack_require__(57);
|
||
|
||
var _createClass3 = _interopRequireDefault(_createClass2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var EventEmitter = __webpack_require__(60).EventEmitter;
|
||
var OperationsLog = __webpack_require__(144);
|
||
var DefaultIndex = __webpack_require__(170);
|
||
|
||
var Store = function () {
|
||
function Store(ipfs, options) {
|
||
(0, _classCallCheck3.default)(this, Store);
|
||
|
||
this._ipfs = ipfs;
|
||
this._index = new DefaultIndex();
|
||
this._oplogs = {};
|
||
this.events = {};
|
||
this.options = options || {};
|
||
}
|
||
|
||
(0, _createClass3.default)(Store, [{
|
||
key: 'use',
|
||
value: function use(dbname, id) {
|
||
var _this = this;
|
||
|
||
this.events[dbname] = new EventEmitter();
|
||
var oplog = new OperationsLog(this._ipfs, dbname, this.events[dbname], this.options);
|
||
return oplog.create(id).then(function () {
|
||
return _this._oplogs[dbname] = oplog;
|
||
}).then(function () {
|
||
return _this._index.updateIndex(oplog);
|
||
}).then(function () {
|
||
return _this.events[dbname];
|
||
});
|
||
}
|
||
}, {
|
||
key: 'sync',
|
||
value: function sync(dbname, hash) {
|
||
var _this2 = this;
|
||
|
||
var oplog = this._oplogs[dbname];
|
||
if (hash && oplog) {
|
||
return oplog.merge(hash).then(function () {
|
||
return _this2._index.updateIndex(oplog);
|
||
}).then(function () {
|
||
return _this2;
|
||
});
|
||
}
|
||
|
||
return _promise2.default.resolve(this);
|
||
}
|
||
}, {
|
||
key: 'delete',
|
||
value: function _delete(dbname) {
|
||
if (this._oplogs[dbname]) this._oplogs[dbname].delete();
|
||
}
|
||
}, {
|
||
key: '_addOperation',
|
||
value: function _addOperation(dbname, type, key, data) {
|
||
var _this3 = this;
|
||
|
||
var oplog = this._oplogs[dbname];
|
||
var result = void 0;
|
||
if (oplog) {
|
||
return oplog.addOperation(type, key, data).then(function (op) {
|
||
return result = op;
|
||
}).then(function () {
|
||
return _this3._index.updateIndex(oplog);
|
||
}).then(function () {
|
||
return result;
|
||
});
|
||
}
|
||
}
|
||
}]);
|
||
return Store;
|
||
}();
|
||
|
||
module.exports = Store;
|
||
|
||
/***/ },
|
||
/* 144 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _assign = __webpack_require__(145);
|
||
|
||
var _assign2 = _interopRequireDefault(_assign);
|
||
|
||
var _promise = __webpack_require__(1);
|
||
|
||
var _promise2 = _interopRequireDefault(_promise);
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _createClass2 = __webpack_require__(57);
|
||
|
||
var _createClass3 = _interopRequireDefault(_createClass2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var Log = __webpack_require__(149);
|
||
var Cache = __webpack_require__(159);
|
||
var DBOperation = __webpack_require__(160);
|
||
|
||
var OperationsLog = function () {
|
||
function OperationsLog(ipfs, dbname, events, opts) {
|
||
(0, _classCallCheck3.default)(this, OperationsLog);
|
||
|
||
this.dbname = dbname;
|
||
this.options = opts || { cacheFile: null };
|
||
this.id = null;
|
||
this.lastWrite = null;
|
||
this._ipfs = ipfs;
|
||
this._log = null;
|
||
this._cached = {};
|
||
this.events = events;
|
||
}
|
||
|
||
(0, _createClass3.default)(OperationsLog, [{
|
||
key: 'create',
|
||
value: function create(id) {
|
||
var _this = this;
|
||
|
||
this.events.emit('load', this.dbname);
|
||
this.id = id;
|
||
return Log.create(this._ipfs, id).then(function (log) {
|
||
return _this._log = log;
|
||
}).then(function () {
|
||
return Cache.loadCache(_this.options.cacheFile);
|
||
}).then(function () {
|
||
return _this.merge(Cache.get(_this.dbname));
|
||
}).then(function () {
|
||
return _this;
|
||
});
|
||
}
|
||
}, {
|
||
key: 'delete',
|
||
value: function _delete() {
|
||
this._log.clear();
|
||
}
|
||
}, {
|
||
key: 'merge',
|
||
value: function merge(hash) {
|
||
var _this2 = this;
|
||
|
||
if (!hash || hash === this.lastWrite || !this._log) return _promise2.default.resolve();
|
||
|
||
this.events.emit('load', this.dbname);
|
||
var oldCount = this._log.items.length;
|
||
|
||
return Log.fromIpfsHash(this._ipfs, hash).then(function (other) {
|
||
return _this2._log.join(other);
|
||
}).then(function (merged) {
|
||
if (_this2._log.items.length - oldCount === 0) return;
|
||
|
||
return _this2._cacheInMemory(_this2._log);
|
||
}).then(function () {
|
||
Cache.set(_this2.dbname, hash);
|
||
_this2.events.emit('readable', _this2.dbname, hash);
|
||
return _this2;
|
||
});
|
||
}
|
||
}, {
|
||
key: 'addOperation',
|
||
value: function addOperation(operation, key, value) {
|
||
var _this3 = this;
|
||
|
||
var post = void 0;
|
||
return DBOperation.create(this._ipfs, operation, key, value).then(function (result) {
|
||
return _this3._log.add(result.Hash).then(function (node) {
|
||
return { node: node, op: result.Post };
|
||
});
|
||
}).then(function (result) {
|
||
_this3._cachePayload(result.node.payload, result.op);
|
||
return result;
|
||
}).then(function (result) {
|
||
return Log.getIpfsHash(_this3._ipfs, _this3._log).then(function (hash) {
|
||
_this3.lastWrite = hash;
|
||
Cache.set(_this3.dbname, hash);
|
||
_this3.events.emit('data', _this3.dbname, hash);
|
||
return result.op.hash;
|
||
});
|
||
});
|
||
}
|
||
}, {
|
||
key: '_cacheInMemory',
|
||
value: function _cacheInMemory(log) {
|
||
var _this4 = this;
|
||
|
||
var promises = log.items.map(function (f) {
|
||
return f.payload;
|
||
}).filter(function (f) {
|
||
return !_this4._cached[f];
|
||
}).map(function (f) {
|
||
return _this4._ipfs.object.get(f).then(function (obj) {
|
||
return _this4._cachePayload(f, JSON.parse(obj.Data));
|
||
});
|
||
});
|
||
|
||
return _promise2.default.all(promises);
|
||
}
|
||
}, {
|
||
key: '_cachePayload',
|
||
value: function _cachePayload(hash, payload) {
|
||
if (!this._cached[hash]) {
|
||
(0, _assign2.default)(payload, { hash: hash });
|
||
if (payload.key === null) (0, _assign2.default)(payload, { key: hash });
|
||
this._cached[hash] = payload;
|
||
}
|
||
}
|
||
}, {
|
||
key: 'ops',
|
||
get: function get() {
|
||
var _this5 = this;
|
||
|
||
return this._log.items.map(function (f) {
|
||
return _this5._cached[f.payload];
|
||
});
|
||
}
|
||
}]);
|
||
return OperationsLog;
|
||
}();
|
||
|
||
module.exports = OperationsLog;
|
||
|
||
/***/ },
|
||
/* 145 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = { "default": __webpack_require__(146), __esModule: true };
|
||
|
||
/***/ },
|
||
/* 146 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
__webpack_require__(147);
|
||
module.exports = __webpack_require__(12).Object.assign;
|
||
|
||
/***/ },
|
||
/* 147 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// 19.1.3.1 Object.assign(target, source)
|
||
var $export = __webpack_require__(10);
|
||
|
||
$export($export.S + $export.F, 'Object', {assign: __webpack_require__(148)});
|
||
|
||
/***/ },
|
||
/* 148 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// 19.1.2.1 Object.assign(target, source, ...)
|
||
var $ = __webpack_require__(17)
|
||
, toObject = __webpack_require__(122)
|
||
, IObject = __webpack_require__(33);
|
||
|
||
// should work with symbols and should have deterministic property order (V8 bug)
|
||
module.exports = __webpack_require__(20)(function(){
|
||
var a = Object.assign
|
||
, A = {}
|
||
, B = {}
|
||
, S = Symbol()
|
||
, K = 'abcdefghijklmnopqrst';
|
||
A[S] = 7;
|
||
K.split('').forEach(function(k){ B[k] = k; });
|
||
return a({}, A)[S] != 7 || Object.keys(a({}, B)).join('') != K;
|
||
}) ? function assign(target, source){ // eslint-disable-line no-unused-vars
|
||
var T = toObject(target)
|
||
, $$ = arguments
|
||
, $$len = $$.length
|
||
, index = 1
|
||
, getKeys = $.getKeys
|
||
, getSymbols = $.getSymbols
|
||
, isEnum = $.isEnum;
|
||
while($$len > index){
|
||
var S = IObject($$[index++])
|
||
, keys = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S)
|
||
, length = keys.length
|
||
, j = 0
|
||
, key;
|
||
while(length > j)if(isEnum.call(S, key = keys[j++]))T[key] = S[key];
|
||
}
|
||
return T;
|
||
} : Object.assign;
|
||
|
||
/***/ },
|
||
/* 149 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
const _ = __webpack_require__(150);
|
||
const Lazy = __webpack_require__(151);
|
||
const Buffer = __webpack_require__(154).Buffer
|
||
const Node = __webpack_require__(158);
|
||
|
||
const MaxBatchSize = 10; // How many items to keep per local batch
|
||
const MaxHistory = 256; // How many items to fetch on join
|
||
|
||
class Log {
|
||
constructor(ipfs, id, items) {
|
||
this.id = id;
|
||
this._ipfs = ipfs;
|
||
this._items = items || [];
|
||
this._currentBatch = [];
|
||
}
|
||
|
||
get items() {
|
||
return this._items.concat(this._currentBatch);
|
||
}
|
||
|
||
get snapshot() {
|
||
return {
|
||
id: this.id,
|
||
items: this._currentBatch.map((f) => f.hash)
|
||
}
|
||
}
|
||
|
||
add(data) {
|
||
if(this._currentBatch.length >= MaxBatchSize)
|
||
this._commit();
|
||
|
||
return new Promise((resolve, reject) => {
|
||
const heads = Log.findHeads(this);
|
||
Node.create(this._ipfs, data, heads)
|
||
.then((node) => {
|
||
this._currentBatch.push(node);
|
||
resolve(node);
|
||
}).catch(reject);
|
||
});
|
||
}
|
||
|
||
join(other) {
|
||
return new Promise((resolve, reject) => {
|
||
const current = Lazy(this._currentBatch).difference(this._items).toArray();
|
||
const others = _.differenceWith(other.items, this._items, Node.equals);
|
||
const final = _.unionWith(current, others, Node.equals);
|
||
this._items = this._items.concat(final);
|
||
this._currentBatch = [];
|
||
|
||
// Fetch history
|
||
const nexts = _.flatten(other.items.map((f) => f.next));
|
||
const promises = nexts.map((f) => {
|
||
let all = this.items.map((a) => a.hash);
|
||
return this._fetchRecursive(this._ipfs, f, all, MaxHistory, 0).then((history) => {
|
||
history.forEach((b) => this._insert(b));
|
||
return history;
|
||
});
|
||
});
|
||
Promise.all(promises).then((r) => resolve(this));
|
||
});
|
||
}
|
||
|
||
clear() {
|
||
this._items = [];
|
||
this._currentBatch = [];
|
||
}
|
||
|
||
_insert(node) {
|
||
let indices = Lazy(node.next).map((next) => Lazy(this._items).map((f) => f.hash).indexOf(next)) // Find the item's parent's indices
|
||
const index = indices.toArray().length > 0 ? Math.max(indices.max() + 1, 0) : 0; // find the largest index (latest parent)
|
||
this._items.splice(index, 0, node);
|
||
return node;
|
||
}
|
||
|
||
_commit() {
|
||
const current = Lazy(this._currentBatch).difference(this._items).toArray();
|
||
this._items = this._items.concat(current);
|
||
this._currentBatch = [];
|
||
}
|
||
|
||
_fetchRecursive(ipfs, hash, all, amount, depth) {
|
||
const isReferenced = (list, item) => Lazy(list).reverse().find((f) => f === item) !== undefined;
|
||
return new Promise((resolve, reject) => {
|
||
let result = [];
|
||
|
||
// If the given hash is in the given log (all) or if we're at maximum depth, return
|
||
if(isReferenced(all, hash) || depth >= amount) {
|
||
resolve(result)
|
||
return;
|
||
}
|
||
|
||
// Create the node and add it to the result
|
||
Node.fromIpfsHash(ipfs, hash).then((node) => {
|
||
result.push(node);
|
||
all.push(hash);
|
||
depth ++;
|
||
|
||
const promises = node.next.map((f) => this._fetchRecursive(ipfs, f, all, amount, depth));
|
||
Promise.all(promises).then((res) => {
|
||
result = _.flatten(res.concat(result));
|
||
resolve(result);
|
||
}).catch(reject);
|
||
}).catch(reject);
|
||
});
|
||
}
|
||
|
||
static create(ipfs, id, items) {
|
||
if(!ipfs) throw new Error("Ipfs instance not defined")
|
||
if(!id) throw new Error("id is not defined")
|
||
return new Promise((resolve, reject) => {
|
||
const log = new Log(ipfs, id, items);
|
||
resolve(log);
|
||
});
|
||
}
|
||
|
||
static getIpfsHash(ipfs, log) {
|
||
if(!ipfs) throw new Error("Ipfs instance not defined")
|
||
return new Promise((resolve, reject) => {
|
||
ipfs.object.put(new Buffer(JSON.stringify({ Data: JSON.stringify(log.snapshot) })))
|
||
.then((res) => resolve(res.Hash))
|
||
.catch(reject);
|
||
});
|
||
}
|
||
|
||
static fromJson(ipfs, json) {
|
||
return new Promise((resolve, reject) => {
|
||
Promise.all(json.items.map((f) => Node.fromIpfsHash(ipfs, f)))
|
||
.then((items) => {
|
||
Log.create(ipfs, json.id, items).then(resolve).catch(reject);
|
||
}).catch(reject)
|
||
});
|
||
}
|
||
|
||
static fromIpfsHash(ipfs, hash) {
|
||
if(!ipfs) throw new Error("Ipfs instance not defined")
|
||
if(!hash) throw new Error("Invalid hash: " + hash)
|
||
return new Promise((resolve, reject) => {
|
||
ipfs.object.get(hash)
|
||
.then((res) => {
|
||
Log.fromJson(ipfs, JSON.parse(res.Data)).then(resolve).catch(reject);
|
||
}).catch(reject);
|
||
});
|
||
}
|
||
|
||
static findHeads(log) {
|
||
return Lazy(log.items)
|
||
.reverse()
|
||
.filter((f) => !Log.isReferencedInChain(log, f))
|
||
.map((f) => f.hash)
|
||
.toArray();
|
||
}
|
||
|
||
static isReferencedInChain(log, item) {
|
||
return Lazy(log.items).reverse().find((e) => e.hasChild(item)) !== undefined;
|
||
}
|
||
|
||
static get batchSize() {
|
||
return MaxBatchSize;
|
||
}
|
||
|
||
static get maxHistory() {
|
||
return MaxHistory;
|
||
}
|
||
|
||
}
|
||
|
||
module.exports = Log;
|
||
|
||
|
||
/***/ },
|
||
/* 150 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(module, global) {/**
|
||
* @license
|
||
* lodash 4.11.1 (Custom Build) <https://lodash.com/>
|
||
* Build: `lodash -d -o ./foo/lodash.js`
|
||
* Copyright jQuery Foundation and other contributors <https://jquery.org/>
|
||
* Released under MIT license <https://lodash.com/license>
|
||
* Based on Underscore.js 1.8.3 <http://underscorejs.org/LICENSE>
|
||
* Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||
*/
|
||
;(function() {
|
||
|
||
/** Used as a safe reference for `undefined` in pre-ES5 environments. */
|
||
var undefined;
|
||
|
||
/** Used as the semantic version number. */
|
||
var VERSION = '4.11.1';
|
||
|
||
/** Used as the size to enable large array optimizations. */
|
||
var LARGE_ARRAY_SIZE = 200;
|
||
|
||
/** Used as the `TypeError` message for "Functions" methods. */
|
||
var FUNC_ERROR_TEXT = 'Expected a function';
|
||
|
||
/** Used to stand-in for `undefined` hash values. */
|
||
var HASH_UNDEFINED = '__lodash_hash_undefined__';
|
||
|
||
/** Used as the internal argument placeholder. */
|
||
var PLACEHOLDER = '__lodash_placeholder__';
|
||
|
||
/** Used to compose bitmasks for wrapper metadata. */
|
||
var BIND_FLAG = 1,
|
||
BIND_KEY_FLAG = 2,
|
||
CURRY_BOUND_FLAG = 4,
|
||
CURRY_FLAG = 8,
|
||
CURRY_RIGHT_FLAG = 16,
|
||
PARTIAL_FLAG = 32,
|
||
PARTIAL_RIGHT_FLAG = 64,
|
||
ARY_FLAG = 128,
|
||
REARG_FLAG = 256,
|
||
FLIP_FLAG = 512;
|
||
|
||
/** Used to compose bitmasks for comparison styles. */
|
||
var UNORDERED_COMPARE_FLAG = 1,
|
||
PARTIAL_COMPARE_FLAG = 2;
|
||
|
||
/** Used as default options for `_.truncate`. */
|
||
var DEFAULT_TRUNC_LENGTH = 30,
|
||
DEFAULT_TRUNC_OMISSION = '...';
|
||
|
||
/** Used to detect hot functions by number of calls within a span of milliseconds. */
|
||
var HOT_COUNT = 150,
|
||
HOT_SPAN = 16;
|
||
|
||
/** Used to indicate the type of lazy iteratees. */
|
||
var LAZY_FILTER_FLAG = 1,
|
||
LAZY_MAP_FLAG = 2,
|
||
LAZY_WHILE_FLAG = 3;
|
||
|
||
/** Used as references for various `Number` constants. */
|
||
var INFINITY = 1 / 0,
|
||
MAX_SAFE_INTEGER = 9007199254740991,
|
||
MAX_INTEGER = 1.7976931348623157e+308,
|
||
NAN = 0 / 0;
|
||
|
||
/** Used as references for the maximum length and index of an array. */
|
||
var MAX_ARRAY_LENGTH = 4294967295,
|
||
MAX_ARRAY_INDEX = MAX_ARRAY_LENGTH - 1,
|
||
HALF_MAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH >>> 1;
|
||
|
||
/** `Object#toString` result references. */
|
||
var argsTag = '[object Arguments]',
|
||
arrayTag = '[object Array]',
|
||
boolTag = '[object Boolean]',
|
||
dateTag = '[object Date]',
|
||
errorTag = '[object Error]',
|
||
funcTag = '[object Function]',
|
||
genTag = '[object GeneratorFunction]',
|
||
mapTag = '[object Map]',
|
||
numberTag = '[object Number]',
|
||
objectTag = '[object Object]',
|
||
promiseTag = '[object Promise]',
|
||
regexpTag = '[object RegExp]',
|
||
setTag = '[object Set]',
|
||
stringTag = '[object String]',
|
||
symbolTag = '[object Symbol]',
|
||
weakMapTag = '[object WeakMap]',
|
||
weakSetTag = '[object WeakSet]';
|
||
|
||
var arrayBufferTag = '[object ArrayBuffer]',
|
||
dataViewTag = '[object DataView]',
|
||
float32Tag = '[object Float32Array]',
|
||
float64Tag = '[object Float64Array]',
|
||
int8Tag = '[object Int8Array]',
|
||
int16Tag = '[object Int16Array]',
|
||
int32Tag = '[object Int32Array]',
|
||
uint8Tag = '[object Uint8Array]',
|
||
uint8ClampedTag = '[object Uint8ClampedArray]',
|
||
uint16Tag = '[object Uint16Array]',
|
||
uint32Tag = '[object Uint32Array]';
|
||
|
||
/** 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 and HTML characters. */
|
||
var reEscapedHtml = /&(?:amp|lt|gt|quot|#39|#96);/g,
|
||
reUnescapedHtml = /[&<>"'`]/g,
|
||
reHasEscapedHtml = RegExp(reEscapedHtml.source),
|
||
reHasUnescapedHtml = RegExp(reUnescapedHtml.source);
|
||
|
||
/** Used to match template delimiters. */
|
||
var reEscape = /<%-([\s\S]+?)%>/g,
|
||
reEvaluate = /<%([\s\S]+?)%>/g,
|
||
reInterpolate = /<%=([\s\S]+?)%>/g;
|
||
|
||
/** Used to match property names within property paths. */
|
||
var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,
|
||
reIsPlainProp = /^\w*$/,
|
||
rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]/g;
|
||
|
||
/**
|
||
* Used to match `RegExp`
|
||
* [syntax characters](http://ecma-international.org/ecma-262/6.0/#sec-patterns).
|
||
*/
|
||
var reRegExpChar = /[\\^$.*+?()[\]{}|]/g,
|
||
reHasRegExpChar = RegExp(reRegExpChar.source);
|
||
|
||
/** Used to match leading and trailing whitespace. */
|
||
var reTrim = /^\s+|\s+$/g,
|
||
reTrimStart = /^\s+/,
|
||
reTrimEnd = /\s+$/;
|
||
|
||
/** Used to match non-compound words composed of alphanumeric characters. */
|
||
var reBasicWord = /[a-zA-Z0-9]+/g;
|
||
|
||
/** Used to match backslashes in property paths. */
|
||
var reEscapeChar = /\\(\\)?/g;
|
||
|
||
/**
|
||
* Used to match
|
||
* [ES template delimiters](http://ecma-international.org/ecma-262/6.0/#sec-template-literal-lexical-components).
|
||
*/
|
||
var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g;
|
||
|
||
/** Used to match `RegExp` flags from their coerced string values. */
|
||
var reFlags = /\w*$/;
|
||
|
||
/** Used to detect hexadecimal string values. */
|
||
var reHasHexPrefix = /^0x/i;
|
||
|
||
/** Used to detect bad signed hexadecimal string values. */
|
||
var reIsBadHex = /^[-+]0x[0-9a-f]+$/i;
|
||
|
||
/** Used to detect binary string values. */
|
||
var reIsBinary = /^0b[01]+$/i;
|
||
|
||
/** Used to detect host constructors (Safari). */
|
||
var reIsHostCtor = /^\[object .+?Constructor\]$/;
|
||
|
||
/** Used to detect octal string values. */
|
||
var reIsOctal = /^0o[0-7]+$/i;
|
||
|
||
/** Used to detect unsigned integer values. */
|
||
var reIsUint = /^(?:0|[1-9]\d*)$/;
|
||
|
||
/** Used to match latin-1 supplementary letters (excluding mathematical operators). */
|
||
var reLatin1 = /[\xc0-\xd6\xd8-\xde\xdf-\xf6\xf8-\xff]/g;
|
||
|
||
/** Used to ensure capturing order of template delimiters. */
|
||
var reNoMatch = /($^)/;
|
||
|
||
/** Used to match unescaped characters in compiled string literals. */
|
||
var reUnescapedString = /['\n\r\u2028\u2029\\]/g;
|
||
|
||
/** Used to compose unicode character classes. */
|
||
var rsAstralRange = '\\ud800-\\udfff',
|
||
rsComboMarksRange = '\\u0300-\\u036f\\ufe20-\\ufe23',
|
||
rsComboSymbolsRange = '\\u20d0-\\u20f0',
|
||
rsDingbatRange = '\\u2700-\\u27bf',
|
||
rsLowerRange = 'a-z\\xdf-\\xf6\\xf8-\\xff',
|
||
rsMathOpRange = '\\xac\\xb1\\xd7\\xf7',
|
||
rsNonCharRange = '\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf',
|
||
rsQuoteRange = '\\u2018\\u2019\\u201c\\u201d',
|
||
rsSpaceRange = ' \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000',
|
||
rsUpperRange = 'A-Z\\xc0-\\xd6\\xd8-\\xde',
|
||
rsVarRange = '\\ufe0e\\ufe0f',
|
||
rsBreakRange = rsMathOpRange + rsNonCharRange + rsQuoteRange + rsSpaceRange;
|
||
|
||
/** Used to compose unicode capture groups. */
|
||
var rsApos = "['\u2019]",
|
||
rsAstral = '[' + rsAstralRange + ']',
|
||
rsBreak = '[' + rsBreakRange + ']',
|
||
rsCombo = '[' + rsComboMarksRange + rsComboSymbolsRange + ']',
|
||
rsDigits = '\\d+',
|
||
rsDingbat = '[' + rsDingbatRange + ']',
|
||
rsLower = '[' + rsLowerRange + ']',
|
||
rsMisc = '[^' + rsAstralRange + rsBreakRange + rsDigits + rsDingbatRange + rsLowerRange + rsUpperRange + ']',
|
||
rsFitz = '\\ud83c[\\udffb-\\udfff]',
|
||
rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')',
|
||
rsNonAstral = '[^' + rsAstralRange + ']',
|
||
rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}',
|
||
rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]',
|
||
rsUpper = '[' + rsUpperRange + ']',
|
||
rsZWJ = '\\u200d';
|
||
|
||
/** Used to compose unicode regexes. */
|
||
var rsLowerMisc = '(?:' + rsLower + '|' + rsMisc + ')',
|
||
rsUpperMisc = '(?:' + rsUpper + '|' + rsMisc + ')',
|
||
rsOptLowerContr = '(?:' + rsApos + '(?:d|ll|m|re|s|t|ve))?',
|
||
rsOptUpperContr = '(?:' + rsApos + '(?:D|LL|M|RE|S|T|VE))?',
|
||
reOptMod = rsModifier + '?',
|
||
rsOptVar = '[' + rsVarRange + ']?',
|
||
rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*',
|
||
rsSeq = rsOptVar + reOptMod + rsOptJoin,
|
||
rsEmoji = '(?:' + [rsDingbat, rsRegional, rsSurrPair].join('|') + ')' + rsSeq,
|
||
rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')';
|
||
|
||
/** Used to match apostrophes. */
|
||
var reApos = RegExp(rsApos, 'g');
|
||
|
||
/**
|
||
* Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
|
||
* [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
|
||
*/
|
||
var reComboMark = RegExp(rsCombo, 'g');
|
||
|
||
/** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */
|
||
var reComplexSymbol = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g');
|
||
|
||
/** Used to match complex or compound words. */
|
||
var reComplexWord = RegExp([
|
||
rsUpper + '?' + rsLower + '+' + rsOptLowerContr + '(?=' + [rsBreak, rsUpper, '$'].join('|') + ')',
|
||
rsUpperMisc + '+' + rsOptUpperContr + '(?=' + [rsBreak, rsUpper + rsLowerMisc, '$'].join('|') + ')',
|
||
rsUpper + '?' + rsLowerMisc + '+' + rsOptLowerContr,
|
||
rsUpper + '+' + rsOptUpperContr,
|
||
rsDigits,
|
||
rsEmoji
|
||
].join('|'), 'g');
|
||
|
||
/** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */
|
||
var reHasComplexSymbol = RegExp('[' + rsZWJ + rsAstralRange + rsComboMarksRange + rsComboSymbolsRange + rsVarRange + ']');
|
||
|
||
/** Used to detect strings that need a more robust regexp to match words. */
|
||
var reHasComplexWord = /[a-z][A-Z]|[A-Z]{2,}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;
|
||
|
||
/** Used to assign default `context` object properties. */
|
||
var contextProps = [
|
||
'Array', 'Buffer', 'DataView', 'Date', 'Error', 'Float32Array', 'Float64Array',
|
||
'Function', 'Int8Array', 'Int16Array', 'Int32Array', 'Map', 'Math', 'Object',
|
||
'Promise', 'Reflect', 'RegExp', 'Set', 'String', 'Symbol', 'TypeError',
|
||
'Uint8Array', 'Uint8ClampedArray', 'Uint16Array', 'Uint32Array', 'WeakMap',
|
||
'_', 'clearTimeout', 'isFinite', 'parseInt', 'setTimeout'
|
||
];
|
||
|
||
/** Used to make template sourceURLs easier to identify. */
|
||
var templateCounter = -1;
|
||
|
||
/** Used to identify `toStringTag` values of typed arrays. */
|
||
var typedArrayTags = {};
|
||
typedArrayTags[float32Tag] = typedArrayTags[float64Tag] =
|
||
typedArrayTags[int8Tag] = typedArrayTags[int16Tag] =
|
||
typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] =
|
||
typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] =
|
||
typedArrayTags[uint32Tag] = true;
|
||
typedArrayTags[argsTag] = typedArrayTags[arrayTag] =
|
||
typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] =
|
||
typedArrayTags[dataViewTag] = typedArrayTags[dateTag] =
|
||
typedArrayTags[errorTag] = typedArrayTags[funcTag] =
|
||
typedArrayTags[mapTag] = typedArrayTags[numberTag] =
|
||
typedArrayTags[objectTag] = typedArrayTags[regexpTag] =
|
||
typedArrayTags[setTag] = typedArrayTags[stringTag] =
|
||
typedArrayTags[weakMapTag] = false;
|
||
|
||
/** Used to identify `toStringTag` values supported by `_.clone`. */
|
||
var cloneableTags = {};
|
||
cloneableTags[argsTag] = cloneableTags[arrayTag] =
|
||
cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] =
|
||
cloneableTags[boolTag] = cloneableTags[dateTag] =
|
||
cloneableTags[float32Tag] = cloneableTags[float64Tag] =
|
||
cloneableTags[int8Tag] = cloneableTags[int16Tag] =
|
||
cloneableTags[int32Tag] = cloneableTags[mapTag] =
|
||
cloneableTags[numberTag] = cloneableTags[objectTag] =
|
||
cloneableTags[regexpTag] = cloneableTags[setTag] =
|
||
cloneableTags[stringTag] = cloneableTags[symbolTag] =
|
||
cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] =
|
||
cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true;
|
||
cloneableTags[errorTag] = cloneableTags[funcTag] =
|
||
cloneableTags[weakMapTag] = false;
|
||
|
||
/** Used to map latin-1 supplementary letters to basic latin letters. */
|
||
var deburredLetters = {
|
||
'\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
|
||
'\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
|
||
'\xc7': 'C', '\xe7': 'c',
|
||
'\xd0': 'D', '\xf0': 'd',
|
||
'\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
|
||
'\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
|
||
'\xcC': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
|
||
'\xeC': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i',
|
||
'\xd1': 'N', '\xf1': 'n',
|
||
'\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
|
||
'\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
|
||
'\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
|
||
'\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
|
||
'\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
|
||
'\xc6': 'Ae', '\xe6': 'ae',
|
||
'\xde': 'Th', '\xfe': 'th',
|
||
'\xdf': 'ss'
|
||
};
|
||
|
||
/** Used to map characters to HTML entities. */
|
||
var htmlEscapes = {
|
||
'&': '&',
|
||
'<': '<',
|
||
'>': '>',
|
||
'"': '"',
|
||
"'": ''',
|
||
'`': '`'
|
||
};
|
||
|
||
/** Used to map HTML entities to characters. */
|
||
var htmlUnescapes = {
|
||
'&': '&',
|
||
'<': '<',
|
||
'>': '>',
|
||
'"': '"',
|
||
''': "'",
|
||
'`': '`'
|
||
};
|
||
|
||
/** Used to determine if values are of the language type `Object`. */
|
||
var objectTypes = {
|
||
'function': true,
|
||
'object': true
|
||
};
|
||
|
||
/** Used to escape characters for inclusion in compiled string literals. */
|
||
var stringEscapes = {
|
||
'\\': '\\',
|
||
"'": "'",
|
||
'\n': 'n',
|
||
'\r': 'r',
|
||
'\u2028': 'u2028',
|
||
'\u2029': 'u2029'
|
||
};
|
||
|
||
/** Built-in method references without a dependency on `root`. */
|
||
var freeParseFloat = parseFloat,
|
||
freeParseInt = parseInt;
|
||
|
||
/** Detect free variable `exports`. */
|
||
var freeExports = (objectTypes[typeof exports] && exports && !exports.nodeType)
|
||
? exports
|
||
: undefined;
|
||
|
||
/** Detect free variable `module`. */
|
||
var freeModule = (objectTypes[typeof module] && module && !module.nodeType)
|
||
? module
|
||
: undefined;
|
||
|
||
/** Detect the popular CommonJS extension `module.exports`. */
|
||
var moduleExports = (freeModule && freeModule.exports === freeExports)
|
||
? freeExports
|
||
: undefined;
|
||
|
||
/** Detect free variable `global` from Node.js. */
|
||
var freeGlobal = checkGlobal(freeExports && freeModule && typeof global == 'object' && global);
|
||
|
||
/** Detect free variable `self`. */
|
||
var freeSelf = checkGlobal(objectTypes[typeof self] && self);
|
||
|
||
/** Detect free variable `window`. */
|
||
var freeWindow = checkGlobal(objectTypes[typeof window] && window);
|
||
|
||
/** Detect `this` as the global object. */
|
||
var thisGlobal = checkGlobal(objectTypes[typeof this] && this);
|
||
|
||
/**
|
||
* Used as a reference to the global object.
|
||
*
|
||
* The `this` value is used if it's the global object to avoid Greasemonkey's
|
||
* restricted `window` object, otherwise the `window` object is used.
|
||
*/
|
||
var root = freeGlobal ||
|
||
((freeWindow !== (thisGlobal && thisGlobal.window)) && freeWindow) ||
|
||
freeSelf || thisGlobal || Function('return this')();
|
||
|
||
/*--------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Adds the key-value `pair` to `map`.
|
||
*
|
||
* @private
|
||
* @param {Object} map The map to modify.
|
||
* @param {Array} pair The key-value pair to add.
|
||
* @returns {Object} Returns `map`.
|
||
*/
|
||
function addMapEntry(map, pair) {
|
||
// Don't return `Map#set` because it doesn't return the map instance in IE 11.
|
||
map.set(pair[0], pair[1]);
|
||
return map;
|
||
}
|
||
|
||
/**
|
||
* Adds `value` to `set`.
|
||
*
|
||
* @private
|
||
* @param {Object} set The set to modify.
|
||
* @param {*} value The value to add.
|
||
* @returns {Object} Returns `set`.
|
||
*/
|
||
function addSetEntry(set, value) {
|
||
set.add(value);
|
||
return set;
|
||
}
|
||
|
||
/**
|
||
* A faster alternative to `Function#apply`, this function invokes `func`
|
||
* with the `this` binding of `thisArg` and the arguments of `args`.
|
||
*
|
||
* @private
|
||
* @param {Function} func The function to invoke.
|
||
* @param {*} thisArg The `this` binding of `func`.
|
||
* @param {Array} args The arguments to invoke `func` with.
|
||
* @returns {*} Returns the result of `func`.
|
||
*/
|
||
function apply(func, thisArg, args) {
|
||
var length = args.length;
|
||
switch (length) {
|
||
case 0: return func.call(thisArg);
|
||
case 1: return func.call(thisArg, args[0]);
|
||
case 2: return func.call(thisArg, args[0], args[1]);
|
||
case 3: return func.call(thisArg, args[0], args[1], args[2]);
|
||
}
|
||
return func.apply(thisArg, args);
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `baseAggregator` for arrays.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Function} setter The function to set `accumulator` values.
|
||
* @param {Function} iteratee The iteratee to transform keys.
|
||
* @param {Object} accumulator The initial aggregated object.
|
||
* @returns {Function} Returns `accumulator`.
|
||
*/
|
||
function arrayAggregator(array, setter, iteratee, accumulator) {
|
||
var index = -1,
|
||
length = array.length;
|
||
|
||
while (++index < length) {
|
||
var value = array[index];
|
||
setter(accumulator, value, iteratee(value), array);
|
||
}
|
||
return accumulator;
|
||
}
|
||
|
||
/**
|
||
* Creates a new array concatenating `array` with `other`.
|
||
*
|
||
* @private
|
||
* @param {Array} array The first array to concatenate.
|
||
* @param {Array} other The second array to concatenate.
|
||
* @returns {Array} Returns the new concatenated array.
|
||
*/
|
||
function arrayConcat(array, other) {
|
||
var index = -1,
|
||
length = array.length,
|
||
othIndex = -1,
|
||
othLength = other.length,
|
||
result = Array(length + othLength);
|
||
|
||
while (++index < length) {
|
||
result[index] = array[index];
|
||
}
|
||
while (++othIndex < othLength) {
|
||
result[index++] = other[othIndex];
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `_.forEach` for arrays without support for
|
||
* iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @returns {Array} Returns `array`.
|
||
*/
|
||
function arrayEach(array, iteratee) {
|
||
var index = -1,
|
||
length = array.length;
|
||
|
||
while (++index < length) {
|
||
if (iteratee(array[index], index, array) === false) {
|
||
break;
|
||
}
|
||
}
|
||
return array;
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `_.forEachRight` for arrays without support for
|
||
* iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @returns {Array} Returns `array`.
|
||
*/
|
||
function arrayEachRight(array, iteratee) {
|
||
var length = array.length;
|
||
|
||
while (length--) {
|
||
if (iteratee(array[length], length, array) === false) {
|
||
break;
|
||
}
|
||
}
|
||
return array;
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `_.every` for arrays without support for
|
||
* iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Function} predicate The function invoked per iteration.
|
||
* @returns {boolean} Returns `true` if all elements pass the predicate check,
|
||
* else `false`.
|
||
*/
|
||
function arrayEvery(array, predicate) {
|
||
var index = -1,
|
||
length = array.length;
|
||
|
||
while (++index < length) {
|
||
if (!predicate(array[index], index, array)) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `_.filter` for arrays without support for
|
||
* iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Function} predicate The function invoked per iteration.
|
||
* @returns {Array} Returns the new filtered array.
|
||
*/
|
||
function arrayFilter(array, predicate) {
|
||
var index = -1,
|
||
length = array.length,
|
||
resIndex = 0,
|
||
result = [];
|
||
|
||
while (++index < length) {
|
||
var value = array[index];
|
||
if (predicate(value, index, array)) {
|
||
result[resIndex++] = value;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `_.includes` for arrays without support for
|
||
* specifying an index to search from.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to search.
|
||
* @param {*} target The value to search for.
|
||
* @returns {boolean} Returns `true` if `target` is found, else `false`.
|
||
*/
|
||
function arrayIncludes(array, value) {
|
||
return !!array.length && baseIndexOf(array, value, 0) > -1;
|
||
}
|
||
|
||
/**
|
||
* This function is like `arrayIncludes` except that it accepts a comparator.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to search.
|
||
* @param {*} target The value to search for.
|
||
* @param {Function} comparator The comparator invoked per element.
|
||
* @returns {boolean} Returns `true` if `target` is found, else `false`.
|
||
*/
|
||
function arrayIncludesWith(array, value, comparator) {
|
||
var index = -1,
|
||
length = array.length;
|
||
|
||
while (++index < length) {
|
||
if (comparator(value, array[index])) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `_.map` for arrays without support for iteratee
|
||
* shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @returns {Array} Returns the new mapped array.
|
||
*/
|
||
function arrayMap(array, iteratee) {
|
||
var index = -1,
|
||
length = array.length,
|
||
result = Array(length);
|
||
|
||
while (++index < length) {
|
||
result[index] = iteratee(array[index], index, array);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Appends the elements of `values` to `array`.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to modify.
|
||
* @param {Array} values The values to append.
|
||
* @returns {Array} Returns `array`.
|
||
*/
|
||
function arrayPush(array, values) {
|
||
var index = -1,
|
||
length = values.length,
|
||
offset = array.length;
|
||
|
||
while (++index < length) {
|
||
array[offset + index] = values[index];
|
||
}
|
||
return array;
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `_.reduce` for arrays without support for
|
||
* iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @param {*} [accumulator] The initial value.
|
||
* @param {boolean} [initAccum] Specify using the first element of `array` as
|
||
* the initial value.
|
||
* @returns {*} Returns the accumulated value.
|
||
*/
|
||
function arrayReduce(array, iteratee, accumulator, initAccum) {
|
||
var index = -1,
|
||
length = array.length;
|
||
|
||
if (initAccum && length) {
|
||
accumulator = array[++index];
|
||
}
|
||
while (++index < length) {
|
||
accumulator = iteratee(accumulator, array[index], index, array);
|
||
}
|
||
return accumulator;
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `_.reduceRight` for arrays without support for
|
||
* iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @param {*} [accumulator] The initial value.
|
||
* @param {boolean} [initAccum] Specify using the last element of `array` as
|
||
* the initial value.
|
||
* @returns {*} Returns the accumulated value.
|
||
*/
|
||
function arrayReduceRight(array, iteratee, accumulator, initAccum) {
|
||
var length = array.length;
|
||
if (initAccum && length) {
|
||
accumulator = array[--length];
|
||
}
|
||
while (length--) {
|
||
accumulator = iteratee(accumulator, array[length], length, array);
|
||
}
|
||
return accumulator;
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `_.some` for arrays without support for iteratee
|
||
* shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Function} predicate The function invoked per iteration.
|
||
* @returns {boolean} Returns `true` if any element passes the predicate check,
|
||
* else `false`.
|
||
*/
|
||
function arraySome(array, predicate) {
|
||
var index = -1,
|
||
length = array.length;
|
||
|
||
while (++index < length) {
|
||
if (predicate(array[index], index, array)) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of methods like `_.max` and `_.min` which accepts a
|
||
* `comparator` to determine the extremum value.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Function} iteratee The iteratee invoked per iteration.
|
||
* @param {Function} comparator The comparator used to compare values.
|
||
* @returns {*} Returns the extremum value.
|
||
*/
|
||
function baseExtremum(array, iteratee, comparator) {
|
||
var index = -1,
|
||
length = array.length;
|
||
|
||
while (++index < length) {
|
||
var value = array[index],
|
||
current = iteratee(value);
|
||
|
||
if (current != null && (computed === undefined
|
||
? current === current
|
||
: comparator(current, computed)
|
||
)) {
|
||
var computed = current,
|
||
result = value;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of methods like `_.find` and `_.findKey`, without
|
||
* support for iteratee shorthands, which iterates over `collection` using
|
||
* `eachFunc`.
|
||
*
|
||
* @private
|
||
* @param {Array|Object} collection The collection to search.
|
||
* @param {Function} predicate The function invoked per iteration.
|
||
* @param {Function} eachFunc The function to iterate over `collection`.
|
||
* @param {boolean} [retKey] Specify returning the key of the found element
|
||
* instead of the element itself.
|
||
* @returns {*} Returns the found element or its key, else `undefined`.
|
||
*/
|
||
function baseFind(collection, predicate, eachFunc, retKey) {
|
||
var result;
|
||
eachFunc(collection, function(value, key, collection) {
|
||
if (predicate(value, key, collection)) {
|
||
result = retKey ? key : value;
|
||
return false;
|
||
}
|
||
});
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.findIndex` and `_.findLastIndex` without
|
||
* support for iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to search.
|
||
* @param {Function} predicate The function invoked per iteration.
|
||
* @param {boolean} [fromRight] Specify iterating from right to left.
|
||
* @returns {number} Returns the index of the matched value, else `-1`.
|
||
*/
|
||
function baseFindIndex(array, predicate, fromRight) {
|
||
var length = array.length,
|
||
index = fromRight ? length : -1;
|
||
|
||
while ((fromRight ? index-- : ++index < length)) {
|
||
if (predicate(array[index], index, array)) {
|
||
return index;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.indexOf` without `fromIndex` bounds checks.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to search.
|
||
* @param {*} value The value to search for.
|
||
* @param {number} fromIndex The index to search from.
|
||
* @returns {number} Returns the index of the matched value, else `-1`.
|
||
*/
|
||
function baseIndexOf(array, value, fromIndex) {
|
||
if (value !== value) {
|
||
return indexOfNaN(array, fromIndex);
|
||
}
|
||
var index = fromIndex - 1,
|
||
length = array.length;
|
||
|
||
while (++index < length) {
|
||
if (array[index] === value) {
|
||
return index;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* This function is like `baseIndexOf` except that it accepts a comparator.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to search.
|
||
* @param {*} value The value to search for.
|
||
* @param {number} fromIndex The index to search from.
|
||
* @param {Function} comparator The comparator invoked per element.
|
||
* @returns {number} Returns the index of the matched value, else `-1`.
|
||
*/
|
||
function baseIndexOfWith(array, value, fromIndex, comparator) {
|
||
var index = fromIndex - 1,
|
||
length = array.length;
|
||
|
||
while (++index < length) {
|
||
if (comparator(array[index], value)) {
|
||
return index;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.mean` and `_.meanBy` without support for
|
||
* iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @returns {number} Returns the mean.
|
||
*/
|
||
function baseMean(array, iteratee) {
|
||
var length = array ? array.length : 0;
|
||
return length ? (baseSum(array, iteratee) / length) : NAN;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.reduce` and `_.reduceRight`, without support
|
||
* for iteratee shorthands, which iterates over `collection` using `eachFunc`.
|
||
*
|
||
* @private
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @param {*} accumulator The initial value.
|
||
* @param {boolean} initAccum Specify using the first or last element of
|
||
* `collection` as the initial value.
|
||
* @param {Function} eachFunc The function to iterate over `collection`.
|
||
* @returns {*} Returns the accumulated value.
|
||
*/
|
||
function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) {
|
||
eachFunc(collection, function(value, index, collection) {
|
||
accumulator = initAccum
|
||
? (initAccum = false, value)
|
||
: iteratee(accumulator, value, index, collection);
|
||
});
|
||
return accumulator;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.sortBy` which uses `comparer` to define the
|
||
* sort order of `array` and replaces criteria objects with their corresponding
|
||
* values.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to sort.
|
||
* @param {Function} comparer The function to define sort order.
|
||
* @returns {Array} Returns `array`.
|
||
*/
|
||
function baseSortBy(array, comparer) {
|
||
var length = array.length;
|
||
|
||
array.sort(comparer);
|
||
while (length--) {
|
||
array[length] = array[length].value;
|
||
}
|
||
return array;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.sum` and `_.sumBy` without support for
|
||
* iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @returns {number} Returns the sum.
|
||
*/
|
||
function baseSum(array, iteratee) {
|
||
var result,
|
||
index = -1,
|
||
length = array.length;
|
||
|
||
while (++index < length) {
|
||
var current = iteratee(array[index]);
|
||
if (current !== undefined) {
|
||
result = result === undefined ? current : (result + current);
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.times` without support for iteratee shorthands
|
||
* or max array length checks.
|
||
*
|
||
* @private
|
||
* @param {number} n The number of times to invoke `iteratee`.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @returns {Array} Returns the array of results.
|
||
*/
|
||
function baseTimes(n, iteratee) {
|
||
var index = -1,
|
||
result = Array(n);
|
||
|
||
while (++index < n) {
|
||
result[index] = iteratee(index);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.toPairs` and `_.toPairsIn` which creates an array
|
||
* of key-value pairs for `object` corresponding to the property names of `props`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @param {Array} props The property names to get values for.
|
||
* @returns {Object} Returns the new array of key-value pairs.
|
||
*/
|
||
function baseToPairs(object, props) {
|
||
return arrayMap(props, function(key) {
|
||
return [key, object[key]];
|
||
});
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.unary` without support for storing wrapper metadata.
|
||
*
|
||
* @private
|
||
* @param {Function} func The function to cap arguments for.
|
||
* @returns {Function} Returns the new function.
|
||
*/
|
||
function baseUnary(func) {
|
||
return function(value) {
|
||
return func(value);
|
||
};
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.values` and `_.valuesIn` which creates an
|
||
* array of `object` property values corresponding to the property names
|
||
* of `props`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @param {Array} props The property names to get values for.
|
||
* @returns {Object} Returns the array of property values.
|
||
*/
|
||
function baseValues(object, props) {
|
||
return arrayMap(props, function(key) {
|
||
return object[key];
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Used by `_.trim` and `_.trimStart` to get the index of the first string symbol
|
||
* that is not found in the character symbols.
|
||
*
|
||
* @private
|
||
* @param {Array} strSymbols The string symbols to inspect.
|
||
* @param {Array} chrSymbols The character symbols to find.
|
||
* @returns {number} Returns the index of the first unmatched string symbol.
|
||
*/
|
||
function charsStartIndex(strSymbols, chrSymbols) {
|
||
var index = -1,
|
||
length = strSymbols.length;
|
||
|
||
while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
|
||
return index;
|
||
}
|
||
|
||
/**
|
||
* Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol
|
||
* that is not found in the character symbols.
|
||
*
|
||
* @private
|
||
* @param {Array} strSymbols The string symbols to inspect.
|
||
* @param {Array} chrSymbols The character symbols to find.
|
||
* @returns {number} Returns the index of the last unmatched string symbol.
|
||
*/
|
||
function charsEndIndex(strSymbols, chrSymbols) {
|
||
var index = strSymbols.length;
|
||
|
||
while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {}
|
||
return index;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is a global object.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to check.
|
||
* @returns {null|Object} Returns `value` if it's a global object, else `null`.
|
||
*/
|
||
function checkGlobal(value) {
|
||
return (value && value.Object === Object) ? value : null;
|
||
}
|
||
|
||
/**
|
||
* Compares values to sort them in ascending order.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to compare.
|
||
* @param {*} other The other value to compare.
|
||
* @returns {number} Returns the sort order indicator for `value`.
|
||
*/
|
||
function compareAscending(value, other) {
|
||
if (value !== other) {
|
||
var valIsNull = value === null,
|
||
valIsUndef = value === undefined,
|
||
valIsReflexive = value === value;
|
||
|
||
var othIsNull = other === null,
|
||
othIsUndef = other === undefined,
|
||
othIsReflexive = other === other;
|
||
|
||
if ((value > other && !othIsNull) || !valIsReflexive ||
|
||
(valIsNull && !othIsUndef && othIsReflexive) ||
|
||
(valIsUndef && othIsReflexive)) {
|
||
return 1;
|
||
}
|
||
if ((value < other && !valIsNull) || !othIsReflexive ||
|
||
(othIsNull && !valIsUndef && valIsReflexive) ||
|
||
(othIsUndef && valIsReflexive)) {
|
||
return -1;
|
||
}
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* Used by `_.orderBy` to compare multiple properties of a value to another
|
||
* and stable sort them.
|
||
*
|
||
* If `orders` is unspecified, all values are sorted in ascending order. Otherwise,
|
||
* specify an order of "desc" for descending or "asc" for ascending sort order
|
||
* of corresponding values.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to compare.
|
||
* @param {Object} other The other object to compare.
|
||
* @param {boolean[]|string[]} orders The order to sort by for each property.
|
||
* @returns {number} Returns the sort order indicator for `object`.
|
||
*/
|
||
function compareMultiple(object, other, orders) {
|
||
var index = -1,
|
||
objCriteria = object.criteria,
|
||
othCriteria = other.criteria,
|
||
length = objCriteria.length,
|
||
ordersLength = orders.length;
|
||
|
||
while (++index < length) {
|
||
var result = compareAscending(objCriteria[index], othCriteria[index]);
|
||
if (result) {
|
||
if (index >= ordersLength) {
|
||
return result;
|
||
}
|
||
var order = orders[index];
|
||
return result * (order == 'desc' ? -1 : 1);
|
||
}
|
||
}
|
||
// Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications
|
||
// that causes it, under certain circumstances, to provide the same value for
|
||
// `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247
|
||
// for more details.
|
||
//
|
||
// This also ensures a stable sort in V8 and other engines.
|
||
// See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details.
|
||
return object.index - other.index;
|
||
}
|
||
|
||
/**
|
||
* Gets the number of `placeholder` occurrences in `array`.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to inspect.
|
||
* @param {*} placeholder The placeholder to search for.
|
||
* @returns {number} Returns the placeholder count.
|
||
*/
|
||
function countHolders(array, placeholder) {
|
||
var length = array.length,
|
||
result = 0;
|
||
|
||
while (length--) {
|
||
if (array[length] === placeholder) {
|
||
result++;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Creates a function that performs a mathematical operation on two values.
|
||
*
|
||
* @private
|
||
* @param {Function} operator The function to perform the operation.
|
||
* @returns {Function} Returns the new mathematical operation function.
|
||
*/
|
||
function createMathOperation(operator) {
|
||
return function(value, other) {
|
||
var result;
|
||
if (value === undefined && other === undefined) {
|
||
return 0;
|
||
}
|
||
if (value !== undefined) {
|
||
result = value;
|
||
}
|
||
if (other !== undefined) {
|
||
result = result === undefined ? other : operator(result, other);
|
||
}
|
||
return result;
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Used by `_.deburr` to convert latin-1 supplementary letters to basic latin letters.
|
||
*
|
||
* @private
|
||
* @param {string} letter The matched letter to deburr.
|
||
* @returns {string} Returns the deburred letter.
|
||
*/
|
||
function deburrLetter(letter) {
|
||
return deburredLetters[letter];
|
||
}
|
||
|
||
/**
|
||
* Used by `_.escape` to convert characters to HTML entities.
|
||
*
|
||
* @private
|
||
* @param {string} chr The matched character to escape.
|
||
* @returns {string} Returns the escaped character.
|
||
*/
|
||
function escapeHtmlChar(chr) {
|
||
return htmlEscapes[chr];
|
||
}
|
||
|
||
/**
|
||
* Used by `_.template` to escape characters for inclusion in compiled string literals.
|
||
*
|
||
* @private
|
||
* @param {string} chr The matched character to escape.
|
||
* @returns {string} Returns the escaped character.
|
||
*/
|
||
function escapeStringChar(chr) {
|
||
return '\\' + stringEscapes[chr];
|
||
}
|
||
|
||
/**
|
||
* Gets the index at which the first occurrence of `NaN` is found in `array`.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to search.
|
||
* @param {number} fromIndex The index to search from.
|
||
* @param {boolean} [fromRight] Specify iterating from right to left.
|
||
* @returns {number} Returns the index of the matched `NaN`, else `-1`.
|
||
*/
|
||
function indexOfNaN(array, fromIndex, fromRight) {
|
||
var length = array.length,
|
||
index = fromIndex + (fromRight ? 0 : -1);
|
||
|
||
while ((fromRight ? index-- : ++index < length)) {
|
||
var other = array[index];
|
||
if (other !== other) {
|
||
return index;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is a host object in IE < 9.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is a host object, else `false`.
|
||
*/
|
||
function isHostObject(value) {
|
||
// Many host objects are `Object` objects that can coerce to strings
|
||
// despite having improperly defined `toString` methods.
|
||
var result = false;
|
||
if (value != null && typeof value.toString != 'function') {
|
||
try {
|
||
result = !!(value + '');
|
||
} catch (e) {}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is a valid array-like index.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to check.
|
||
* @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index.
|
||
* @returns {boolean} Returns `true` if `value` is a valid index, else `false`.
|
||
*/
|
||
function isIndex(value, length) {
|
||
value = (typeof value == 'number' || reIsUint.test(value)) ? +value : -1;
|
||
length = length == null ? MAX_SAFE_INTEGER : length;
|
||
return value > -1 && value % 1 == 0 && value < length;
|
||
}
|
||
|
||
/**
|
||
* Converts `iterator` to an array.
|
||
*
|
||
* @private
|
||
* @param {Object} iterator The iterator to convert.
|
||
* @returns {Array} Returns the converted array.
|
||
*/
|
||
function iteratorToArray(iterator) {
|
||
var data,
|
||
result = [];
|
||
|
||
while (!(data = iterator.next()).done) {
|
||
result.push(data.value);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Converts `map` to an array.
|
||
*
|
||
* @private
|
||
* @param {Object} map The map to convert.
|
||
* @returns {Array} Returns the converted array.
|
||
*/
|
||
function mapToArray(map) {
|
||
var index = -1,
|
||
result = Array(map.size);
|
||
|
||
map.forEach(function(value, key) {
|
||
result[++index] = [key, value];
|
||
});
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Replaces all `placeholder` elements in `array` with an internal placeholder
|
||
* and returns an array of their indexes.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to modify.
|
||
* @param {*} placeholder The placeholder to replace.
|
||
* @returns {Array} Returns the new array of placeholder indexes.
|
||
*/
|
||
function replaceHolders(array, placeholder) {
|
||
var index = -1,
|
||
length = array.length,
|
||
resIndex = 0,
|
||
result = [];
|
||
|
||
while (++index < length) {
|
||
var value = array[index];
|
||
if (value === placeholder || value === PLACEHOLDER) {
|
||
array[index] = PLACEHOLDER;
|
||
result[resIndex++] = index;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Converts `set` to an array.
|
||
*
|
||
* @private
|
||
* @param {Object} set The set to convert.
|
||
* @returns {Array} Returns the converted array.
|
||
*/
|
||
function setToArray(set) {
|
||
var index = -1,
|
||
result = Array(set.size);
|
||
|
||
set.forEach(function(value) {
|
||
result[++index] = value;
|
||
});
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Gets the number of symbols in `string`.
|
||
*
|
||
* @private
|
||
* @param {string} string The string to inspect.
|
||
* @returns {number} Returns the string size.
|
||
*/
|
||
function stringSize(string) {
|
||
if (!(string && reHasComplexSymbol.test(string))) {
|
||
return string.length;
|
||
}
|
||
var result = reComplexSymbol.lastIndex = 0;
|
||
while (reComplexSymbol.test(string)) {
|
||
result++;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Converts `string` to an array.
|
||
*
|
||
* @private
|
||
* @param {string} string The string to convert.
|
||
* @returns {Array} Returns the converted array.
|
||
*/
|
||
function stringToArray(string) {
|
||
return string.match(reComplexSymbol);
|
||
}
|
||
|
||
/**
|
||
* Used by `_.unescape` to convert HTML entities to characters.
|
||
*
|
||
* @private
|
||
* @param {string} chr The matched character to unescape.
|
||
* @returns {string} Returns the unescaped character.
|
||
*/
|
||
function unescapeHtmlChar(chr) {
|
||
return htmlUnescapes[chr];
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Create a new pristine `lodash` function using the `context` object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 1.1.0
|
||
* @category Util
|
||
* @param {Object} [context=root] The context object.
|
||
* @returns {Function} Returns a new `lodash` function.
|
||
* @example
|
||
*
|
||
* _.mixin({ 'foo': _.constant('foo') });
|
||
*
|
||
* var lodash = _.runInContext();
|
||
* lodash.mixin({ 'bar': lodash.constant('bar') });
|
||
*
|
||
* _.isFunction(_.foo);
|
||
* // => true
|
||
* _.isFunction(_.bar);
|
||
* // => false
|
||
*
|
||
* lodash.isFunction(lodash.foo);
|
||
* // => false
|
||
* lodash.isFunction(lodash.bar);
|
||
* // => true
|
||
*
|
||
* // Use `context` to mock `Date#getTime` use in `_.now`.
|
||
* var mock = _.runInContext({
|
||
* 'Date': function() {
|
||
* return { 'getTime': getTimeMock };
|
||
* }
|
||
* });
|
||
*
|
||
* // Create a suped-up `defer` in Node.js.
|
||
* var defer = _.runInContext({ 'setTimeout': setImmediate }).defer;
|
||
*/
|
||
function runInContext(context) {
|
||
context = context ? _.defaults({}, context, _.pick(root, contextProps)) : root;
|
||
|
||
/** Built-in constructor references. */
|
||
var Date = context.Date,
|
||
Error = context.Error,
|
||
Math = context.Math,
|
||
RegExp = context.RegExp,
|
||
TypeError = context.TypeError;
|
||
|
||
/** Used for built-in method references. */
|
||
var arrayProto = context.Array.prototype,
|
||
objectProto = context.Object.prototype,
|
||
stringProto = context.String.prototype;
|
||
|
||
/** Used to resolve the decompiled source of functions. */
|
||
var funcToString = context.Function.prototype.toString;
|
||
|
||
/** Used to check objects for own properties. */
|
||
var hasOwnProperty = objectProto.hasOwnProperty;
|
||
|
||
/** Used to generate unique IDs. */
|
||
var idCounter = 0;
|
||
|
||
/** Used to infer the `Object` constructor. */
|
||
var objectCtorString = funcToString.call(Object);
|
||
|
||
/**
|
||
* Used to resolve the
|
||
* [`toStringTag`](http://ecma-international.org/ecma-262/6.0/#sec-object.prototype.tostring)
|
||
* of values.
|
||
*/
|
||
var objectToString = objectProto.toString;
|
||
|
||
/** Used to restore the original `_` reference in `_.noConflict`. */
|
||
var oldDash = root._;
|
||
|
||
/** Used to detect if a method is native. */
|
||
var reIsNative = RegExp('^' +
|
||
funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&')
|
||
.replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$'
|
||
);
|
||
|
||
/** Built-in value references. */
|
||
var Buffer = moduleExports ? context.Buffer : undefined,
|
||
Reflect = context.Reflect,
|
||
Symbol = context.Symbol,
|
||
Uint8Array = context.Uint8Array,
|
||
clearTimeout = context.clearTimeout,
|
||
enumerate = Reflect ? Reflect.enumerate : undefined,
|
||
getOwnPropertySymbols = Object.getOwnPropertySymbols,
|
||
iteratorSymbol = typeof (iteratorSymbol = Symbol && Symbol.iterator) == 'symbol' ? iteratorSymbol : undefined,
|
||
objectCreate = Object.create,
|
||
propertyIsEnumerable = objectProto.propertyIsEnumerable,
|
||
setTimeout = context.setTimeout,
|
||
splice = arrayProto.splice;
|
||
|
||
/* Built-in method references for those with the same name as other `lodash` methods. */
|
||
var nativeCeil = Math.ceil,
|
||
nativeFloor = Math.floor,
|
||
nativeGetPrototype = Object.getPrototypeOf,
|
||
nativeIsFinite = context.isFinite,
|
||
nativeJoin = arrayProto.join,
|
||
nativeKeys = Object.keys,
|
||
nativeMax = Math.max,
|
||
nativeMin = Math.min,
|
||
nativeParseInt = context.parseInt,
|
||
nativeRandom = Math.random,
|
||
nativeReplace = stringProto.replace,
|
||
nativeReverse = arrayProto.reverse,
|
||
nativeSplit = stringProto.split;
|
||
|
||
/* Built-in method references that are verified to be native. */
|
||
var DataView = getNative(context, 'DataView'),
|
||
Map = getNative(context, 'Map'),
|
||
Promise = getNative(context, 'Promise'),
|
||
Set = getNative(context, 'Set'),
|
||
WeakMap = getNative(context, 'WeakMap'),
|
||
nativeCreate = getNative(Object, 'create');
|
||
|
||
/** Used to store function metadata. */
|
||
var metaMap = WeakMap && new WeakMap;
|
||
|
||
/** Detect if properties shadowing those on `Object.prototype` are non-enumerable. */
|
||
var nonEnumShadows = !propertyIsEnumerable.call({ 'valueOf': 1 }, 'valueOf');
|
||
|
||
/** Used to lookup unminified function names. */
|
||
var realNames = {};
|
||
|
||
/** Used to detect maps, sets, and weakmaps. */
|
||
var dataViewCtorString = toSource(DataView),
|
||
mapCtorString = toSource(Map),
|
||
promiseCtorString = toSource(Promise),
|
||
setCtorString = toSource(Set),
|
||
weakMapCtorString = toSource(WeakMap);
|
||
|
||
/** Used to convert symbols to primitives and strings. */
|
||
var symbolProto = Symbol ? Symbol.prototype : undefined,
|
||
symbolValueOf = symbolProto ? symbolProto.valueOf : undefined,
|
||
symbolToString = symbolProto ? symbolProto.toString : undefined;
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Creates a `lodash` object which wraps `value` to enable implicit method
|
||
* chain sequences. Methods that operate on and return arrays, collections,
|
||
* and functions can be chained together. Methods that retrieve a single value
|
||
* or may return a primitive value will automatically end the chain sequence
|
||
* and return the unwrapped value. Otherwise, the value must be unwrapped
|
||
* with `_#value`.
|
||
*
|
||
* Explicit chain sequences, which must be unwrapped with `_#value`, may be
|
||
* enabled using `_.chain`.
|
||
*
|
||
* The execution of chained methods is lazy, that is, it's deferred until
|
||
* `_#value` is implicitly or explicitly called.
|
||
*
|
||
* Lazy evaluation allows several methods to support shortcut fusion.
|
||
* Shortcut fusion is an optimization to merge iteratee calls; this avoids
|
||
* the creation of intermediate arrays and can greatly reduce the number of
|
||
* iteratee executions. Sections of a chain sequence qualify for shortcut
|
||
* fusion if the section is applied to an array of at least `200` elements
|
||
* and any iteratees accept only one argument. The heuristic for whether a
|
||
* section qualifies for shortcut fusion is subject to change.
|
||
*
|
||
* Chaining is supported in custom builds as long as the `_#value` method is
|
||
* directly or indirectly included in the build.
|
||
*
|
||
* In addition to lodash methods, wrappers have `Array` and `String` methods.
|
||
*
|
||
* The wrapper `Array` methods are:
|
||
* `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift`
|
||
*
|
||
* The wrapper `String` methods are:
|
||
* `replace` and `split`
|
||
*
|
||
* The wrapper methods that support shortcut fusion are:
|
||
* `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`,
|
||
* `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`,
|
||
* `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray`
|
||
*
|
||
* The chainable wrapper methods are:
|
||
* `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`,
|
||
* `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`,
|
||
* `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`,
|
||
* `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`,
|
||
* `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`,
|
||
* `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`,
|
||
* `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`,
|
||
* `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`,
|
||
* `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`,
|
||
* `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`,
|
||
* `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`,
|
||
* `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`,
|
||
* `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`,
|
||
* `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`,
|
||
* `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`,
|
||
* `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`,
|
||
* `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`,
|
||
* `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`,
|
||
* `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`,
|
||
* `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`,
|
||
* `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`,
|
||
* `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`,
|
||
* `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`,
|
||
* `zipObject`, `zipObjectDeep`, and `zipWith`
|
||
*
|
||
* The wrapper methods that are **not** chainable by default are:
|
||
* `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`,
|
||
* `cloneDeep`, `cloneDeepWith`, `cloneWith`, `deburr`, `divide`, `each`,
|
||
* `eachRight`, `endsWith`, `eq`, `escape`, `escapeRegExp`, `every`, `find`,
|
||
* `findIndex`, `findKey`, `findLast`, `findLastIndex`, `findLastKey`, `first`,
|
||
* `floor`, `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`,
|
||
* `forOwnRight`, `get`, `gt`, `gte`, `has`, `hasIn`, `head`, `identity`,
|
||
* `includes`, `indexOf`, `inRange`, `invoke`, `isArguments`, `isArray`,
|
||
* `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, `isBoolean`, `isBuffer`,
|
||
* `isDate`, `isElement`, `isEmpty`, `isEqual`, `isEqualWith`, `isError`,
|
||
* `isFinite`, `isFunction`, `isInteger`, `isLength`, `isMap`, `isMatch`,
|
||
* `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, `isNumber`,
|
||
* `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, `isSafeInteger`,
|
||
* `isSet`, `isString`, `isUndefined`, `isTypedArray`, `isWeakMap`, `isWeakSet`,
|
||
* `join`, `kebabCase`, `last`, `lastIndexOf`, `lowerCase`, `lowerFirst`,
|
||
* `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, `min`, `minBy`, `multiply`,
|
||
* `noConflict`, `noop`, `now`, `nth`, `pad`, `padEnd`, `padStart`, `parseInt`,
|
||
* `pop`, `random`, `reduce`, `reduceRight`, `repeat`, `result`, `round`,
|
||
* `runInContext`, `sample`, `shift`, `size`, `snakeCase`, `some`, `sortedIndex`,
|
||
* `sortedIndexBy`, `sortedLastIndex`, `sortedLastIndexBy`, `startCase`,
|
||
* `startsWith`, `subtract`, `sum`, `sumBy`, `template`, `times`, `toInteger`,
|
||
* `toJSON`, `toLength`, `toLower`, `toNumber`, `toSafeInteger`, `toString`,
|
||
* `toUpper`, `trim`, `trimEnd`, `trimStart`, `truncate`, `unescape`,
|
||
* `uniqueId`, `upperCase`, `upperFirst`, `value`, and `words`
|
||
*
|
||
* @name _
|
||
* @constructor
|
||
* @category Seq
|
||
* @param {*} value The value to wrap in a `lodash` instance.
|
||
* @returns {Object} Returns the new `lodash` wrapper instance.
|
||
* @example
|
||
*
|
||
* function square(n) {
|
||
* return n * n;
|
||
* }
|
||
*
|
||
* var wrapped = _([1, 2, 3]);
|
||
*
|
||
* // Returns an unwrapped value.
|
||
* wrapped.reduce(_.add);
|
||
* // => 6
|
||
*
|
||
* // Returns a wrapped value.
|
||
* var squares = wrapped.map(square);
|
||
*
|
||
* _.isArray(squares);
|
||
* // => false
|
||
*
|
||
* _.isArray(squares.value());
|
||
* // => true
|
||
*/
|
||
function lodash(value) {
|
||
if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) {
|
||
if (value instanceof LodashWrapper) {
|
||
return value;
|
||
}
|
||
if (hasOwnProperty.call(value, '__wrapped__')) {
|
||
return wrapperClone(value);
|
||
}
|
||
}
|
||
return new LodashWrapper(value);
|
||
}
|
||
|
||
/**
|
||
* The function whose prototype chain sequence wrappers inherit from.
|
||
*
|
||
* @private
|
||
*/
|
||
function baseLodash() {
|
||
// No operation performed.
|
||
}
|
||
|
||
/**
|
||
* The base constructor for creating `lodash` wrapper objects.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to wrap.
|
||
* @param {boolean} [chainAll] Enable explicit method chain sequences.
|
||
*/
|
||
function LodashWrapper(value, chainAll) {
|
||
this.__wrapped__ = value;
|
||
this.__actions__ = [];
|
||
this.__chain__ = !!chainAll;
|
||
this.__index__ = 0;
|
||
this.__values__ = undefined;
|
||
}
|
||
|
||
/**
|
||
* By default, the template delimiters used by lodash are like 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': reEscape,
|
||
|
||
/**
|
||
* Used to detect code to be evaluated.
|
||
*
|
||
* @memberOf _.templateSettings
|
||
* @type {RegExp}
|
||
*/
|
||
'evaluate': reEvaluate,
|
||
|
||
/**
|
||
* 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
|
||
}
|
||
};
|
||
|
||
// Ensure wrappers are instances of `baseLodash`.
|
||
lodash.prototype = baseLodash.prototype;
|
||
lodash.prototype.constructor = lodash;
|
||
|
||
LodashWrapper.prototype = baseCreate(baseLodash.prototype);
|
||
LodashWrapper.prototype.constructor = LodashWrapper;
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Creates a lazy wrapper object which wraps `value` to enable lazy evaluation.
|
||
*
|
||
* @private
|
||
* @constructor
|
||
* @param {*} value The value to wrap.
|
||
*/
|
||
function LazyWrapper(value) {
|
||
this.__wrapped__ = value;
|
||
this.__actions__ = [];
|
||
this.__dir__ = 1;
|
||
this.__filtered__ = false;
|
||
this.__iteratees__ = [];
|
||
this.__takeCount__ = MAX_ARRAY_LENGTH;
|
||
this.__views__ = [];
|
||
}
|
||
|
||
/**
|
||
* Creates a clone of the lazy wrapper object.
|
||
*
|
||
* @private
|
||
* @name clone
|
||
* @memberOf LazyWrapper
|
||
* @returns {Object} Returns the cloned `LazyWrapper` object.
|
||
*/
|
||
function lazyClone() {
|
||
var result = new LazyWrapper(this.__wrapped__);
|
||
result.__actions__ = copyArray(this.__actions__);
|
||
result.__dir__ = this.__dir__;
|
||
result.__filtered__ = this.__filtered__;
|
||
result.__iteratees__ = copyArray(this.__iteratees__);
|
||
result.__takeCount__ = this.__takeCount__;
|
||
result.__views__ = copyArray(this.__views__);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Reverses the direction of lazy iteration.
|
||
*
|
||
* @private
|
||
* @name reverse
|
||
* @memberOf LazyWrapper
|
||
* @returns {Object} Returns the new reversed `LazyWrapper` object.
|
||
*/
|
||
function lazyReverse() {
|
||
if (this.__filtered__) {
|
||
var result = new LazyWrapper(this);
|
||
result.__dir__ = -1;
|
||
result.__filtered__ = true;
|
||
} else {
|
||
result = this.clone();
|
||
result.__dir__ *= -1;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Extracts the unwrapped value from its lazy wrapper.
|
||
*
|
||
* @private
|
||
* @name value
|
||
* @memberOf LazyWrapper
|
||
* @returns {*} Returns the unwrapped value.
|
||
*/
|
||
function lazyValue() {
|
||
var array = this.__wrapped__.value(),
|
||
dir = this.__dir__,
|
||
isArr = isArray(array),
|
||
isRight = dir < 0,
|
||
arrLength = isArr ? array.length : 0,
|
||
view = getView(0, arrLength, this.__views__),
|
||
start = view.start,
|
||
end = view.end,
|
||
length = end - start,
|
||
index = isRight ? end : (start - 1),
|
||
iteratees = this.__iteratees__,
|
||
iterLength = iteratees.length,
|
||
resIndex = 0,
|
||
takeCount = nativeMin(length, this.__takeCount__);
|
||
|
||
if (!isArr || arrLength < LARGE_ARRAY_SIZE ||
|
||
(arrLength == length && takeCount == length)) {
|
||
return baseWrapperValue(array, this.__actions__);
|
||
}
|
||
var result = [];
|
||
|
||
outer:
|
||
while (length-- && resIndex < takeCount) {
|
||
index += dir;
|
||
|
||
var iterIndex = -1,
|
||
value = array[index];
|
||
|
||
while (++iterIndex < iterLength) {
|
||
var data = iteratees[iterIndex],
|
||
iteratee = data.iteratee,
|
||
type = data.type,
|
||
computed = iteratee(value);
|
||
|
||
if (type == LAZY_MAP_FLAG) {
|
||
value = computed;
|
||
} else if (!computed) {
|
||
if (type == LAZY_FILTER_FLAG) {
|
||
continue outer;
|
||
} else {
|
||
break outer;
|
||
}
|
||
}
|
||
}
|
||
result[resIndex++] = value;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
// Ensure `LazyWrapper` is an instance of `baseLodash`.
|
||
LazyWrapper.prototype = baseCreate(baseLodash.prototype);
|
||
LazyWrapper.prototype.constructor = LazyWrapper;
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Creates a hash object.
|
||
*
|
||
* @private
|
||
* @constructor
|
||
* @returns {Object} Returns the new hash object.
|
||
*/
|
||
function Hash() {}
|
||
|
||
/**
|
||
* Removes `key` and its value from the hash.
|
||
*
|
||
* @private
|
||
* @param {Object} hash The hash to modify.
|
||
* @param {string} key The key of the value to remove.
|
||
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
|
||
*/
|
||
function hashDelete(hash, key) {
|
||
return hashHas(hash, key) && delete hash[key];
|
||
}
|
||
|
||
/**
|
||
* Gets the hash value for `key`.
|
||
*
|
||
* @private
|
||
* @param {Object} hash The hash to query.
|
||
* @param {string} key The key of the value to get.
|
||
* @returns {*} Returns the entry value.
|
||
*/
|
||
function hashGet(hash, key) {
|
||
if (nativeCreate) {
|
||
var result = hash[key];
|
||
return result === HASH_UNDEFINED ? undefined : result;
|
||
}
|
||
return hasOwnProperty.call(hash, key) ? hash[key] : undefined;
|
||
}
|
||
|
||
/**
|
||
* Checks if a hash value for `key` exists.
|
||
*
|
||
* @private
|
||
* @param {Object} hash The hash to query.
|
||
* @param {string} key The key of the entry to check.
|
||
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
|
||
*/
|
||
function hashHas(hash, key) {
|
||
return nativeCreate ? hash[key] !== undefined : hasOwnProperty.call(hash, key);
|
||
}
|
||
|
||
/**
|
||
* Sets the hash `key` to `value`.
|
||
*
|
||
* @private
|
||
* @param {Object} hash The hash to modify.
|
||
* @param {string} key The key of the value to set.
|
||
* @param {*} value The value to set.
|
||
*/
|
||
function hashSet(hash, key, value) {
|
||
hash[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value;
|
||
}
|
||
|
||
// Avoid inheriting from `Object.prototype` when possible.
|
||
Hash.prototype = nativeCreate ? nativeCreate(null) : objectProto;
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Creates a map cache object to store key-value pairs.
|
||
*
|
||
* @private
|
||
* @constructor
|
||
* @param {Array} [values] The values to cache.
|
||
*/
|
||
function MapCache(values) {
|
||
var index = -1,
|
||
length = values ? values.length : 0;
|
||
|
||
this.clear();
|
||
while (++index < length) {
|
||
var entry = values[index];
|
||
this.set(entry[0], entry[1]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Removes all key-value entries from the map.
|
||
*
|
||
* @private
|
||
* @name clear
|
||
* @memberOf MapCache
|
||
*/
|
||
function mapClear() {
|
||
this.__data__ = {
|
||
'hash': new Hash,
|
||
'map': Map ? new Map : [],
|
||
'string': new Hash
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Removes `key` and its value from the map.
|
||
*
|
||
* @private
|
||
* @name delete
|
||
* @memberOf MapCache
|
||
* @param {string} key The key of the value to remove.
|
||
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
|
||
*/
|
||
function mapDelete(key) {
|
||
var data = this.__data__;
|
||
if (isKeyable(key)) {
|
||
return hashDelete(typeof key == 'string' ? data.string : data.hash, key);
|
||
}
|
||
return Map ? data.map['delete'](key) : assocDelete(data.map, key);
|
||
}
|
||
|
||
/**
|
||
* Gets the map value for `key`.
|
||
*
|
||
* @private
|
||
* @name get
|
||
* @memberOf MapCache
|
||
* @param {string} key The key of the value to get.
|
||
* @returns {*} Returns the entry value.
|
||
*/
|
||
function mapGet(key) {
|
||
var data = this.__data__;
|
||
if (isKeyable(key)) {
|
||
return hashGet(typeof key == 'string' ? data.string : data.hash, key);
|
||
}
|
||
return Map ? data.map.get(key) : assocGet(data.map, key);
|
||
}
|
||
|
||
/**
|
||
* Checks if a map value for `key` exists.
|
||
*
|
||
* @private
|
||
* @name has
|
||
* @memberOf MapCache
|
||
* @param {string} key The key of the entry to check.
|
||
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
|
||
*/
|
||
function mapHas(key) {
|
||
var data = this.__data__;
|
||
if (isKeyable(key)) {
|
||
return hashHas(typeof key == 'string' ? data.string : data.hash, key);
|
||
}
|
||
return Map ? data.map.has(key) : assocHas(data.map, key);
|
||
}
|
||
|
||
/**
|
||
* Sets the map `key` to `value`.
|
||
*
|
||
* @private
|
||
* @name set
|
||
* @memberOf MapCache
|
||
* @param {string} key The key of the value to set.
|
||
* @param {*} value The value to set.
|
||
* @returns {Object} Returns the map cache instance.
|
||
*/
|
||
function mapSet(key, value) {
|
||
var data = this.__data__;
|
||
if (isKeyable(key)) {
|
||
hashSet(typeof key == 'string' ? data.string : data.hash, key, value);
|
||
} else if (Map) {
|
||
data.map.set(key, value);
|
||
} else {
|
||
assocSet(data.map, key, value);
|
||
}
|
||
return this;
|
||
}
|
||
|
||
// Add methods to `MapCache`.
|
||
MapCache.prototype.clear = mapClear;
|
||
MapCache.prototype['delete'] = mapDelete;
|
||
MapCache.prototype.get = mapGet;
|
||
MapCache.prototype.has = mapHas;
|
||
MapCache.prototype.set = mapSet;
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
*
|
||
* Creates a set cache object to store unique values.
|
||
*
|
||
* @private
|
||
* @constructor
|
||
* @param {Array} [values] The values to cache.
|
||
*/
|
||
function SetCache(values) {
|
||
var index = -1,
|
||
length = values ? values.length : 0;
|
||
|
||
this.__data__ = new MapCache;
|
||
while (++index < length) {
|
||
this.push(values[index]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is in `cache`.
|
||
*
|
||
* @private
|
||
* @param {Object} cache The set cache to search.
|
||
* @param {*} value The value to search for.
|
||
* @returns {number} Returns `true` if `value` is found, else `false`.
|
||
*/
|
||
function cacheHas(cache, value) {
|
||
var map = cache.__data__;
|
||
if (isKeyable(value)) {
|
||
var data = map.__data__,
|
||
hash = typeof value == 'string' ? data.string : data.hash;
|
||
|
||
return hash[value] === HASH_UNDEFINED;
|
||
}
|
||
return map.has(value);
|
||
}
|
||
|
||
/**
|
||
* Adds `value` to the set cache.
|
||
*
|
||
* @private
|
||
* @name push
|
||
* @memberOf SetCache
|
||
* @param {*} value The value to cache.
|
||
*/
|
||
function cachePush(value) {
|
||
var map = this.__data__;
|
||
if (isKeyable(value)) {
|
||
var data = map.__data__,
|
||
hash = typeof value == 'string' ? data.string : data.hash;
|
||
|
||
hash[value] = HASH_UNDEFINED;
|
||
}
|
||
else {
|
||
map.set(value, HASH_UNDEFINED);
|
||
}
|
||
}
|
||
|
||
// Add methods to `SetCache`.
|
||
SetCache.prototype.push = cachePush;
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Creates a stack cache object to store key-value pairs.
|
||
*
|
||
* @private
|
||
* @constructor
|
||
* @param {Array} [values] The values to cache.
|
||
*/
|
||
function Stack(values) {
|
||
var index = -1,
|
||
length = values ? values.length : 0;
|
||
|
||
this.clear();
|
||
while (++index < length) {
|
||
var entry = values[index];
|
||
this.set(entry[0], entry[1]);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Removes all key-value entries from the stack.
|
||
*
|
||
* @private
|
||
* @name clear
|
||
* @memberOf Stack
|
||
*/
|
||
function stackClear() {
|
||
this.__data__ = { 'array': [], 'map': null };
|
||
}
|
||
|
||
/**
|
||
* Removes `key` and its value from the stack.
|
||
*
|
||
* @private
|
||
* @name delete
|
||
* @memberOf Stack
|
||
* @param {string} key The key of the value to remove.
|
||
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
|
||
*/
|
||
function stackDelete(key) {
|
||
var data = this.__data__,
|
||
array = data.array;
|
||
|
||
return array ? assocDelete(array, key) : data.map['delete'](key);
|
||
}
|
||
|
||
/**
|
||
* Gets the stack value for `key`.
|
||
*
|
||
* @private
|
||
* @name get
|
||
* @memberOf Stack
|
||
* @param {string} key The key of the value to get.
|
||
* @returns {*} Returns the entry value.
|
||
*/
|
||
function stackGet(key) {
|
||
var data = this.__data__,
|
||
array = data.array;
|
||
|
||
return array ? assocGet(array, key) : data.map.get(key);
|
||
}
|
||
|
||
/**
|
||
* Checks if a stack value for `key` exists.
|
||
*
|
||
* @private
|
||
* @name has
|
||
* @memberOf Stack
|
||
* @param {string} key The key of the entry to check.
|
||
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
|
||
*/
|
||
function stackHas(key) {
|
||
var data = this.__data__,
|
||
array = data.array;
|
||
|
||
return array ? assocHas(array, key) : data.map.has(key);
|
||
}
|
||
|
||
/**
|
||
* Sets the stack `key` to `value`.
|
||
*
|
||
* @private
|
||
* @name set
|
||
* @memberOf Stack
|
||
* @param {string} key The key of the value to set.
|
||
* @param {*} value The value to set.
|
||
* @returns {Object} Returns the stack cache instance.
|
||
*/
|
||
function stackSet(key, value) {
|
||
var data = this.__data__,
|
||
array = data.array;
|
||
|
||
if (array) {
|
||
if (array.length < (LARGE_ARRAY_SIZE - 1)) {
|
||
assocSet(array, key, value);
|
||
} else {
|
||
data.array = null;
|
||
data.map = new MapCache(array);
|
||
}
|
||
}
|
||
var map = data.map;
|
||
if (map) {
|
||
map.set(key, value);
|
||
}
|
||
return this;
|
||
}
|
||
|
||
// Add methods to `Stack`.
|
||
Stack.prototype.clear = stackClear;
|
||
Stack.prototype['delete'] = stackDelete;
|
||
Stack.prototype.get = stackGet;
|
||
Stack.prototype.has = stackHas;
|
||
Stack.prototype.set = stackSet;
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Removes `key` and its value from the associative array.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to modify.
|
||
* @param {string} key The key of the value to remove.
|
||
* @returns {boolean} Returns `true` if the entry was removed, else `false`.
|
||
*/
|
||
function assocDelete(array, key) {
|
||
var index = assocIndexOf(array, key);
|
||
if (index < 0) {
|
||
return false;
|
||
}
|
||
var lastIndex = array.length - 1;
|
||
if (index == lastIndex) {
|
||
array.pop();
|
||
} else {
|
||
splice.call(array, index, 1);
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* Gets the associative array value for `key`.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to query.
|
||
* @param {string} key The key of the value to get.
|
||
* @returns {*} Returns the entry value.
|
||
*/
|
||
function assocGet(array, key) {
|
||
var index = assocIndexOf(array, key);
|
||
return index < 0 ? undefined : array[index][1];
|
||
}
|
||
|
||
/**
|
||
* Checks if an associative array value for `key` exists.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to query.
|
||
* @param {string} key The key of the entry to check.
|
||
* @returns {boolean} Returns `true` if an entry for `key` exists, else `false`.
|
||
*/
|
||
function assocHas(array, key) {
|
||
return assocIndexOf(array, key) > -1;
|
||
}
|
||
|
||
/**
|
||
* Gets the index at which the `key` is found in `array` of key-value pairs.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to search.
|
||
* @param {*} key The key to search for.
|
||
* @returns {number} Returns the index of the matched value, else `-1`.
|
||
*/
|
||
function assocIndexOf(array, key) {
|
||
var length = array.length;
|
||
while (length--) {
|
||
if (eq(array[length][0], key)) {
|
||
return length;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* Sets the associative array `key` to `value`.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to modify.
|
||
* @param {string} key The key of the value to set.
|
||
* @param {*} value The value to set.
|
||
*/
|
||
function assocSet(array, key, value) {
|
||
var index = assocIndexOf(array, key);
|
||
if (index < 0) {
|
||
array.push([key, value]);
|
||
} else {
|
||
array[index][1] = value;
|
||
}
|
||
}
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Used by `_.defaults` to customize its `_.assignIn` use.
|
||
*
|
||
* @private
|
||
* @param {*} objValue The destination value.
|
||
* @param {*} srcValue The source value.
|
||
* @param {string} key The key of the property to assign.
|
||
* @param {Object} object The parent object of `objValue`.
|
||
* @returns {*} Returns the value to assign.
|
||
*/
|
||
function assignInDefaults(objValue, srcValue, key, object) {
|
||
if (objValue === undefined ||
|
||
(eq(objValue, objectProto[key]) && !hasOwnProperty.call(object, key))) {
|
||
return srcValue;
|
||
}
|
||
return objValue;
|
||
}
|
||
|
||
/**
|
||
* This function is like `assignValue` except that it doesn't assign
|
||
* `undefined` values.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to modify.
|
||
* @param {string} key The key of the property to assign.
|
||
* @param {*} value The value to assign.
|
||
*/
|
||
function assignMergeValue(object, key, value) {
|
||
if ((value !== undefined && !eq(object[key], value)) ||
|
||
(typeof key == 'number' && value === undefined && !(key in object))) {
|
||
object[key] = value;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Assigns `value` to `key` of `object` if the existing value is not equivalent
|
||
* using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
|
||
* for equality comparisons.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to modify.
|
||
* @param {string} key The key of the property to assign.
|
||
* @param {*} value The value to assign.
|
||
*/
|
||
function assignValue(object, key, value) {
|
||
var objValue = object[key];
|
||
if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) ||
|
||
(value === undefined && !(key in object))) {
|
||
object[key] = value;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Aggregates elements of `collection` on `accumulator` with keys transformed
|
||
* by `iteratee` and values set by `setter`.
|
||
*
|
||
* @private
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Function} setter The function to set `accumulator` values.
|
||
* @param {Function} iteratee The iteratee to transform keys.
|
||
* @param {Object} accumulator The initial aggregated object.
|
||
* @returns {Function} Returns `accumulator`.
|
||
*/
|
||
function baseAggregator(collection, setter, iteratee, accumulator) {
|
||
baseEach(collection, function(value, key, collection) {
|
||
setter(accumulator, value, iteratee(value), collection);
|
||
});
|
||
return accumulator;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.assign` without support for multiple sources
|
||
* or `customizer` functions.
|
||
*
|
||
* @private
|
||
* @param {Object} object The destination object.
|
||
* @param {Object} source The source object.
|
||
* @returns {Object} Returns `object`.
|
||
*/
|
||
function baseAssign(object, source) {
|
||
return object && copyObject(source, keys(source), object);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.at` without support for individual paths.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to iterate over.
|
||
* @param {string[]} paths The property paths of elements to pick.
|
||
* @returns {Array} Returns the new array of picked elements.
|
||
*/
|
||
function baseAt(object, paths) {
|
||
var index = -1,
|
||
isNil = object == null,
|
||
length = paths.length,
|
||
result = Array(length);
|
||
|
||
while (++index < length) {
|
||
result[index] = isNil ? undefined : get(object, paths[index]);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.clamp` which doesn't coerce arguments to numbers.
|
||
*
|
||
* @private
|
||
* @param {number} number The number to clamp.
|
||
* @param {number} [lower] The lower bound.
|
||
* @param {number} upper The upper bound.
|
||
* @returns {number} Returns the clamped number.
|
||
*/
|
||
function baseClamp(number, lower, upper) {
|
||
if (number === number) {
|
||
if (upper !== undefined) {
|
||
number = number <= upper ? number : upper;
|
||
}
|
||
if (lower !== undefined) {
|
||
number = number >= lower ? number : lower;
|
||
}
|
||
}
|
||
return number;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.clone` and `_.cloneDeep` which tracks
|
||
* traversed objects.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to clone.
|
||
* @param {boolean} [isDeep] Specify a deep clone.
|
||
* @param {boolean} [isFull] Specify a clone including symbols.
|
||
* @param {Function} [customizer] The function to customize cloning.
|
||
* @param {string} [key] The key of `value`.
|
||
* @param {Object} [object] The parent object of `value`.
|
||
* @param {Object} [stack] Tracks traversed objects and their clone counterparts.
|
||
* @returns {*} Returns the cloned value.
|
||
*/
|
||
function baseClone(value, isDeep, isFull, customizer, key, object, stack) {
|
||
var result;
|
||
if (customizer) {
|
||
result = object ? customizer(value, key, object, stack) : customizer(value);
|
||
}
|
||
if (result !== undefined) {
|
||
return result;
|
||
}
|
||
if (!isObject(value)) {
|
||
return value;
|
||
}
|
||
var isArr = isArray(value);
|
||
if (isArr) {
|
||
result = initCloneArray(value);
|
||
if (!isDeep) {
|
||
return copyArray(value, result);
|
||
}
|
||
} else {
|
||
var tag = getTag(value),
|
||
isFunc = tag == funcTag || tag == genTag;
|
||
|
||
if (isBuffer(value)) {
|
||
return cloneBuffer(value, isDeep);
|
||
}
|
||
if (tag == objectTag || tag == argsTag || (isFunc && !object)) {
|
||
if (isHostObject(value)) {
|
||
return object ? value : {};
|
||
}
|
||
result = initCloneObject(isFunc ? {} : value);
|
||
if (!isDeep) {
|
||
return copySymbols(value, baseAssign(result, value));
|
||
}
|
||
} else {
|
||
if (!cloneableTags[tag]) {
|
||
return object ? value : {};
|
||
}
|
||
result = initCloneByTag(value, tag, baseClone, isDeep);
|
||
}
|
||
}
|
||
// Check for circular references and return its corresponding clone.
|
||
stack || (stack = new Stack);
|
||
var stacked = stack.get(value);
|
||
if (stacked) {
|
||
return stacked;
|
||
}
|
||
stack.set(value, result);
|
||
|
||
if (!isArr) {
|
||
var props = isFull ? getAllKeys(value) : keys(value);
|
||
}
|
||
// Recursively populate clone (susceptible to call stack limits).
|
||
arrayEach(props || value, function(subValue, key) {
|
||
if (props) {
|
||
key = subValue;
|
||
subValue = value[key];
|
||
}
|
||
assignValue(result, key, baseClone(subValue, isDeep, isFull, customizer, key, value, stack));
|
||
});
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.conforms` which doesn't clone `source`.
|
||
*
|
||
* @private
|
||
* @param {Object} source The object of property predicates to conform to.
|
||
* @returns {Function} Returns the new function.
|
||
*/
|
||
function baseConforms(source) {
|
||
var props = keys(source),
|
||
length = props.length;
|
||
|
||
return function(object) {
|
||
if (object == null) {
|
||
return !length;
|
||
}
|
||
var index = length;
|
||
while (index--) {
|
||
var key = props[index],
|
||
predicate = source[key],
|
||
value = object[key];
|
||
|
||
if ((value === undefined &&
|
||
!(key in Object(object))) || !predicate(value)) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
};
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.create` without support for assigning
|
||
* properties to the created object.
|
||
*
|
||
* @private
|
||
* @param {Object} prototype The object to inherit from.
|
||
* @returns {Object} Returns the new object.
|
||
*/
|
||
function baseCreate(proto) {
|
||
return isObject(proto) ? objectCreate(proto) : {};
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.delay` and `_.defer` which accepts an array
|
||
* of `func` arguments.
|
||
*
|
||
* @private
|
||
* @param {Function} func The function to delay.
|
||
* @param {number} wait The number of milliseconds to delay invocation.
|
||
* @param {Object} args The arguments to provide to `func`.
|
||
* @returns {number} Returns the timer id.
|
||
*/
|
||
function baseDelay(func, wait, args) {
|
||
if (typeof func != 'function') {
|
||
throw new TypeError(FUNC_ERROR_TEXT);
|
||
}
|
||
return setTimeout(function() { func.apply(undefined, args); }, wait);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of methods like `_.difference` without support
|
||
* for excluding multiple arrays or iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to inspect.
|
||
* @param {Array} values The values to exclude.
|
||
* @param {Function} [iteratee] The iteratee invoked per element.
|
||
* @param {Function} [comparator] The comparator invoked per element.
|
||
* @returns {Array} Returns the new array of filtered values.
|
||
*/
|
||
function baseDifference(array, values, iteratee, comparator) {
|
||
var index = -1,
|
||
includes = arrayIncludes,
|
||
isCommon = true,
|
||
length = array.length,
|
||
result = [],
|
||
valuesLength = values.length;
|
||
|
||
if (!length) {
|
||
return result;
|
||
}
|
||
if (iteratee) {
|
||
values = arrayMap(values, baseUnary(iteratee));
|
||
}
|
||
if (comparator) {
|
||
includes = arrayIncludesWith;
|
||
isCommon = false;
|
||
}
|
||
else if (values.length >= LARGE_ARRAY_SIZE) {
|
||
includes = cacheHas;
|
||
isCommon = false;
|
||
values = new SetCache(values);
|
||
}
|
||
outer:
|
||
while (++index < length) {
|
||
var value = array[index],
|
||
computed = iteratee ? iteratee(value) : value;
|
||
|
||
if (isCommon && computed === computed) {
|
||
var valuesIndex = valuesLength;
|
||
while (valuesIndex--) {
|
||
if (values[valuesIndex] === computed) {
|
||
continue outer;
|
||
}
|
||
}
|
||
result.push(value);
|
||
}
|
||
else if (!includes(values, computed, comparator)) {
|
||
result.push(value);
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.forEach` without support for iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @returns {Array|Object} Returns `collection`.
|
||
*/
|
||
var baseEach = createBaseEach(baseForOwn);
|
||
|
||
/**
|
||
* The base implementation of `_.forEachRight` without support for iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @returns {Array|Object} Returns `collection`.
|
||
*/
|
||
var baseEachRight = createBaseEach(baseForOwnRight, true);
|
||
|
||
/**
|
||
* The base implementation of `_.every` without support for iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Function} predicate The function invoked per iteration.
|
||
* @returns {boolean} Returns `true` if all elements pass the predicate check,
|
||
* else `false`
|
||
*/
|
||
function baseEvery(collection, predicate) {
|
||
var result = true;
|
||
baseEach(collection, function(value, index, collection) {
|
||
result = !!predicate(value, index, collection);
|
||
return result;
|
||
});
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.fill` without an iteratee call guard.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to fill.
|
||
* @param {*} value The value to fill `array` with.
|
||
* @param {number} [start=0] The start position.
|
||
* @param {number} [end=array.length] The end position.
|
||
* @returns {Array} Returns `array`.
|
||
*/
|
||
function baseFill(array, value, start, end) {
|
||
var length = array.length;
|
||
|
||
start = toInteger(start);
|
||
if (start < 0) {
|
||
start = -start > length ? 0 : (length + start);
|
||
}
|
||
end = (end === undefined || end > length) ? length : toInteger(end);
|
||
if (end < 0) {
|
||
end += length;
|
||
}
|
||
end = start > end ? 0 : toLength(end);
|
||
while (start < end) {
|
||
array[start++] = value;
|
||
}
|
||
return array;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.filter` without support for iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Function} predicate The function invoked per iteration.
|
||
* @returns {Array} Returns the new filtered array.
|
||
*/
|
||
function baseFilter(collection, predicate) {
|
||
var result = [];
|
||
baseEach(collection, function(value, index, collection) {
|
||
if (predicate(value, index, collection)) {
|
||
result.push(value);
|
||
}
|
||
});
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.flatten` with support for restricting flattening.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to flatten.
|
||
* @param {number} depth The maximum recursion depth.
|
||
* @param {boolean} [predicate=isFlattenable] The function invoked per iteration.
|
||
* @param {boolean} [isStrict] Restrict to values that pass `predicate` checks.
|
||
* @param {Array} [result=[]] The initial result value.
|
||
* @returns {Array} Returns the new flattened array.
|
||
*/
|
||
function baseFlatten(array, depth, predicate, isStrict, result) {
|
||
var index = -1,
|
||
length = array.length;
|
||
|
||
predicate || (predicate = isFlattenable);
|
||
result || (result = []);
|
||
|
||
while (++index < length) {
|
||
var value = array[index];
|
||
if (depth > 0 && predicate(value)) {
|
||
if (depth > 1) {
|
||
// Recursively flatten arrays (susceptible to call stack limits).
|
||
baseFlatten(value, depth - 1, predicate, isStrict, result);
|
||
} else {
|
||
arrayPush(result, value);
|
||
}
|
||
} else if (!isStrict) {
|
||
result[result.length] = value;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `baseForOwn` which iterates over `object`
|
||
* properties returned by `keysFunc` and invokes `iteratee` for each property.
|
||
* Iteratee functions may exit iteration early by explicitly returning `false`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to iterate over.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @param {Function} keysFunc The function to get the keys of `object`.
|
||
* @returns {Object} Returns `object`.
|
||
*/
|
||
var baseFor = createBaseFor();
|
||
|
||
/**
|
||
* This function is like `baseFor` except that it iterates over properties
|
||
* in the opposite order.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to iterate over.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @param {Function} keysFunc The function to get the keys of `object`.
|
||
* @returns {Object} Returns `object`.
|
||
*/
|
||
var baseForRight = createBaseFor(true);
|
||
|
||
/**
|
||
* The base implementation of `_.forOwn` without support for iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to iterate over.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @returns {Object} Returns `object`.
|
||
*/
|
||
function baseForOwn(object, iteratee) {
|
||
return object && baseFor(object, iteratee, keys);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.forOwnRight` without support for iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to iterate over.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @returns {Object} Returns `object`.
|
||
*/
|
||
function baseForOwnRight(object, iteratee) {
|
||
return object && baseForRight(object, iteratee, keys);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.functions` which creates an array of
|
||
* `object` function property names filtered from `props`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to inspect.
|
||
* @param {Array} props The property names to filter.
|
||
* @returns {Array} Returns the new array of filtered property names.
|
||
*/
|
||
function baseFunctions(object, props) {
|
||
return arrayFilter(props, function(key) {
|
||
return isFunction(object[key]);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.get` without support for default values.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @param {Array|string} path The path of the property to get.
|
||
* @returns {*} Returns the resolved value.
|
||
*/
|
||
function baseGet(object, path) {
|
||
path = isKey(path, object) ? [path] : castPath(path);
|
||
|
||
var index = 0,
|
||
length = path.length;
|
||
|
||
while (object != null && index < length) {
|
||
object = object[path[index++]];
|
||
}
|
||
return (index && index == length) ? object : undefined;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `getAllKeys` and `getAllKeysIn` which uses
|
||
* `keysFunc` and `symbolsFunc` to get the enumerable property names and
|
||
* symbols of `object`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @param {Function} keysFunc The function to get the keys of `object`.
|
||
* @param {Function} symbolsFunc The function to get the symbols of `object`.
|
||
* @returns {Array} Returns the array of property names and symbols.
|
||
*/
|
||
function baseGetAllKeys(object, keysFunc, symbolsFunc) {
|
||
var result = keysFunc(object);
|
||
return isArray(object)
|
||
? result
|
||
: arrayPush(result, symbolsFunc(object));
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.has` without support for deep paths.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @param {Array|string} key The key to check.
|
||
* @returns {boolean} Returns `true` if `key` exists, else `false`.
|
||
*/
|
||
function baseHas(object, key) {
|
||
// Avoid a bug in IE 10-11 where objects with a [[Prototype]] of `null`,
|
||
// that are composed entirely of index properties, return `false` for
|
||
// `hasOwnProperty` checks of them.
|
||
return hasOwnProperty.call(object, key) ||
|
||
(typeof object == 'object' && key in object && getPrototype(object) === null);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.hasIn` without support for deep paths.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @param {Array|string} key The key to check.
|
||
* @returns {boolean} Returns `true` if `key` exists, else `false`.
|
||
*/
|
||
function baseHasIn(object, key) {
|
||
return key in Object(object);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.inRange` which doesn't coerce arguments to numbers.
|
||
*
|
||
* @private
|
||
* @param {number} number The number to check.
|
||
* @param {number} start The start of the range.
|
||
* @param {number} end The end of the range.
|
||
* @returns {boolean} Returns `true` if `number` is in the range, else `false`.
|
||
*/
|
||
function baseInRange(number, start, end) {
|
||
return number >= nativeMin(start, end) && number < nativeMax(start, end);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of methods like `_.intersection`, without support
|
||
* for iteratee shorthands, that accepts an array of arrays to inspect.
|
||
*
|
||
* @private
|
||
* @param {Array} arrays The arrays to inspect.
|
||
* @param {Function} [iteratee] The iteratee invoked per element.
|
||
* @param {Function} [comparator] The comparator invoked per element.
|
||
* @returns {Array} Returns the new array of shared values.
|
||
*/
|
||
function baseIntersection(arrays, iteratee, comparator) {
|
||
var includes = comparator ? arrayIncludesWith : arrayIncludes,
|
||
length = arrays[0].length,
|
||
othLength = arrays.length,
|
||
othIndex = othLength,
|
||
caches = Array(othLength),
|
||
maxLength = Infinity,
|
||
result = [];
|
||
|
||
while (othIndex--) {
|
||
var array = arrays[othIndex];
|
||
if (othIndex && iteratee) {
|
||
array = arrayMap(array, baseUnary(iteratee));
|
||
}
|
||
maxLength = nativeMin(array.length, maxLength);
|
||
caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120))
|
||
? new SetCache(othIndex && array)
|
||
: undefined;
|
||
}
|
||
array = arrays[0];
|
||
|
||
var index = -1,
|
||
seen = caches[0];
|
||
|
||
outer:
|
||
while (++index < length && result.length < maxLength) {
|
||
var value = array[index],
|
||
computed = iteratee ? iteratee(value) : value;
|
||
|
||
if (!(seen
|
||
? cacheHas(seen, computed)
|
||
: includes(result, computed, comparator)
|
||
)) {
|
||
othIndex = othLength;
|
||
while (--othIndex) {
|
||
var cache = caches[othIndex];
|
||
if (!(cache
|
||
? cacheHas(cache, computed)
|
||
: includes(arrays[othIndex], computed, comparator))
|
||
) {
|
||
continue outer;
|
||
}
|
||
}
|
||
if (seen) {
|
||
seen.push(computed);
|
||
}
|
||
result.push(value);
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.invert` and `_.invertBy` which inverts
|
||
* `object` with values transformed by `iteratee` and set by `setter`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to iterate over.
|
||
* @param {Function} setter The function to set `accumulator` values.
|
||
* @param {Function} iteratee The iteratee to transform values.
|
||
* @param {Object} accumulator The initial inverted object.
|
||
* @returns {Function} Returns `accumulator`.
|
||
*/
|
||
function baseInverter(object, setter, iteratee, accumulator) {
|
||
baseForOwn(object, function(value, key, object) {
|
||
setter(accumulator, iteratee(value), key, object);
|
||
});
|
||
return accumulator;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.invoke` without support for individual
|
||
* method arguments.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @param {Array|string} path The path of the method to invoke.
|
||
* @param {Array} args The arguments to invoke the method with.
|
||
* @returns {*} Returns the result of the invoked method.
|
||
*/
|
||
function baseInvoke(object, path, args) {
|
||
if (!isKey(path, object)) {
|
||
path = castPath(path);
|
||
object = parent(object, path);
|
||
path = last(path);
|
||
}
|
||
var func = object == null ? object : object[path];
|
||
return func == null ? undefined : apply(func, object, args);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.isEqual` which supports partial comparisons
|
||
* and tracks traversed objects.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to compare.
|
||
* @param {*} other The other value to compare.
|
||
* @param {Function} [customizer] The function to customize comparisons.
|
||
* @param {boolean} [bitmask] The bitmask of comparison flags.
|
||
* The bitmask may be composed of the following flags:
|
||
* 1 - Unordered comparison
|
||
* 2 - Partial comparison
|
||
* @param {Object} [stack] Tracks traversed `value` and `other` objects.
|
||
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
|
||
*/
|
||
function baseIsEqual(value, other, customizer, bitmask, stack) {
|
||
if (value === other) {
|
||
return true;
|
||
}
|
||
if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) {
|
||
return value !== value && other !== other;
|
||
}
|
||
return baseIsEqualDeep(value, other, baseIsEqual, customizer, bitmask, stack);
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `baseIsEqual` for arrays and objects which performs
|
||
* deep comparisons and tracks traversed objects enabling objects with circular
|
||
* references to be compared.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to compare.
|
||
* @param {Object} other The other object to compare.
|
||
* @param {Function} equalFunc The function to determine equivalents of values.
|
||
* @param {Function} [customizer] The function to customize comparisons.
|
||
* @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual`
|
||
* for more details.
|
||
* @param {Object} [stack] Tracks traversed `object` and `other` objects.
|
||
* @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
|
||
*/
|
||
function baseIsEqualDeep(object, other, equalFunc, customizer, bitmask, stack) {
|
||
var objIsArr = isArray(object),
|
||
othIsArr = isArray(other),
|
||
objTag = arrayTag,
|
||
othTag = arrayTag;
|
||
|
||
if (!objIsArr) {
|
||
objTag = getTag(object);
|
||
objTag = objTag == argsTag ? objectTag : objTag;
|
||
}
|
||
if (!othIsArr) {
|
||
othTag = getTag(other);
|
||
othTag = othTag == argsTag ? objectTag : othTag;
|
||
}
|
||
var objIsObj = objTag == objectTag && !isHostObject(object),
|
||
othIsObj = othTag == objectTag && !isHostObject(other),
|
||
isSameTag = objTag == othTag;
|
||
|
||
if (isSameTag && !objIsObj) {
|
||
stack || (stack = new Stack);
|
||
return (objIsArr || isTypedArray(object))
|
||
? equalArrays(object, other, equalFunc, customizer, bitmask, stack)
|
||
: equalByTag(object, other, objTag, equalFunc, customizer, bitmask, stack);
|
||
}
|
||
if (!(bitmask & PARTIAL_COMPARE_FLAG)) {
|
||
var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'),
|
||
othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__');
|
||
|
||
if (objIsWrapped || othIsWrapped) {
|
||
var objUnwrapped = objIsWrapped ? object.value() : object,
|
||
othUnwrapped = othIsWrapped ? other.value() : other;
|
||
|
||
stack || (stack = new Stack);
|
||
return equalFunc(objUnwrapped, othUnwrapped, customizer, bitmask, stack);
|
||
}
|
||
}
|
||
if (!isSameTag) {
|
||
return false;
|
||
}
|
||
stack || (stack = new Stack);
|
||
return equalObjects(object, other, equalFunc, customizer, bitmask, stack);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.isMatch` without support for iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to inspect.
|
||
* @param {Object} source The object of property values to match.
|
||
* @param {Array} matchData The property names, values, and compare flags to match.
|
||
* @param {Function} [customizer] The function to customize comparisons.
|
||
* @returns {boolean} Returns `true` if `object` is a match, else `false`.
|
||
*/
|
||
function baseIsMatch(object, source, matchData, customizer) {
|
||
var index = matchData.length,
|
||
length = index,
|
||
noCustomizer = !customizer;
|
||
|
||
if (object == null) {
|
||
return !length;
|
||
}
|
||
object = Object(object);
|
||
while (index--) {
|
||
var data = matchData[index];
|
||
if ((noCustomizer && data[2])
|
||
? data[1] !== object[data[0]]
|
||
: !(data[0] in object)
|
||
) {
|
||
return false;
|
||
}
|
||
}
|
||
while (++index < length) {
|
||
data = matchData[index];
|
||
var key = data[0],
|
||
objValue = object[key],
|
||
srcValue = data[1];
|
||
|
||
if (noCustomizer && data[2]) {
|
||
if (objValue === undefined && !(key in object)) {
|
||
return false;
|
||
}
|
||
} else {
|
||
var stack = new Stack;
|
||
if (customizer) {
|
||
var result = customizer(objValue, srcValue, key, object, source, stack);
|
||
}
|
||
if (!(result === undefined
|
||
? baseIsEqual(srcValue, objValue, customizer, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG, stack)
|
||
: result
|
||
)) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
return true;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.iteratee`.
|
||
*
|
||
* @private
|
||
* @param {*} [value=_.identity] The value to convert to an iteratee.
|
||
* @returns {Function} Returns the iteratee.
|
||
*/
|
||
function baseIteratee(value) {
|
||
// Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9.
|
||
// See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details.
|
||
if (typeof value == 'function') {
|
||
return value;
|
||
}
|
||
if (value == null) {
|
||
return identity;
|
||
}
|
||
if (typeof value == 'object') {
|
||
return isArray(value)
|
||
? baseMatchesProperty(value[0], value[1])
|
||
: baseMatches(value);
|
||
}
|
||
return property(value);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.keys` which doesn't skip the constructor
|
||
* property of prototypes or treat sparse arrays as dense.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @returns {Array} Returns the array of property names.
|
||
*/
|
||
function baseKeys(object) {
|
||
return nativeKeys(Object(object));
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.keysIn` which doesn't skip the constructor
|
||
* property of prototypes or treat sparse arrays as dense.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @returns {Array} Returns the array of property names.
|
||
*/
|
||
function baseKeysIn(object) {
|
||
object = object == null ? object : Object(object);
|
||
|
||
var result = [];
|
||
for (var key in object) {
|
||
result.push(key);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
// Fallback for IE < 9 with es6-shim.
|
||
if (enumerate && !propertyIsEnumerable.call({ 'valueOf': 1 }, 'valueOf')) {
|
||
baseKeysIn = function(object) {
|
||
return iteratorToArray(enumerate(object));
|
||
};
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.map` without support for iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Function} iteratee The function invoked per iteration.
|
||
* @returns {Array} Returns the new mapped array.
|
||
*/
|
||
function baseMap(collection, iteratee) {
|
||
var index = -1,
|
||
result = isArrayLike(collection) ? Array(collection.length) : [];
|
||
|
||
baseEach(collection, function(value, key, collection) {
|
||
result[++index] = iteratee(value, key, collection);
|
||
});
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.matches` which doesn't clone `source`.
|
||
*
|
||
* @private
|
||
* @param {Object} source The object of property values to match.
|
||
* @returns {Function} Returns the new function.
|
||
*/
|
||
function baseMatches(source) {
|
||
var matchData = getMatchData(source);
|
||
if (matchData.length == 1 && matchData[0][2]) {
|
||
return matchesStrictComparable(matchData[0][0], matchData[0][1]);
|
||
}
|
||
return function(object) {
|
||
return object === source || baseIsMatch(object, source, matchData);
|
||
};
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.matchesProperty` which doesn't clone `srcValue`.
|
||
*
|
||
* @private
|
||
* @param {string} path The path of the property to get.
|
||
* @param {*} srcValue The value to match.
|
||
* @returns {Function} Returns the new function.
|
||
*/
|
||
function baseMatchesProperty(path, srcValue) {
|
||
if (isKey(path) && isStrictComparable(srcValue)) {
|
||
return matchesStrictComparable(path, srcValue);
|
||
}
|
||
return function(object) {
|
||
var objValue = get(object, path);
|
||
return (objValue === undefined && objValue === srcValue)
|
||
? hasIn(object, path)
|
||
: baseIsEqual(srcValue, objValue, undefined, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG);
|
||
};
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.merge` without support for multiple sources.
|
||
*
|
||
* @private
|
||
* @param {Object} object The destination object.
|
||
* @param {Object} source The source object.
|
||
* @param {number} srcIndex The index of `source`.
|
||
* @param {Function} [customizer] The function to customize merged values.
|
||
* @param {Object} [stack] Tracks traversed source values and their merged
|
||
* counterparts.
|
||
*/
|
||
function baseMerge(object, source, srcIndex, customizer, stack) {
|
||
if (object === source) {
|
||
return;
|
||
}
|
||
if (!(isArray(source) || isTypedArray(source))) {
|
||
var props = keysIn(source);
|
||
}
|
||
arrayEach(props || source, function(srcValue, key) {
|
||
if (props) {
|
||
key = srcValue;
|
||
srcValue = source[key];
|
||
}
|
||
if (isObject(srcValue)) {
|
||
stack || (stack = new Stack);
|
||
baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack);
|
||
}
|
||
else {
|
||
var newValue = customizer
|
||
? customizer(object[key], srcValue, (key + ''), object, source, stack)
|
||
: undefined;
|
||
|
||
if (newValue === undefined) {
|
||
newValue = srcValue;
|
||
}
|
||
assignMergeValue(object, key, newValue);
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `baseMerge` for arrays and objects which performs
|
||
* deep merges and tracks traversed objects enabling objects with circular
|
||
* references to be merged.
|
||
*
|
||
* @private
|
||
* @param {Object} object The destination object.
|
||
* @param {Object} source The source object.
|
||
* @param {string} key The key of the value to merge.
|
||
* @param {number} srcIndex The index of `source`.
|
||
* @param {Function} mergeFunc The function to merge values.
|
||
* @param {Function} [customizer] The function to customize assigned values.
|
||
* @param {Object} [stack] Tracks traversed source values and their merged
|
||
* counterparts.
|
||
*/
|
||
function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) {
|
||
var objValue = object[key],
|
||
srcValue = source[key],
|
||
stacked = stack.get(srcValue);
|
||
|
||
if (stacked) {
|
||
assignMergeValue(object, key, stacked);
|
||
return;
|
||
}
|
||
var newValue = customizer
|
||
? customizer(objValue, srcValue, (key + ''), object, source, stack)
|
||
: undefined;
|
||
|
||
var isCommon = newValue === undefined;
|
||
|
||
if (isCommon) {
|
||
newValue = srcValue;
|
||
if (isArray(srcValue) || isTypedArray(srcValue)) {
|
||
if (isArray(objValue)) {
|
||
newValue = objValue;
|
||
}
|
||
else if (isArrayLikeObject(objValue)) {
|
||
newValue = copyArray(objValue);
|
||
}
|
||
else {
|
||
isCommon = false;
|
||
newValue = baseClone(srcValue, true);
|
||
}
|
||
}
|
||
else if (isPlainObject(srcValue) || isArguments(srcValue)) {
|
||
if (isArguments(objValue)) {
|
||
newValue = toPlainObject(objValue);
|
||
}
|
||
else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) {
|
||
isCommon = false;
|
||
newValue = baseClone(srcValue, true);
|
||
}
|
||
else {
|
||
newValue = objValue;
|
||
}
|
||
}
|
||
else {
|
||
isCommon = false;
|
||
}
|
||
}
|
||
stack.set(srcValue, newValue);
|
||
|
||
if (isCommon) {
|
||
// Recursively merge objects and arrays (susceptible to call stack limits).
|
||
mergeFunc(newValue, srcValue, srcIndex, customizer, stack);
|
||
}
|
||
stack['delete'](srcValue);
|
||
assignMergeValue(object, key, newValue);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.nth` which doesn't coerce `n` to an integer.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to query.
|
||
* @param {number} n The index of the element to return.
|
||
* @returns {*} Returns the nth element of `array`.
|
||
*/
|
||
function baseNth(array, n) {
|
||
var length = array.length;
|
||
if (!length) {
|
||
return;
|
||
}
|
||
n += n < 0 ? length : 0;
|
||
return isIndex(n, length) ? array[n] : undefined;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.orderBy` without param guards.
|
||
*
|
||
* @private
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by.
|
||
* @param {string[]} orders The sort orders of `iteratees`.
|
||
* @returns {Array} Returns the new sorted array.
|
||
*/
|
||
function baseOrderBy(collection, iteratees, orders) {
|
||
var index = -1;
|
||
iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(getIteratee()));
|
||
|
||
var result = baseMap(collection, function(value, key, collection) {
|
||
var criteria = arrayMap(iteratees, function(iteratee) {
|
||
return iteratee(value);
|
||
});
|
||
return { 'criteria': criteria, 'index': ++index, 'value': value };
|
||
});
|
||
|
||
return baseSortBy(result, function(object, other) {
|
||
return compareMultiple(object, other, orders);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.pick` without support for individual
|
||
* property identifiers.
|
||
*
|
||
* @private
|
||
* @param {Object} object The source object.
|
||
* @param {string[]} props The property identifiers to pick.
|
||
* @returns {Object} Returns the new object.
|
||
*/
|
||
function basePick(object, props) {
|
||
object = Object(object);
|
||
return arrayReduce(props, function(result, key) {
|
||
if (key in object) {
|
||
result[key] = object[key];
|
||
}
|
||
return result;
|
||
}, {});
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.pickBy` without support for iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Object} object The source object.
|
||
* @param {Function} predicate The function invoked per property.
|
||
* @returns {Object} Returns the new object.
|
||
*/
|
||
function basePickBy(object, predicate) {
|
||
var index = -1,
|
||
props = getAllKeysIn(object),
|
||
length = props.length,
|
||
result = {};
|
||
|
||
while (++index < length) {
|
||
var key = props[index],
|
||
value = object[key];
|
||
|
||
if (predicate(value, key)) {
|
||
result[key] = value;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.property` without support for deep paths.
|
||
*
|
||
* @private
|
||
* @param {string} key The key of the property to get.
|
||
* @returns {Function} Returns the new function.
|
||
*/
|
||
function baseProperty(key) {
|
||
return function(object) {
|
||
return object == null ? undefined : object[key];
|
||
};
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `baseProperty` which supports deep paths.
|
||
*
|
||
* @private
|
||
* @param {Array|string} path The path of the property to get.
|
||
* @returns {Function} Returns the new function.
|
||
*/
|
||
function basePropertyDeep(path) {
|
||
return function(object) {
|
||
return baseGet(object, path);
|
||
};
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.pullAllBy` without support for iteratee
|
||
* shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to modify.
|
||
* @param {Array} values The values to remove.
|
||
* @param {Function} [iteratee] The iteratee invoked per element.
|
||
* @param {Function} [comparator] The comparator invoked per element.
|
||
* @returns {Array} Returns `array`.
|
||
*/
|
||
function basePullAll(array, values, iteratee, comparator) {
|
||
var indexOf = comparator ? baseIndexOfWith : baseIndexOf,
|
||
index = -1,
|
||
length = values.length,
|
||
seen = array;
|
||
|
||
if (iteratee) {
|
||
seen = arrayMap(array, baseUnary(iteratee));
|
||
}
|
||
while (++index < length) {
|
||
var fromIndex = 0,
|
||
value = values[index],
|
||
computed = iteratee ? iteratee(value) : value;
|
||
|
||
while ((fromIndex = indexOf(seen, computed, fromIndex, comparator)) > -1) {
|
||
if (seen !== array) {
|
||
splice.call(seen, fromIndex, 1);
|
||
}
|
||
splice.call(array, fromIndex, 1);
|
||
}
|
||
}
|
||
return array;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.pullAt` without support for individual
|
||
* indexes or capturing the removed elements.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to modify.
|
||
* @param {number[]} indexes The indexes of elements to remove.
|
||
* @returns {Array} Returns `array`.
|
||
*/
|
||
function basePullAt(array, indexes) {
|
||
var length = array ? indexes.length : 0,
|
||
lastIndex = length - 1;
|
||
|
||
while (length--) {
|
||
var index = indexes[length];
|
||
if (lastIndex == length || index != previous) {
|
||
var previous = index;
|
||
if (isIndex(index)) {
|
||
splice.call(array, index, 1);
|
||
}
|
||
else if (!isKey(index, array)) {
|
||
var path = castPath(index),
|
||
object = parent(array, path);
|
||
|
||
if (object != null) {
|
||
delete object[last(path)];
|
||
}
|
||
}
|
||
else {
|
||
delete array[index];
|
||
}
|
||
}
|
||
}
|
||
return array;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.random` without support for returning
|
||
* floating-point numbers.
|
||
*
|
||
* @private
|
||
* @param {number} lower The lower bound.
|
||
* @param {number} upper The upper bound.
|
||
* @returns {number} Returns the random number.
|
||
*/
|
||
function baseRandom(lower, upper) {
|
||
return lower + nativeFloor(nativeRandom() * (upper - lower + 1));
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.range` and `_.rangeRight` which doesn't
|
||
* coerce arguments to numbers.
|
||
*
|
||
* @private
|
||
* @param {number} start The start of the range.
|
||
* @param {number} end The end of the range.
|
||
* @param {number} step The value to increment or decrement by.
|
||
* @param {boolean} [fromRight] Specify iterating from right to left.
|
||
* @returns {Array} Returns the new array of numbers.
|
||
*/
|
||
function baseRange(start, end, step, fromRight) {
|
||
var index = -1,
|
||
length = nativeMax(nativeCeil((end - start) / (step || 1)), 0),
|
||
result = Array(length);
|
||
|
||
while (length--) {
|
||
result[fromRight ? length : ++index] = start;
|
||
start += step;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.repeat` which doesn't coerce arguments.
|
||
*
|
||
* @private
|
||
* @param {string} string The string to repeat.
|
||
* @param {number} n The number of times to repeat the string.
|
||
* @returns {string} Returns the repeated string.
|
||
*/
|
||
function baseRepeat(string, n) {
|
||
var result = '';
|
||
if (!string || n < 1 || n > MAX_SAFE_INTEGER) {
|
||
return result;
|
||
}
|
||
// Leverage the exponentiation by squaring algorithm for a faster repeat.
|
||
// See https://en.wikipedia.org/wiki/Exponentiation_by_squaring for more details.
|
||
do {
|
||
if (n % 2) {
|
||
result += string;
|
||
}
|
||
n = nativeFloor(n / 2);
|
||
if (n) {
|
||
string += string;
|
||
}
|
||
} while (n);
|
||
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.set`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @param {Array|string} path The path of the property to set.
|
||
* @param {*} value The value to set.
|
||
* @param {Function} [customizer] The function to customize path creation.
|
||
* @returns {Object} Returns `object`.
|
||
*/
|
||
function baseSet(object, path, value, customizer) {
|
||
path = isKey(path, object) ? [path] : castPath(path);
|
||
|
||
var index = -1,
|
||
length = path.length,
|
||
lastIndex = length - 1,
|
||
nested = object;
|
||
|
||
while (nested != null && ++index < length) {
|
||
var key = path[index];
|
||
if (isObject(nested)) {
|
||
var newValue = value;
|
||
if (index != lastIndex) {
|
||
var objValue = nested[key];
|
||
newValue = customizer ? customizer(objValue, key, nested) : undefined;
|
||
if (newValue === undefined) {
|
||
newValue = objValue == null
|
||
? (isIndex(path[index + 1]) ? [] : {})
|
||
: objValue;
|
||
}
|
||
}
|
||
assignValue(nested, key, newValue);
|
||
}
|
||
nested = nested[key];
|
||
}
|
||
return object;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `setData` without support for hot loop detection.
|
||
*
|
||
* @private
|
||
* @param {Function} func The function to associate metadata with.
|
||
* @param {*} data The metadata.
|
||
* @returns {Function} Returns `func`.
|
||
*/
|
||
var baseSetData = !metaMap ? identity : function(func, data) {
|
||
metaMap.set(func, data);
|
||
return func;
|
||
};
|
||
|
||
/**
|
||
* The base implementation of `_.slice` without an iteratee call guard.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to slice.
|
||
* @param {number} [start=0] The start position.
|
||
* @param {number} [end=array.length] The end position.
|
||
* @returns {Array} Returns the slice of `array`.
|
||
*/
|
||
function baseSlice(array, start, end) {
|
||
var index = -1,
|
||
length = array.length;
|
||
|
||
if (start < 0) {
|
||
start = -start > length ? 0 : (length + start);
|
||
}
|
||
end = end > length ? length : end;
|
||
if (end < 0) {
|
||
end += length;
|
||
}
|
||
length = start > end ? 0 : ((end - start) >>> 0);
|
||
start >>>= 0;
|
||
|
||
var result = Array(length);
|
||
while (++index < length) {
|
||
result[index] = array[index + start];
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.some` without support for iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Function} predicate The function invoked per iteration.
|
||
* @returns {boolean} Returns `true` if any element passes the predicate check,
|
||
* else `false`.
|
||
*/
|
||
function baseSome(collection, predicate) {
|
||
var result;
|
||
|
||
baseEach(collection, function(value, index, collection) {
|
||
result = predicate(value, index, collection);
|
||
return !result;
|
||
});
|
||
return !!result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.sortedIndex` and `_.sortedLastIndex` which
|
||
* performs a binary search of `array` to determine the index at which `value`
|
||
* should be inserted into `array` in order to maintain its sort order.
|
||
*
|
||
* @private
|
||
* @param {Array} array The sorted array to inspect.
|
||
* @param {*} value The value to evaluate.
|
||
* @param {boolean} [retHighest] Specify returning the highest qualified index.
|
||
* @returns {number} Returns the index at which `value` should be inserted
|
||
* into `array`.
|
||
*/
|
||
function baseSortedIndex(array, value, retHighest) {
|
||
var low = 0,
|
||
high = array ? array.length : low;
|
||
|
||
if (typeof value == 'number' && value === value && high <= HALF_MAX_ARRAY_LENGTH) {
|
||
while (low < high) {
|
||
var mid = (low + high) >>> 1,
|
||
computed = array[mid];
|
||
|
||
if ((retHighest ? (computed <= value) : (computed < value)) && computed !== null) {
|
||
low = mid + 1;
|
||
} else {
|
||
high = mid;
|
||
}
|
||
}
|
||
return high;
|
||
}
|
||
return baseSortedIndexBy(array, value, identity, retHighest);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.sortedIndexBy` and `_.sortedLastIndexBy`
|
||
* which invokes `iteratee` for `value` and each element of `array` to compute
|
||
* their sort ranking. The iteratee is invoked with one argument; (value).
|
||
*
|
||
* @private
|
||
* @param {Array} array The sorted array to inspect.
|
||
* @param {*} value The value to evaluate.
|
||
* @param {Function} iteratee The iteratee invoked per element.
|
||
* @param {boolean} [retHighest] Specify returning the highest qualified index.
|
||
* @returns {number} Returns the index at which `value` should be inserted
|
||
* into `array`.
|
||
*/
|
||
function baseSortedIndexBy(array, value, iteratee, retHighest) {
|
||
value = iteratee(value);
|
||
|
||
var low = 0,
|
||
high = array ? array.length : 0,
|
||
valIsNaN = value !== value,
|
||
valIsNull = value === null,
|
||
valIsUndef = value === undefined;
|
||
|
||
while (low < high) {
|
||
var mid = nativeFloor((low + high) / 2),
|
||
computed = iteratee(array[mid]),
|
||
isDef = computed !== undefined,
|
||
isReflexive = computed === computed;
|
||
|
||
if (valIsNaN) {
|
||
var setLow = isReflexive || retHighest;
|
||
} else if (valIsNull) {
|
||
setLow = isReflexive && isDef && (retHighest || computed != null);
|
||
} else if (valIsUndef) {
|
||
setLow = isReflexive && (retHighest || isDef);
|
||
} else if (computed == null) {
|
||
setLow = false;
|
||
} else {
|
||
setLow = retHighest ? (computed <= value) : (computed < value);
|
||
}
|
||
if (setLow) {
|
||
low = mid + 1;
|
||
} else {
|
||
high = mid;
|
||
}
|
||
}
|
||
return nativeMin(high, MAX_ARRAY_INDEX);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.sortedUniq`.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to inspect.
|
||
* @returns {Array} Returns the new duplicate free array.
|
||
*/
|
||
function baseSortedUniq(array) {
|
||
return baseSortedUniqBy(array);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.sortedUniqBy` without support for iteratee
|
||
* shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to inspect.
|
||
* @param {Function} [iteratee] The iteratee invoked per element.
|
||
* @returns {Array} Returns the new duplicate free array.
|
||
*/
|
||
function baseSortedUniqBy(array, iteratee) {
|
||
var index = 0,
|
||
length = array.length,
|
||
value = array[0],
|
||
computed = iteratee ? iteratee(value) : value,
|
||
seen = computed,
|
||
resIndex = 1,
|
||
result = [value];
|
||
|
||
while (++index < length) {
|
||
value = array[index],
|
||
computed = iteratee ? iteratee(value) : value;
|
||
|
||
if (!eq(computed, seen)) {
|
||
seen = computed;
|
||
result[resIndex++] = value;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.uniqBy` without support for iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to inspect.
|
||
* @param {Function} [iteratee] The iteratee invoked per element.
|
||
* @param {Function} [comparator] The comparator invoked per element.
|
||
* @returns {Array} Returns the new duplicate free array.
|
||
*/
|
||
function baseUniq(array, iteratee, comparator) {
|
||
var index = -1,
|
||
includes = arrayIncludes,
|
||
length = array.length,
|
||
isCommon = true,
|
||
result = [],
|
||
seen = result;
|
||
|
||
if (comparator) {
|
||
isCommon = false;
|
||
includes = arrayIncludesWith;
|
||
}
|
||
else if (length >= LARGE_ARRAY_SIZE) {
|
||
var set = iteratee ? null : createSet(array);
|
||
if (set) {
|
||
return setToArray(set);
|
||
}
|
||
isCommon = false;
|
||
includes = cacheHas;
|
||
seen = new SetCache;
|
||
}
|
||
else {
|
||
seen = iteratee ? [] : result;
|
||
}
|
||
outer:
|
||
while (++index < length) {
|
||
var value = array[index],
|
||
computed = iteratee ? iteratee(value) : value;
|
||
|
||
if (isCommon && computed === computed) {
|
||
var seenIndex = seen.length;
|
||
while (seenIndex--) {
|
||
if (seen[seenIndex] === computed) {
|
||
continue outer;
|
||
}
|
||
}
|
||
if (iteratee) {
|
||
seen.push(computed);
|
||
}
|
||
result.push(value);
|
||
}
|
||
else if (!includes(seen, computed, comparator)) {
|
||
if (seen !== result) {
|
||
seen.push(computed);
|
||
}
|
||
result.push(value);
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.unset`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to modify.
|
||
* @param {Array|string} path The path of the property to unset.
|
||
* @returns {boolean} Returns `true` if the property is deleted, else `false`.
|
||
*/
|
||
function baseUnset(object, path) {
|
||
path = isKey(path, object) ? [path] : castPath(path);
|
||
object = parent(object, path);
|
||
var key = last(path);
|
||
return (object != null && has(object, key)) ? delete object[key] : true;
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `_.update`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @param {Array|string} path The path of the property to update.
|
||
* @param {Function} updater The function to produce the updated value.
|
||
* @param {Function} [customizer] The function to customize path creation.
|
||
* @returns {Object} Returns `object`.
|
||
*/
|
||
function baseUpdate(object, path, updater, customizer) {
|
||
return baseSet(object, path, updater(baseGet(object, path)), customizer);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of methods like `_.dropWhile` and `_.takeWhile`
|
||
* without support for iteratee shorthands.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to query.
|
||
* @param {Function} predicate The function invoked per iteration.
|
||
* @param {boolean} [isDrop] Specify dropping elements instead of taking them.
|
||
* @param {boolean} [fromRight] Specify iterating from right to left.
|
||
* @returns {Array} Returns the slice of `array`.
|
||
*/
|
||
function baseWhile(array, predicate, isDrop, fromRight) {
|
||
var length = array.length,
|
||
index = fromRight ? length : -1;
|
||
|
||
while ((fromRight ? index-- : ++index < length) &&
|
||
predicate(array[index], index, array)) {}
|
||
|
||
return isDrop
|
||
? baseSlice(array, (fromRight ? 0 : index), (fromRight ? index + 1 : length))
|
||
: baseSlice(array, (fromRight ? index + 1 : 0), (fromRight ? length : index));
|
||
}
|
||
|
||
/**
|
||
* The base implementation of `wrapperValue` which returns the result of
|
||
* performing a sequence of actions on the unwrapped `value`, where each
|
||
* successive action is supplied the return value of the previous.
|
||
*
|
||
* @private
|
||
* @param {*} value The unwrapped value.
|
||
* @param {Array} actions Actions to perform to resolve the unwrapped value.
|
||
* @returns {*} Returns the resolved value.
|
||
*/
|
||
function baseWrapperValue(value, actions) {
|
||
var result = value;
|
||
if (result instanceof LazyWrapper) {
|
||
result = result.value();
|
||
}
|
||
return arrayReduce(actions, function(result, action) {
|
||
return action.func.apply(action.thisArg, arrayPush([result], action.args));
|
||
}, result);
|
||
}
|
||
|
||
/**
|
||
* The base implementation of methods like `_.xor`, without support for
|
||
* iteratee shorthands, that accepts an array of arrays to inspect.
|
||
*
|
||
* @private
|
||
* @param {Array} arrays The arrays to inspect.
|
||
* @param {Function} [iteratee] The iteratee invoked per element.
|
||
* @param {Function} [comparator] The comparator invoked per element.
|
||
* @returns {Array} Returns the new array of values.
|
||
*/
|
||
function baseXor(arrays, iteratee, comparator) {
|
||
var index = -1,
|
||
length = arrays.length;
|
||
|
||
while (++index < length) {
|
||
var result = result
|
||
? arrayPush(
|
||
baseDifference(result, arrays[index], iteratee, comparator),
|
||
baseDifference(arrays[index], result, iteratee, comparator)
|
||
)
|
||
: arrays[index];
|
||
}
|
||
return (result && result.length) ? baseUniq(result, iteratee, comparator) : [];
|
||
}
|
||
|
||
/**
|
||
* This base implementation of `_.zipObject` which assigns values using `assignFunc`.
|
||
*
|
||
* @private
|
||
* @param {Array} props The property identifiers.
|
||
* @param {Array} values The property values.
|
||
* @param {Function} assignFunc The function to assign values.
|
||
* @returns {Object} Returns the new object.
|
||
*/
|
||
function baseZipObject(props, values, assignFunc) {
|
||
var index = -1,
|
||
length = props.length,
|
||
valsLength = values.length,
|
||
result = {};
|
||
|
||
while (++index < length) {
|
||
var value = index < valsLength ? values[index] : undefined;
|
||
assignFunc(result, props[index], value);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Casts `value` to an empty array if it's not an array like object.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to inspect.
|
||
* @returns {Array|Object} Returns the cast array-like object.
|
||
*/
|
||
function castArrayLikeObject(value) {
|
||
return isArrayLikeObject(value) ? value : [];
|
||
}
|
||
|
||
/**
|
||
* Casts `value` to `identity` if it's not a function.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to inspect.
|
||
* @returns {Function} Returns cast function.
|
||
*/
|
||
function castFunction(value) {
|
||
return typeof value == 'function' ? value : identity;
|
||
}
|
||
|
||
/**
|
||
* Casts `value` to a path array if it's not one.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to inspect.
|
||
* @returns {Array} Returns the cast property path array.
|
||
*/
|
||
function castPath(value) {
|
||
return isArray(value) ? value : stringToPath(value);
|
||
}
|
||
|
||
/**
|
||
* Casts `array` to a slice if it's needed.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to inspect.
|
||
* @param {number} start The start position.
|
||
* @param {number} [end=array.length] The end position.
|
||
* @returns {Array} Returns the cast slice.
|
||
*/
|
||
function castSlice(array, start, end) {
|
||
var length = array.length;
|
||
end = end === undefined ? length : end;
|
||
return (!start && end >= length) ? array : baseSlice(array, start, end);
|
||
}
|
||
|
||
/**
|
||
* Creates a clone of `buffer`.
|
||
*
|
||
* @private
|
||
* @param {Buffer} buffer The buffer to clone.
|
||
* @param {boolean} [isDeep] Specify a deep clone.
|
||
* @returns {Buffer} Returns the cloned buffer.
|
||
*/
|
||
function cloneBuffer(buffer, isDeep) {
|
||
if (isDeep) {
|
||
return buffer.slice();
|
||
}
|
||
var result = new buffer.constructor(buffer.length);
|
||
buffer.copy(result);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Creates a clone of `arrayBuffer`.
|
||
*
|
||
* @private
|
||
* @param {ArrayBuffer} arrayBuffer The array buffer to clone.
|
||
* @returns {ArrayBuffer} Returns the cloned array buffer.
|
||
*/
|
||
function cloneArrayBuffer(arrayBuffer) {
|
||
var result = new arrayBuffer.constructor(arrayBuffer.byteLength);
|
||
new Uint8Array(result).set(new Uint8Array(arrayBuffer));
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Creates a clone of `dataView`.
|
||
*
|
||
* @private
|
||
* @param {Object} dataView The data view to clone.
|
||
* @param {boolean} [isDeep] Specify a deep clone.
|
||
* @returns {Object} Returns the cloned data view.
|
||
*/
|
||
function cloneDataView(dataView, isDeep) {
|
||
var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer;
|
||
return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength);
|
||
}
|
||
|
||
/**
|
||
* Creates a clone of `map`.
|
||
*
|
||
* @private
|
||
* @param {Object} map The map to clone.
|
||
* @param {Function} cloneFunc The function to clone values.
|
||
* @param {boolean} [isDeep] Specify a deep clone.
|
||
* @returns {Object} Returns the cloned map.
|
||
*/
|
||
function cloneMap(map, isDeep, cloneFunc) {
|
||
var array = isDeep ? cloneFunc(mapToArray(map), true) : mapToArray(map);
|
||
return arrayReduce(array, addMapEntry, new map.constructor);
|
||
}
|
||
|
||
/**
|
||
* Creates a clone of `regexp`.
|
||
*
|
||
* @private
|
||
* @param {Object} regexp The regexp to clone.
|
||
* @returns {Object} Returns the cloned regexp.
|
||
*/
|
||
function cloneRegExp(regexp) {
|
||
var result = new regexp.constructor(regexp.source, reFlags.exec(regexp));
|
||
result.lastIndex = regexp.lastIndex;
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Creates a clone of `set`.
|
||
*
|
||
* @private
|
||
* @param {Object} set The set to clone.
|
||
* @param {Function} cloneFunc The function to clone values.
|
||
* @param {boolean} [isDeep] Specify a deep clone.
|
||
* @returns {Object} Returns the cloned set.
|
||
*/
|
||
function cloneSet(set, isDeep, cloneFunc) {
|
||
var array = isDeep ? cloneFunc(setToArray(set), true) : setToArray(set);
|
||
return arrayReduce(array, addSetEntry, new set.constructor);
|
||
}
|
||
|
||
/**
|
||
* Creates a clone of the `symbol` object.
|
||
*
|
||
* @private
|
||
* @param {Object} symbol The symbol object to clone.
|
||
* @returns {Object} Returns the cloned symbol object.
|
||
*/
|
||
function cloneSymbol(symbol) {
|
||
return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {};
|
||
}
|
||
|
||
/**
|
||
* Creates a clone of `typedArray`.
|
||
*
|
||
* @private
|
||
* @param {Object} typedArray The typed array to clone.
|
||
* @param {boolean} [isDeep] Specify a deep clone.
|
||
* @returns {Object} Returns the cloned typed array.
|
||
*/
|
||
function cloneTypedArray(typedArray, isDeep) {
|
||
var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer;
|
||
return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length);
|
||
}
|
||
|
||
/**
|
||
* Creates an array that is the composition of partially applied arguments,
|
||
* placeholders, and provided arguments into a single array of arguments.
|
||
*
|
||
* @private
|
||
* @param {Array|Object} args The provided arguments.
|
||
* @param {Array} partials The arguments to prepend to those provided.
|
||
* @param {Array} holders The `partials` placeholder indexes.
|
||
* @params {boolean} [isCurried] Specify composing for a curried function.
|
||
* @returns {Array} Returns the new array of composed arguments.
|
||
*/
|
||
function composeArgs(args, partials, holders, isCurried) {
|
||
var argsIndex = -1,
|
||
argsLength = args.length,
|
||
holdersLength = holders.length,
|
||
leftIndex = -1,
|
||
leftLength = partials.length,
|
||
rangeLength = nativeMax(argsLength - holdersLength, 0),
|
||
result = Array(leftLength + rangeLength),
|
||
isUncurried = !isCurried;
|
||
|
||
while (++leftIndex < leftLength) {
|
||
result[leftIndex] = partials[leftIndex];
|
||
}
|
||
while (++argsIndex < holdersLength) {
|
||
if (isUncurried || argsIndex < argsLength) {
|
||
result[holders[argsIndex]] = args[argsIndex];
|
||
}
|
||
}
|
||
while (rangeLength--) {
|
||
result[leftIndex++] = args[argsIndex++];
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* This function is like `composeArgs` except that the arguments composition
|
||
* is tailored for `_.partialRight`.
|
||
*
|
||
* @private
|
||
* @param {Array|Object} args The provided arguments.
|
||
* @param {Array} partials The arguments to append to those provided.
|
||
* @param {Array} holders The `partials` placeholder indexes.
|
||
* @params {boolean} [isCurried] Specify composing for a curried function.
|
||
* @returns {Array} Returns the new array of composed arguments.
|
||
*/
|
||
function composeArgsRight(args, partials, holders, isCurried) {
|
||
var argsIndex = -1,
|
||
argsLength = args.length,
|
||
holdersIndex = -1,
|
||
holdersLength = holders.length,
|
||
rightIndex = -1,
|
||
rightLength = partials.length,
|
||
rangeLength = nativeMax(argsLength - holdersLength, 0),
|
||
result = Array(rangeLength + rightLength),
|
||
isUncurried = !isCurried;
|
||
|
||
while (++argsIndex < rangeLength) {
|
||
result[argsIndex] = args[argsIndex];
|
||
}
|
||
var offset = argsIndex;
|
||
while (++rightIndex < rightLength) {
|
||
result[offset + rightIndex] = partials[rightIndex];
|
||
}
|
||
while (++holdersIndex < holdersLength) {
|
||
if (isUncurried || argsIndex < argsLength) {
|
||
result[offset + holders[holdersIndex]] = args[argsIndex++];
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Copies the values of `source` to `array`.
|
||
*
|
||
* @private
|
||
* @param {Array} source The array to copy values from.
|
||
* @param {Array} [array=[]] The array to copy values to.
|
||
* @returns {Array} Returns `array`.
|
||
*/
|
||
function copyArray(source, array) {
|
||
var index = -1,
|
||
length = source.length;
|
||
|
||
array || (array = Array(length));
|
||
while (++index < length) {
|
||
array[index] = source[index];
|
||
}
|
||
return array;
|
||
}
|
||
|
||
/**
|
||
* Copies properties of `source` to `object`.
|
||
*
|
||
* @private
|
||
* @param {Object} source The object to copy properties from.
|
||
* @param {Array} props The property identifiers to copy.
|
||
* @param {Object} [object={}] The object to copy properties to.
|
||
* @param {Function} [customizer] The function to customize copied values.
|
||
* @returns {Object} Returns `object`.
|
||
*/
|
||
function copyObject(source, props, object, customizer) {
|
||
object || (object = {});
|
||
|
||
var index = -1,
|
||
length = props.length;
|
||
|
||
while (++index < length) {
|
||
var key = props[index];
|
||
|
||
var newValue = customizer
|
||
? customizer(object[key], source[key], key, object, source)
|
||
: source[key];
|
||
|
||
assignValue(object, key, newValue);
|
||
}
|
||
return object;
|
||
}
|
||
|
||
/**
|
||
* Copies own symbol properties of `source` to `object`.
|
||
*
|
||
* @private
|
||
* @param {Object} source The object to copy symbols from.
|
||
* @param {Object} [object={}] The object to copy symbols to.
|
||
* @returns {Object} Returns `object`.
|
||
*/
|
||
function copySymbols(source, object) {
|
||
return copyObject(source, getSymbols(source), object);
|
||
}
|
||
|
||
/**
|
||
* Creates a function like `_.groupBy`.
|
||
*
|
||
* @private
|
||
* @param {Function} setter The function to set accumulator values.
|
||
* @param {Function} [initializer] The accumulator object initializer.
|
||
* @returns {Function} Returns the new aggregator function.
|
||
*/
|
||
function createAggregator(setter, initializer) {
|
||
return function(collection, iteratee) {
|
||
var func = isArray(collection) ? arrayAggregator : baseAggregator,
|
||
accumulator = initializer ? initializer() : {};
|
||
|
||
return func(collection, setter, getIteratee(iteratee), accumulator);
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates a function like `_.assign`.
|
||
*
|
||
* @private
|
||
* @param {Function} assigner The function to assign values.
|
||
* @returns {Function} Returns the new assigner function.
|
||
*/
|
||
function createAssigner(assigner) {
|
||
return rest(function(object, sources) {
|
||
var index = -1,
|
||
length = sources.length,
|
||
customizer = length > 1 ? sources[length - 1] : undefined,
|
||
guard = length > 2 ? sources[2] : undefined;
|
||
|
||
customizer = typeof customizer == 'function'
|
||
? (length--, customizer)
|
||
: undefined;
|
||
|
||
if (guard && isIterateeCall(sources[0], sources[1], guard)) {
|
||
customizer = length < 3 ? undefined : customizer;
|
||
length = 1;
|
||
}
|
||
object = Object(object);
|
||
while (++index < length) {
|
||
var source = sources[index];
|
||
if (source) {
|
||
assigner(object, source, index, customizer);
|
||
}
|
||
}
|
||
return object;
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Creates a `baseEach` or `baseEachRight` function.
|
||
*
|
||
* @private
|
||
* @param {Function} eachFunc The function to iterate over a collection.
|
||
* @param {boolean} [fromRight] Specify iterating from right to left.
|
||
* @returns {Function} Returns the new base function.
|
||
*/
|
||
function createBaseEach(eachFunc, fromRight) {
|
||
return function(collection, iteratee) {
|
||
if (collection == null) {
|
||
return collection;
|
||
}
|
||
if (!isArrayLike(collection)) {
|
||
return eachFunc(collection, iteratee);
|
||
}
|
||
var length = collection.length,
|
||
index = fromRight ? length : -1,
|
||
iterable = Object(collection);
|
||
|
||
while ((fromRight ? index-- : ++index < length)) {
|
||
if (iteratee(iterable[index], index, iterable) === false) {
|
||
break;
|
||
}
|
||
}
|
||
return collection;
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates a base function for methods like `_.forIn` and `_.forOwn`.
|
||
*
|
||
* @private
|
||
* @param {boolean} [fromRight] Specify iterating from right to left.
|
||
* @returns {Function} Returns the new base function.
|
||
*/
|
||
function createBaseFor(fromRight) {
|
||
return function(object, iteratee, keysFunc) {
|
||
var index = -1,
|
||
iterable = Object(object),
|
||
props = keysFunc(object),
|
||
length = props.length;
|
||
|
||
while (length--) {
|
||
var key = props[fromRight ? length : ++index];
|
||
if (iteratee(iterable[key], key, iterable) === false) {
|
||
break;
|
||
}
|
||
}
|
||
return object;
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates a function that wraps `func` to invoke it with the optional `this`
|
||
* binding of `thisArg`.
|
||
*
|
||
* @private
|
||
* @param {Function} func The function to wrap.
|
||
* @param {number} bitmask The bitmask of wrapper flags. See `createWrapper`
|
||
* for more details.
|
||
* @param {*} [thisArg] The `this` binding of `func`.
|
||
* @returns {Function} Returns the new wrapped function.
|
||
*/
|
||
function createBaseWrapper(func, bitmask, thisArg) {
|
||
var isBind = bitmask & BIND_FLAG,
|
||
Ctor = createCtorWrapper(func);
|
||
|
||
function wrapper() {
|
||
var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
|
||
return fn.apply(isBind ? thisArg : this, arguments);
|
||
}
|
||
return wrapper;
|
||
}
|
||
|
||
/**
|
||
* Creates a function like `_.lowerFirst`.
|
||
*
|
||
* @private
|
||
* @param {string} methodName The name of the `String` case method to use.
|
||
* @returns {Function} Returns the new function.
|
||
*/
|
||
function createCaseFirst(methodName) {
|
||
return function(string) {
|
||
string = toString(string);
|
||
|
||
var strSymbols = reHasComplexSymbol.test(string)
|
||
? stringToArray(string)
|
||
: undefined;
|
||
|
||
var chr = strSymbols
|
||
? strSymbols[0]
|
||
: string.charAt(0);
|
||
|
||
var trailing = strSymbols
|
||
? castSlice(strSymbols, 1).join('')
|
||
: string.slice(1);
|
||
|
||
return chr[methodName]() + trailing;
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates a function like `_.camelCase`.
|
||
*
|
||
* @private
|
||
* @param {Function} callback The function to combine each word.
|
||
* @returns {Function} Returns the new compounder function.
|
||
*/
|
||
function createCompounder(callback) {
|
||
return function(string) {
|
||
return arrayReduce(words(deburr(string).replace(reApos, '')), callback, '');
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates a function that produces an instance of `Ctor` regardless of
|
||
* whether it was invoked as part of a `new` expression or by `call` or `apply`.
|
||
*
|
||
* @private
|
||
* @param {Function} Ctor The constructor to wrap.
|
||
* @returns {Function} Returns the new wrapped function.
|
||
*/
|
||
function createCtorWrapper(Ctor) {
|
||
return function() {
|
||
// Use a `switch` statement to work with class constructors. See
|
||
// http://ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
|
||
// for more details.
|
||
var args = arguments;
|
||
switch (args.length) {
|
||
case 0: return new Ctor;
|
||
case 1: return new Ctor(args[0]);
|
||
case 2: return new Ctor(args[0], args[1]);
|
||
case 3: return new Ctor(args[0], args[1], args[2]);
|
||
case 4: return new Ctor(args[0], args[1], args[2], args[3]);
|
||
case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]);
|
||
case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]);
|
||
case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
|
||
}
|
||
var thisBinding = baseCreate(Ctor.prototype),
|
||
result = Ctor.apply(thisBinding, args);
|
||
|
||
// Mimic the constructor's `return` behavior.
|
||
// See https://es5.github.io/#x13.2.2 for more details.
|
||
return isObject(result) ? result : thisBinding;
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates a function that wraps `func` to enable currying.
|
||
*
|
||
* @private
|
||
* @param {Function} func The function to wrap.
|
||
* @param {number} bitmask The bitmask of wrapper flags. See `createWrapper`
|
||
* for more details.
|
||
* @param {number} arity The arity of `func`.
|
||
* @returns {Function} Returns the new wrapped function.
|
||
*/
|
||
function createCurryWrapper(func, bitmask, arity) {
|
||
var Ctor = createCtorWrapper(func);
|
||
|
||
function wrapper() {
|
||
var length = arguments.length,
|
||
args = Array(length),
|
||
index = length,
|
||
placeholder = getPlaceholder(wrapper);
|
||
|
||
while (index--) {
|
||
args[index] = arguments[index];
|
||
}
|
||
var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder)
|
||
? []
|
||
: replaceHolders(args, placeholder);
|
||
|
||
length -= holders.length;
|
||
if (length < arity) {
|
||
return createRecurryWrapper(
|
||
func, bitmask, createHybridWrapper, wrapper.placeholder, undefined,
|
||
args, holders, undefined, undefined, arity - length);
|
||
}
|
||
var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
|
||
return apply(fn, this, args);
|
||
}
|
||
return wrapper;
|
||
}
|
||
|
||
/**
|
||
* Creates a `_.flow` or `_.flowRight` function.
|
||
*
|
||
* @private
|
||
* @param {boolean} [fromRight] Specify iterating from right to left.
|
||
* @returns {Function} Returns the new flow function.
|
||
*/
|
||
function createFlow(fromRight) {
|
||
return rest(function(funcs) {
|
||
funcs = baseFlatten(funcs, 1);
|
||
|
||
var length = funcs.length,
|
||
index = length,
|
||
prereq = LodashWrapper.prototype.thru;
|
||
|
||
if (fromRight) {
|
||
funcs.reverse();
|
||
}
|
||
while (index--) {
|
||
var func = funcs[index];
|
||
if (typeof func != 'function') {
|
||
throw new TypeError(FUNC_ERROR_TEXT);
|
||
}
|
||
if (prereq && !wrapper && getFuncName(func) == 'wrapper') {
|
||
var wrapper = new LodashWrapper([], true);
|
||
}
|
||
}
|
||
index = wrapper ? index : length;
|
||
while (++index < length) {
|
||
func = funcs[index];
|
||
|
||
var funcName = getFuncName(func),
|
||
data = funcName == 'wrapper' ? getData(func) : undefined;
|
||
|
||
if (data && isLaziable(data[0]) &&
|
||
data[1] == (ARY_FLAG | CURRY_FLAG | PARTIAL_FLAG | REARG_FLAG) &&
|
||
!data[4].length && data[9] == 1
|
||
) {
|
||
wrapper = wrapper[getFuncName(data[0])].apply(wrapper, data[3]);
|
||
} else {
|
||
wrapper = (func.length == 1 && isLaziable(func))
|
||
? wrapper[funcName]()
|
||
: wrapper.thru(func);
|
||
}
|
||
}
|
||
return function() {
|
||
var args = arguments,
|
||
value = args[0];
|
||
|
||
if (wrapper && args.length == 1 &&
|
||
isArray(value) && value.length >= LARGE_ARRAY_SIZE) {
|
||
return wrapper.plant(value).value();
|
||
}
|
||
var index = 0,
|
||
result = length ? funcs[index].apply(this, args) : value;
|
||
|
||
while (++index < length) {
|
||
result = funcs[index].call(this, result);
|
||
}
|
||
return result;
|
||
};
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Creates a function that wraps `func` to invoke it with optional `this`
|
||
* binding of `thisArg`, partial application, and currying.
|
||
*
|
||
* @private
|
||
* @param {Function|string} func The function or method name to wrap.
|
||
* @param {number} bitmask The bitmask of wrapper flags. See `createWrapper`
|
||
* for more details.
|
||
* @param {*} [thisArg] The `this` binding of `func`.
|
||
* @param {Array} [partials] The arguments to prepend to those provided to
|
||
* the new function.
|
||
* @param {Array} [holders] The `partials` placeholder indexes.
|
||
* @param {Array} [partialsRight] The arguments to append to those provided
|
||
* to the new function.
|
||
* @param {Array} [holdersRight] The `partialsRight` placeholder indexes.
|
||
* @param {Array} [argPos] The argument positions of the new function.
|
||
* @param {number} [ary] The arity cap of `func`.
|
||
* @param {number} [arity] The arity of `func`.
|
||
* @returns {Function} Returns the new wrapped function.
|
||
*/
|
||
function createHybridWrapper(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) {
|
||
var isAry = bitmask & ARY_FLAG,
|
||
isBind = bitmask & BIND_FLAG,
|
||
isBindKey = bitmask & BIND_KEY_FLAG,
|
||
isCurried = bitmask & (CURRY_FLAG | CURRY_RIGHT_FLAG),
|
||
isFlip = bitmask & FLIP_FLAG,
|
||
Ctor = isBindKey ? undefined : createCtorWrapper(func);
|
||
|
||
function wrapper() {
|
||
var length = arguments.length,
|
||
index = length,
|
||
args = Array(length);
|
||
|
||
while (index--) {
|
||
args[index] = arguments[index];
|
||
}
|
||
if (isCurried) {
|
||
var placeholder = getPlaceholder(wrapper),
|
||
holdersCount = countHolders(args, placeholder);
|
||
}
|
||
if (partials) {
|
||
args = composeArgs(args, partials, holders, isCurried);
|
||
}
|
||
if (partialsRight) {
|
||
args = composeArgsRight(args, partialsRight, holdersRight, isCurried);
|
||
}
|
||
length -= holdersCount;
|
||
if (isCurried && length < arity) {
|
||
var newHolders = replaceHolders(args, placeholder);
|
||
return createRecurryWrapper(
|
||
func, bitmask, createHybridWrapper, wrapper.placeholder, thisArg,
|
||
args, newHolders, argPos, ary, arity - length
|
||
);
|
||
}
|
||
var thisBinding = isBind ? thisArg : this,
|
||
fn = isBindKey ? thisBinding[func] : func;
|
||
|
||
length = args.length;
|
||
if (argPos) {
|
||
args = reorder(args, argPos);
|
||
} else if (isFlip && length > 1) {
|
||
args.reverse();
|
||
}
|
||
if (isAry && ary < length) {
|
||
args.length = ary;
|
||
}
|
||
if (this && this !== root && this instanceof wrapper) {
|
||
fn = Ctor || createCtorWrapper(fn);
|
||
}
|
||
return fn.apply(thisBinding, args);
|
||
}
|
||
return wrapper;
|
||
}
|
||
|
||
/**
|
||
* Creates a function like `_.invertBy`.
|
||
*
|
||
* @private
|
||
* @param {Function} setter The function to set accumulator values.
|
||
* @param {Function} toIteratee The function to resolve iteratees.
|
||
* @returns {Function} Returns the new inverter function.
|
||
*/
|
||
function createInverter(setter, toIteratee) {
|
||
return function(object, iteratee) {
|
||
return baseInverter(object, setter, toIteratee(iteratee), {});
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates a function like `_.over`.
|
||
*
|
||
* @private
|
||
* @param {Function} arrayFunc The function to iterate over iteratees.
|
||
* @returns {Function} Returns the new invoker function.
|
||
*/
|
||
function createOver(arrayFunc) {
|
||
return rest(function(iteratees) {
|
||
iteratees = (iteratees.length == 1 && isArray(iteratees[0]))
|
||
? arrayMap(iteratees[0], baseUnary(getIteratee()))
|
||
: arrayMap(baseFlatten(iteratees, 1, isFlattenableIteratee), baseUnary(getIteratee()));
|
||
|
||
return rest(function(args) {
|
||
var thisArg = this;
|
||
return arrayFunc(iteratees, function(iteratee) {
|
||
return apply(iteratee, thisArg, args);
|
||
});
|
||
});
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Creates the padding for `string` based on `length`. The `chars` string
|
||
* is truncated if the number of characters exceeds `length`.
|
||
*
|
||
* @private
|
||
* @param {number} length The padding length.
|
||
* @param {string} [chars=' '] The string used as padding.
|
||
* @returns {string} Returns the padding for `string`.
|
||
*/
|
||
function createPadding(length, chars) {
|
||
chars = chars === undefined ? ' ' : (chars + '');
|
||
|
||
var charsLength = chars.length;
|
||
if (charsLength < 2) {
|
||
return charsLength ? baseRepeat(chars, length) : chars;
|
||
}
|
||
var result = baseRepeat(chars, nativeCeil(length / stringSize(chars)));
|
||
return reHasComplexSymbol.test(chars)
|
||
? castSlice(stringToArray(result), 0, length).join('')
|
||
: result.slice(0, length);
|
||
}
|
||
|
||
/**
|
||
* Creates a function that wraps `func` to invoke it with the `this` binding
|
||
* of `thisArg` and `partials` prepended to the arguments it receives.
|
||
*
|
||
* @private
|
||
* @param {Function} func The function to wrap.
|
||
* @param {number} bitmask The bitmask of wrapper flags. See `createWrapper`
|
||
* for more details.
|
||
* @param {*} thisArg The `this` binding of `func`.
|
||
* @param {Array} partials The arguments to prepend to those provided to
|
||
* the new function.
|
||
* @returns {Function} Returns the new wrapped function.
|
||
*/
|
||
function createPartialWrapper(func, bitmask, thisArg, partials) {
|
||
var isBind = bitmask & BIND_FLAG,
|
||
Ctor = createCtorWrapper(func);
|
||
|
||
function wrapper() {
|
||
var argsIndex = -1,
|
||
argsLength = arguments.length,
|
||
leftIndex = -1,
|
||
leftLength = partials.length,
|
||
args = Array(leftLength + argsLength),
|
||
fn = (this && this !== root && this instanceof wrapper) ? Ctor : func;
|
||
|
||
while (++leftIndex < leftLength) {
|
||
args[leftIndex] = partials[leftIndex];
|
||
}
|
||
while (argsLength--) {
|
||
args[leftIndex++] = arguments[++argsIndex];
|
||
}
|
||
return apply(fn, isBind ? thisArg : this, args);
|
||
}
|
||
return wrapper;
|
||
}
|
||
|
||
/**
|
||
* Creates a `_.range` or `_.rangeRight` function.
|
||
*
|
||
* @private
|
||
* @param {boolean} [fromRight] Specify iterating from right to left.
|
||
* @returns {Function} Returns the new range function.
|
||
*/
|
||
function createRange(fromRight) {
|
||
return function(start, end, step) {
|
||
if (step && typeof step != 'number' && isIterateeCall(start, end, step)) {
|
||
end = step = undefined;
|
||
}
|
||
// Ensure the sign of `-0` is preserved.
|
||
start = toNumber(start);
|
||
start = start === start ? start : 0;
|
||
if (end === undefined) {
|
||
end = start;
|
||
start = 0;
|
||
} else {
|
||
end = toNumber(end) || 0;
|
||
}
|
||
step = step === undefined ? (start < end ? 1 : -1) : (toNumber(step) || 0);
|
||
return baseRange(start, end, step, fromRight);
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates a function that wraps `func` to continue currying.
|
||
*
|
||
* @private
|
||
* @param {Function} func The function to wrap.
|
||
* @param {number} bitmask The bitmask of wrapper flags. See `createWrapper`
|
||
* for more details.
|
||
* @param {Function} wrapFunc The function to create the `func` wrapper.
|
||
* @param {*} placeholder The placeholder value.
|
||
* @param {*} [thisArg] The `this` binding of `func`.
|
||
* @param {Array} [partials] The arguments to prepend to those provided to
|
||
* the new function.
|
||
* @param {Array} [holders] The `partials` placeholder indexes.
|
||
* @param {Array} [argPos] The argument positions of the new function.
|
||
* @param {number} [ary] The arity cap of `func`.
|
||
* @param {number} [arity] The arity of `func`.
|
||
* @returns {Function} Returns the new wrapped function.
|
||
*/
|
||
function createRecurryWrapper(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) {
|
||
var isCurry = bitmask & CURRY_FLAG,
|
||
newHolders = isCurry ? holders : undefined,
|
||
newHoldersRight = isCurry ? undefined : holders,
|
||
newPartials = isCurry ? partials : undefined,
|
||
newPartialsRight = isCurry ? undefined : partials;
|
||
|
||
bitmask |= (isCurry ? PARTIAL_FLAG : PARTIAL_RIGHT_FLAG);
|
||
bitmask &= ~(isCurry ? PARTIAL_RIGHT_FLAG : PARTIAL_FLAG);
|
||
|
||
if (!(bitmask & CURRY_BOUND_FLAG)) {
|
||
bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
|
||
}
|
||
var newData = [
|
||
func, bitmask, thisArg, newPartials, newHolders, newPartialsRight,
|
||
newHoldersRight, argPos, ary, arity
|
||
];
|
||
|
||
var result = wrapFunc.apply(undefined, newData);
|
||
if (isLaziable(func)) {
|
||
setData(result, newData);
|
||
}
|
||
result.placeholder = placeholder;
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Creates a function like `_.round`.
|
||
*
|
||
* @private
|
||
* @param {string} methodName The name of the `Math` method to use when rounding.
|
||
* @returns {Function} Returns the new round function.
|
||
*/
|
||
function createRound(methodName) {
|
||
var func = Math[methodName];
|
||
return function(number, precision) {
|
||
number = toNumber(number);
|
||
precision = toInteger(precision);
|
||
if (precision) {
|
||
// Shift with exponential notation to avoid floating-point issues.
|
||
// See [MDN](https://mdn.io/round#Examples) for more details.
|
||
var pair = (toString(number) + 'e').split('e'),
|
||
value = func(pair[0] + 'e' + (+pair[1] + precision));
|
||
|
||
pair = (toString(value) + 'e').split('e');
|
||
return +(pair[0] + 'e' + (+pair[1] - precision));
|
||
}
|
||
return func(number);
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates a set of `values`.
|
||
*
|
||
* @private
|
||
* @param {Array} values The values to add to the set.
|
||
* @returns {Object} Returns the new set.
|
||
*/
|
||
var createSet = !(Set && new Set([1, 2]).size === 2) ? noop : function(values) {
|
||
return new Set(values);
|
||
};
|
||
|
||
/**
|
||
* Creates a function that either curries or invokes `func` with optional
|
||
* `this` binding and partially applied arguments.
|
||
*
|
||
* @private
|
||
* @param {Function|string} func The function or method name to wrap.
|
||
* @param {number} bitmask The bitmask of wrapper flags.
|
||
* The bitmask may be composed of the following flags:
|
||
* 1 - `_.bind`
|
||
* 2 - `_.bindKey`
|
||
* 4 - `_.curry` or `_.curryRight` of a bound function
|
||
* 8 - `_.curry`
|
||
* 16 - `_.curryRight`
|
||
* 32 - `_.partial`
|
||
* 64 - `_.partialRight`
|
||
* 128 - `_.rearg`
|
||
* 256 - `_.ary`
|
||
* @param {*} [thisArg] The `this` binding of `func`.
|
||
* @param {Array} [partials] The arguments to be partially applied.
|
||
* @param {Array} [holders] The `partials` placeholder indexes.
|
||
* @param {Array} [argPos] The argument positions of the new function.
|
||
* @param {number} [ary] The arity cap of `func`.
|
||
* @param {number} [arity] The arity of `func`.
|
||
* @returns {Function} Returns the new wrapped function.
|
||
*/
|
||
function createWrapper(func, bitmask, thisArg, partials, holders, argPos, ary, arity) {
|
||
var isBindKey = bitmask & BIND_KEY_FLAG;
|
||
if (!isBindKey && typeof func != 'function') {
|
||
throw new TypeError(FUNC_ERROR_TEXT);
|
||
}
|
||
var length = partials ? partials.length : 0;
|
||
if (!length) {
|
||
bitmask &= ~(PARTIAL_FLAG | PARTIAL_RIGHT_FLAG);
|
||
partials = holders = undefined;
|
||
}
|
||
ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0);
|
||
arity = arity === undefined ? arity : toInteger(arity);
|
||
length -= holders ? holders.length : 0;
|
||
|
||
if (bitmask & PARTIAL_RIGHT_FLAG) {
|
||
var partialsRight = partials,
|
||
holdersRight = holders;
|
||
|
||
partials = holders = undefined;
|
||
}
|
||
var data = isBindKey ? undefined : getData(func);
|
||
|
||
var newData = [
|
||
func, bitmask, thisArg, partials, holders, partialsRight, holdersRight,
|
||
argPos, ary, arity
|
||
];
|
||
|
||
if (data) {
|
||
mergeData(newData, data);
|
||
}
|
||
func = newData[0];
|
||
bitmask = newData[1];
|
||
thisArg = newData[2];
|
||
partials = newData[3];
|
||
holders = newData[4];
|
||
arity = newData[9] = newData[9] == null
|
||
? (isBindKey ? 0 : func.length)
|
||
: nativeMax(newData[9] - length, 0);
|
||
|
||
if (!arity && bitmask & (CURRY_FLAG | CURRY_RIGHT_FLAG)) {
|
||
bitmask &= ~(CURRY_FLAG | CURRY_RIGHT_FLAG);
|
||
}
|
||
if (!bitmask || bitmask == BIND_FLAG) {
|
||
var result = createBaseWrapper(func, bitmask, thisArg);
|
||
} else if (bitmask == CURRY_FLAG || bitmask == CURRY_RIGHT_FLAG) {
|
||
result = createCurryWrapper(func, bitmask, arity);
|
||
} else if ((bitmask == PARTIAL_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) && !holders.length) {
|
||
result = createPartialWrapper(func, bitmask, thisArg, partials);
|
||
} else {
|
||
result = createHybridWrapper.apply(undefined, newData);
|
||
}
|
||
var setter = data ? baseSetData : setData;
|
||
return setter(result, newData);
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `baseIsEqualDeep` for arrays with support for
|
||
* partial deep comparisons.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to compare.
|
||
* @param {Array} other The other array to compare.
|
||
* @param {Function} equalFunc The function to determine equivalents of values.
|
||
* @param {Function} customizer The function to customize comparisons.
|
||
* @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual`
|
||
* for more details.
|
||
* @param {Object} stack Tracks traversed `array` and `other` objects.
|
||
* @returns {boolean} Returns `true` if the arrays are equivalent, else `false`.
|
||
*/
|
||
function equalArrays(array, other, equalFunc, customizer, bitmask, stack) {
|
||
var index = -1,
|
||
isPartial = bitmask & PARTIAL_COMPARE_FLAG,
|
||
isUnordered = bitmask & UNORDERED_COMPARE_FLAG,
|
||
arrLength = array.length,
|
||
othLength = other.length;
|
||
|
||
if (arrLength != othLength && !(isPartial && othLength > arrLength)) {
|
||
return false;
|
||
}
|
||
// Assume cyclic values are equal.
|
||
var stacked = stack.get(array);
|
||
if (stacked) {
|
||
return stacked == other;
|
||
}
|
||
var result = true;
|
||
stack.set(array, other);
|
||
|
||
// Ignore non-index properties.
|
||
while (++index < arrLength) {
|
||
var arrValue = array[index],
|
||
othValue = other[index];
|
||
|
||
if (customizer) {
|
||
var compared = isPartial
|
||
? customizer(othValue, arrValue, index, other, array, stack)
|
||
: customizer(arrValue, othValue, index, array, other, stack);
|
||
}
|
||
if (compared !== undefined) {
|
||
if (compared) {
|
||
continue;
|
||
}
|
||
result = false;
|
||
break;
|
||
}
|
||
// Recursively compare arrays (susceptible to call stack limits).
|
||
if (isUnordered) {
|
||
if (!arraySome(other, function(othValue) {
|
||
return arrValue === othValue ||
|
||
equalFunc(arrValue, othValue, customizer, bitmask, stack);
|
||
})) {
|
||
result = false;
|
||
break;
|
||
}
|
||
} else if (!(
|
||
arrValue === othValue ||
|
||
equalFunc(arrValue, othValue, customizer, bitmask, stack)
|
||
)) {
|
||
result = false;
|
||
break;
|
||
}
|
||
}
|
||
stack['delete'](array);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `baseIsEqualDeep` for comparing objects of
|
||
* the same `toStringTag`.
|
||
*
|
||
* **Note:** This function only supports comparing values with tags of
|
||
* `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to compare.
|
||
* @param {Object} other The other object to compare.
|
||
* @param {string} tag The `toStringTag` of the objects to compare.
|
||
* @param {Function} equalFunc The function to determine equivalents of values.
|
||
* @param {Function} customizer The function to customize comparisons.
|
||
* @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual`
|
||
* for more details.
|
||
* @param {Object} stack Tracks traversed `object` and `other` objects.
|
||
* @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
|
||
*/
|
||
function equalByTag(object, other, tag, equalFunc, customizer, bitmask, stack) {
|
||
switch (tag) {
|
||
case dataViewTag:
|
||
if ((object.byteLength != other.byteLength) ||
|
||
(object.byteOffset != other.byteOffset)) {
|
||
return false;
|
||
}
|
||
object = object.buffer;
|
||
other = other.buffer;
|
||
|
||
case arrayBufferTag:
|
||
if ((object.byteLength != other.byteLength) ||
|
||
!equalFunc(new Uint8Array(object), new Uint8Array(other))) {
|
||
return false;
|
||
}
|
||
return true;
|
||
|
||
case boolTag:
|
||
case dateTag:
|
||
// 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 +object == +other;
|
||
|
||
case errorTag:
|
||
return object.name == other.name && object.message == other.message;
|
||
|
||
case numberTag:
|
||
// Treat `NaN` vs. `NaN` as equal.
|
||
return (object != +object) ? other != +other : object == +other;
|
||
|
||
case regexpTag:
|
||
case stringTag:
|
||
// Coerce regexes to strings and treat strings, primitives and objects,
|
||
// as equal. See http://www.ecma-international.org/ecma-262/6.0/#sec-regexp.prototype.tostring
|
||
// for more details.
|
||
return object == (other + '');
|
||
|
||
case mapTag:
|
||
var convert = mapToArray;
|
||
|
||
case setTag:
|
||
var isPartial = bitmask & PARTIAL_COMPARE_FLAG;
|
||
convert || (convert = setToArray);
|
||
|
||
if (object.size != other.size && !isPartial) {
|
||
return false;
|
||
}
|
||
// Assume cyclic values are equal.
|
||
var stacked = stack.get(object);
|
||
if (stacked) {
|
||
return stacked == other;
|
||
}
|
||
bitmask |= UNORDERED_COMPARE_FLAG;
|
||
stack.set(object, other);
|
||
|
||
// Recursively compare objects (susceptible to call stack limits).
|
||
return equalArrays(convert(object), convert(other), equalFunc, customizer, bitmask, stack);
|
||
|
||
case symbolTag:
|
||
if (symbolValueOf) {
|
||
return symbolValueOf.call(object) == symbolValueOf.call(other);
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `baseIsEqualDeep` for objects with support for
|
||
* partial deep comparisons.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to compare.
|
||
* @param {Object} other The other object to compare.
|
||
* @param {Function} equalFunc The function to determine equivalents of values.
|
||
* @param {Function} customizer The function to customize comparisons.
|
||
* @param {number} bitmask The bitmask of comparison flags. See `baseIsEqual`
|
||
* for more details.
|
||
* @param {Object} stack Tracks traversed `object` and `other` objects.
|
||
* @returns {boolean} Returns `true` if the objects are equivalent, else `false`.
|
||
*/
|
||
function equalObjects(object, other, equalFunc, customizer, bitmask, stack) {
|
||
var isPartial = bitmask & PARTIAL_COMPARE_FLAG,
|
||
objProps = keys(object),
|
||
objLength = objProps.length,
|
||
othProps = keys(other),
|
||
othLength = othProps.length;
|
||
|
||
if (objLength != othLength && !isPartial) {
|
||
return false;
|
||
}
|
||
var index = objLength;
|
||
while (index--) {
|
||
var key = objProps[index];
|
||
if (!(isPartial ? key in other : baseHas(other, key))) {
|
||
return false;
|
||
}
|
||
}
|
||
// Assume cyclic values are equal.
|
||
var stacked = stack.get(object);
|
||
if (stacked) {
|
||
return stacked == other;
|
||
}
|
||
var result = true;
|
||
stack.set(object, other);
|
||
|
||
var skipCtor = isPartial;
|
||
while (++index < objLength) {
|
||
key = objProps[index];
|
||
var objValue = object[key],
|
||
othValue = other[key];
|
||
|
||
if (customizer) {
|
||
var compared = isPartial
|
||
? customizer(othValue, objValue, key, other, object, stack)
|
||
: customizer(objValue, othValue, key, object, other, stack);
|
||
}
|
||
// Recursively compare objects (susceptible to call stack limits).
|
||
if (!(compared === undefined
|
||
? (objValue === othValue || equalFunc(objValue, othValue, customizer, bitmask, stack))
|
||
: compared
|
||
)) {
|
||
result = false;
|
||
break;
|
||
}
|
||
skipCtor || (skipCtor = key == 'constructor');
|
||
}
|
||
if (result && !skipCtor) {
|
||
var objCtor = object.constructor,
|
||
othCtor = other.constructor;
|
||
|
||
// Non `Object` object instances with different constructors are not equal.
|
||
if (objCtor != othCtor &&
|
||
('constructor' in object && 'constructor' in other) &&
|
||
!(typeof objCtor == 'function' && objCtor instanceof objCtor &&
|
||
typeof othCtor == 'function' && othCtor instanceof othCtor)) {
|
||
result = false;
|
||
}
|
||
}
|
||
stack['delete'](object);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Creates an array of own enumerable property names and symbols of `object`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @returns {Array} Returns the array of property names and symbols.
|
||
*/
|
||
function getAllKeys(object) {
|
||
return baseGetAllKeys(object, keys, getSymbols);
|
||
}
|
||
|
||
/**
|
||
* Creates an array of own and inherited enumerable property names and
|
||
* symbols of `object`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @returns {Array} Returns the array of property names and symbols.
|
||
*/
|
||
function getAllKeysIn(object) {
|
||
return baseGetAllKeys(object, keysIn, getSymbolsIn);
|
||
}
|
||
|
||
/**
|
||
* Gets metadata for `func`.
|
||
*
|
||
* @private
|
||
* @param {Function} func The function to query.
|
||
* @returns {*} Returns the metadata for `func`.
|
||
*/
|
||
var getData = !metaMap ? noop : function(func) {
|
||
return metaMap.get(func);
|
||
};
|
||
|
||
/**
|
||
* Gets the name of `func`.
|
||
*
|
||
* @private
|
||
* @param {Function} func The function to query.
|
||
* @returns {string} Returns the function name.
|
||
*/
|
||
function getFuncName(func) {
|
||
var result = (func.name + ''),
|
||
array = realNames[result],
|
||
length = hasOwnProperty.call(realNames, result) ? array.length : 0;
|
||
|
||
while (length--) {
|
||
var data = array[length],
|
||
otherFunc = data.func;
|
||
if (otherFunc == null || otherFunc == func) {
|
||
return data.name;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Gets the appropriate "iteratee" function. If `_.iteratee` is customized,
|
||
* this function returns the custom method, otherwise it returns `baseIteratee`.
|
||
* If arguments are provided, the chosen function is invoked with them and
|
||
* its result is returned.
|
||
*
|
||
* @private
|
||
* @param {*} [value] The value to convert to an iteratee.
|
||
* @param {number} [arity] The arity of the created iteratee.
|
||
* @returns {Function} Returns the chosen function or its result.
|
||
*/
|
||
function getIteratee() {
|
||
var result = lodash.iteratee || iteratee;
|
||
result = result === iteratee ? baseIteratee : result;
|
||
return arguments.length ? result(arguments[0], arguments[1]) : result;
|
||
}
|
||
|
||
/**
|
||
* Gets the "length" property value of `object`.
|
||
*
|
||
* **Note:** This function is used to avoid a
|
||
* [JIT bug](https://bugs.webkit.org/show_bug.cgi?id=142792) that affects
|
||
* Safari on at least iOS 8.1-8.3 ARM64.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @returns {*} Returns the "length" value.
|
||
*/
|
||
var getLength = baseProperty('length');
|
||
|
||
/**
|
||
* Gets the property names, values, and compare flags of `object`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @returns {Array} Returns the match data of `object`.
|
||
*/
|
||
function getMatchData(object) {
|
||
var result = toPairs(object),
|
||
length = result.length;
|
||
|
||
while (length--) {
|
||
result[length][2] = isStrictComparable(result[length][1]);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Gets the native function at `key` of `object`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @param {string} key The key of the method to get.
|
||
* @returns {*} Returns the function if it's native, else `undefined`.
|
||
*/
|
||
function getNative(object, key) {
|
||
var value = object[key];
|
||
return isNative(value) ? value : undefined;
|
||
}
|
||
|
||
/**
|
||
* Gets the argument placeholder value for `func`.
|
||
*
|
||
* @private
|
||
* @param {Function} func The function to inspect.
|
||
* @returns {*} Returns the placeholder value.
|
||
*/
|
||
function getPlaceholder(func) {
|
||
var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func;
|
||
return object.placeholder;
|
||
}
|
||
|
||
/**
|
||
* Gets the `[[Prototype]]` of `value`.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to query.
|
||
* @returns {null|Object} Returns the `[[Prototype]]`.
|
||
*/
|
||
function getPrototype(value) {
|
||
return nativeGetPrototype(Object(value));
|
||
}
|
||
|
||
/**
|
||
* Creates an array of the own enumerable symbol properties of `object`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @returns {Array} Returns the array of symbols.
|
||
*/
|
||
function getSymbols(object) {
|
||
// Coerce `object` to an object to avoid non-object errors in V8.
|
||
// See https://bugs.chromium.org/p/v8/issues/detail?id=3443 for more details.
|
||
return getOwnPropertySymbols(Object(object));
|
||
}
|
||
|
||
// Fallback for IE < 11.
|
||
if (!getOwnPropertySymbols) {
|
||
getSymbols = function() {
|
||
return [];
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates an array of the own and inherited enumerable symbol properties
|
||
* of `object`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @returns {Array} Returns the array of symbols.
|
||
*/
|
||
var getSymbolsIn = !getOwnPropertySymbols ? getSymbols : function(object) {
|
||
var result = [];
|
||
while (object) {
|
||
arrayPush(result, getSymbols(object));
|
||
object = getPrototype(object);
|
||
}
|
||
return result;
|
||
};
|
||
|
||
/**
|
||
* Gets the `toStringTag` of `value`.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to query.
|
||
* @returns {string} Returns the `toStringTag`.
|
||
*/
|
||
function getTag(value) {
|
||
return objectToString.call(value);
|
||
}
|
||
|
||
// Fallback for data views, maps, sets, and weak maps in IE 11,
|
||
// for data views in Edge, and promises in Node.js.
|
||
if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) ||
|
||
(Map && getTag(new Map) != mapTag) ||
|
||
(Promise && getTag(Promise.resolve()) != promiseTag) ||
|
||
(Set && getTag(new Set) != setTag) ||
|
||
(WeakMap && getTag(new WeakMap) != weakMapTag)) {
|
||
getTag = function(value) {
|
||
var result = objectToString.call(value),
|
||
Ctor = result == objectTag ? value.constructor : undefined,
|
||
ctorString = Ctor ? toSource(Ctor) : undefined;
|
||
|
||
if (ctorString) {
|
||
switch (ctorString) {
|
||
case dataViewCtorString: return dataViewTag;
|
||
case mapCtorString: return mapTag;
|
||
case promiseCtorString: return promiseTag;
|
||
case setCtorString: return setTag;
|
||
case weakMapCtorString: return weakMapTag;
|
||
}
|
||
}
|
||
return result;
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Gets the view, applying any `transforms` to the `start` and `end` positions.
|
||
*
|
||
* @private
|
||
* @param {number} start The start of the view.
|
||
* @param {number} end The end of the view.
|
||
* @param {Array} transforms The transformations to apply to the view.
|
||
* @returns {Object} Returns an object containing the `start` and `end`
|
||
* positions of the view.
|
||
*/
|
||
function getView(start, end, transforms) {
|
||
var index = -1,
|
||
length = transforms.length;
|
||
|
||
while (++index < length) {
|
||
var data = transforms[index],
|
||
size = data.size;
|
||
|
||
switch (data.type) {
|
||
case 'drop': start += size; break;
|
||
case 'dropRight': end -= size; break;
|
||
case 'take': end = nativeMin(end, start + size); break;
|
||
case 'takeRight': start = nativeMax(start, end - size); break;
|
||
}
|
||
}
|
||
return { 'start': start, 'end': end };
|
||
}
|
||
|
||
/**
|
||
* Checks if `path` exists on `object`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @param {Array|string} path The path to check.
|
||
* @param {Function} hasFunc The function to check properties.
|
||
* @returns {boolean} Returns `true` if `path` exists, else `false`.
|
||
*/
|
||
function hasPath(object, path, hasFunc) {
|
||
path = isKey(path, object) ? [path] : castPath(path);
|
||
|
||
var result,
|
||
index = -1,
|
||
length = path.length;
|
||
|
||
while (++index < length) {
|
||
var key = path[index];
|
||
if (!(result = object != null && hasFunc(object, key))) {
|
||
break;
|
||
}
|
||
object = object[key];
|
||
}
|
||
if (result) {
|
||
return result;
|
||
}
|
||
var length = object ? object.length : 0;
|
||
return !!length && isLength(length) && isIndex(key, length) &&
|
||
(isArray(object) || isString(object) || isArguments(object));
|
||
}
|
||
|
||
/**
|
||
* Initializes an array clone.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to clone.
|
||
* @returns {Array} Returns the initialized clone.
|
||
*/
|
||
function initCloneArray(array) {
|
||
var length = array.length,
|
||
result = array.constructor(length);
|
||
|
||
// Add properties assigned by `RegExp#exec`.
|
||
if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) {
|
||
result.index = array.index;
|
||
result.input = array.input;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Initializes an object clone.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to clone.
|
||
* @returns {Object} Returns the initialized clone.
|
||
*/
|
||
function initCloneObject(object) {
|
||
return (typeof object.constructor == 'function' && !isPrototype(object))
|
||
? baseCreate(getPrototype(object))
|
||
: {};
|
||
}
|
||
|
||
/**
|
||
* Initializes an object clone based on its `toStringTag`.
|
||
*
|
||
* **Note:** This function only supports cloning values with tags of
|
||
* `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to clone.
|
||
* @param {string} tag The `toStringTag` of the object to clone.
|
||
* @param {Function} cloneFunc The function to clone values.
|
||
* @param {boolean} [isDeep] Specify a deep clone.
|
||
* @returns {Object} Returns the initialized clone.
|
||
*/
|
||
function initCloneByTag(object, tag, cloneFunc, isDeep) {
|
||
var Ctor = object.constructor;
|
||
switch (tag) {
|
||
case arrayBufferTag:
|
||
return cloneArrayBuffer(object);
|
||
|
||
case boolTag:
|
||
case dateTag:
|
||
return new Ctor(+object);
|
||
|
||
case dataViewTag:
|
||
return cloneDataView(object, isDeep);
|
||
|
||
case float32Tag: case float64Tag:
|
||
case int8Tag: case int16Tag: case int32Tag:
|
||
case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag:
|
||
return cloneTypedArray(object, isDeep);
|
||
|
||
case mapTag:
|
||
return cloneMap(object, isDeep, cloneFunc);
|
||
|
||
case numberTag:
|
||
case stringTag:
|
||
return new Ctor(object);
|
||
|
||
case regexpTag:
|
||
return cloneRegExp(object);
|
||
|
||
case setTag:
|
||
return cloneSet(object, isDeep, cloneFunc);
|
||
|
||
case symbolTag:
|
||
return cloneSymbol(object);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Creates an array of index keys for `object` values of arrays,
|
||
* `arguments` objects, and strings, otherwise `null` is returned.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @returns {Array|null} Returns index keys, else `null`.
|
||
*/
|
||
function indexKeys(object) {
|
||
var length = object ? object.length : undefined;
|
||
if (isLength(length) &&
|
||
(isArray(object) || isString(object) || isArguments(object))) {
|
||
return baseTimes(length, String);
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is a flattenable `arguments` object or array.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
|
||
*/
|
||
function isFlattenable(value) {
|
||
return isArrayLikeObject(value) && (isArray(value) || isArguments(value));
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is a flattenable array and not a `_.matchesProperty`
|
||
* iteratee shorthand.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is flattenable, else `false`.
|
||
*/
|
||
function isFlattenableIteratee(value) {
|
||
return isArray(value) && !(value.length == 2 && !isFunction(value[0]));
|
||
}
|
||
|
||
/**
|
||
* Checks if the given arguments are from an iteratee call.
|
||
*
|
||
* @private
|
||
* @param {*} value The potential iteratee value argument.
|
||
* @param {*} index The potential iteratee index or key argument.
|
||
* @param {*} object The potential iteratee object argument.
|
||
* @returns {boolean} Returns `true` if the arguments are from an iteratee call,
|
||
* else `false`.
|
||
*/
|
||
function isIterateeCall(value, index, object) {
|
||
if (!isObject(object)) {
|
||
return false;
|
||
}
|
||
var type = typeof index;
|
||
if (type == 'number'
|
||
? (isArrayLike(object) && isIndex(index, object.length))
|
||
: (type == 'string' && index in object)
|
||
) {
|
||
return eq(object[index], value);
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is a property name and not a property path.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to check.
|
||
* @param {Object} [object] The object to query keys on.
|
||
* @returns {boolean} Returns `true` if `value` is a property name, else `false`.
|
||
*/
|
||
function isKey(value, object) {
|
||
var type = typeof value;
|
||
if (type == 'number' || type == 'symbol') {
|
||
return true;
|
||
}
|
||
return !isArray(value) &&
|
||
(isSymbol(value) || reIsPlainProp.test(value) || !reIsDeepProp.test(value) ||
|
||
(object != null && value in Object(object)));
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is suitable for use as unique object key.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is suitable, else `false`.
|
||
*/
|
||
function isKeyable(value) {
|
||
var type = typeof value;
|
||
return type == 'number' || type == 'boolean' ||
|
||
(type == 'string' && value != '__proto__') || value == null;
|
||
}
|
||
|
||
/**
|
||
* Checks if `func` has a lazy counterpart.
|
||
*
|
||
* @private
|
||
* @param {Function} func The function to check.
|
||
* @returns {boolean} Returns `true` if `func` has a lazy counterpart,
|
||
* else `false`.
|
||
*/
|
||
function isLaziable(func) {
|
||
var funcName = getFuncName(func),
|
||
other = lodash[funcName];
|
||
|
||
if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) {
|
||
return false;
|
||
}
|
||
if (func === other) {
|
||
return true;
|
||
}
|
||
var data = getData(other);
|
||
return !!data && func === data[0];
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is likely a prototype object.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is a prototype, else `false`.
|
||
*/
|
||
function isPrototype(value) {
|
||
var Ctor = value && value.constructor,
|
||
proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto;
|
||
|
||
return value === proto;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is suitable for strict equality comparisons, i.e. `===`.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` if suitable for strict
|
||
* equality comparisons, else `false`.
|
||
*/
|
||
function isStrictComparable(value) {
|
||
return value === value && !isObject(value);
|
||
}
|
||
|
||
/**
|
||
* A specialized version of `matchesProperty` for source values suitable
|
||
* for strict equality comparisons, i.e. `===`.
|
||
*
|
||
* @private
|
||
* @param {string} key The key of the property to get.
|
||
* @param {*} srcValue The value to match.
|
||
* @returns {Function} Returns the new function.
|
||
*/
|
||
function matchesStrictComparable(key, srcValue) {
|
||
return function(object) {
|
||
if (object == null) {
|
||
return false;
|
||
}
|
||
return object[key] === srcValue &&
|
||
(srcValue !== undefined || (key in Object(object)));
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Merges the function metadata of `source` into `data`.
|
||
*
|
||
* Merging metadata reduces the number of wrappers used to invoke a function.
|
||
* This is possible because methods like `_.bind`, `_.curry`, and `_.partial`
|
||
* may be applied regardless of execution order. Methods like `_.ary` and
|
||
* `_.rearg` modify function arguments, making the order in which they are
|
||
* executed important, preventing the merging of metadata. However, we make
|
||
* an exception for a safe combined case where curried functions have `_.ary`
|
||
* and or `_.rearg` applied.
|
||
*
|
||
* @private
|
||
* @param {Array} data The destination metadata.
|
||
* @param {Array} source The source metadata.
|
||
* @returns {Array} Returns `data`.
|
||
*/
|
||
function mergeData(data, source) {
|
||
var bitmask = data[1],
|
||
srcBitmask = source[1],
|
||
newBitmask = bitmask | srcBitmask,
|
||
isCommon = newBitmask < (BIND_FLAG | BIND_KEY_FLAG | ARY_FLAG);
|
||
|
||
var isCombo =
|
||
((srcBitmask == ARY_FLAG) && (bitmask == CURRY_FLAG)) ||
|
||
((srcBitmask == ARY_FLAG) && (bitmask == REARG_FLAG) && (data[7].length <= source[8])) ||
|
||
((srcBitmask == (ARY_FLAG | REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == CURRY_FLAG));
|
||
|
||
// Exit early if metadata can't be merged.
|
||
if (!(isCommon || isCombo)) {
|
||
return data;
|
||
}
|
||
// Use source `thisArg` if available.
|
||
if (srcBitmask & BIND_FLAG) {
|
||
data[2] = source[2];
|
||
// Set when currying a bound function.
|
||
newBitmask |= bitmask & BIND_FLAG ? 0 : CURRY_BOUND_FLAG;
|
||
}
|
||
// Compose partial arguments.
|
||
var value = source[3];
|
||
if (value) {
|
||
var partials = data[3];
|
||
data[3] = partials ? composeArgs(partials, value, source[4]) : value;
|
||
data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4];
|
||
}
|
||
// Compose partial right arguments.
|
||
value = source[5];
|
||
if (value) {
|
||
partials = data[5];
|
||
data[5] = partials ? composeArgsRight(partials, value, source[6]) : value;
|
||
data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6];
|
||
}
|
||
// Use source `argPos` if available.
|
||
value = source[7];
|
||
if (value) {
|
||
data[7] = value;
|
||
}
|
||
// Use source `ary` if it's smaller.
|
||
if (srcBitmask & ARY_FLAG) {
|
||
data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]);
|
||
}
|
||
// Use source `arity` if one is not provided.
|
||
if (data[9] == null) {
|
||
data[9] = source[9];
|
||
}
|
||
// Use source `func` and merge bitmasks.
|
||
data[0] = source[0];
|
||
data[1] = newBitmask;
|
||
|
||
return data;
|
||
}
|
||
|
||
/**
|
||
* Used by `_.defaultsDeep` to customize its `_.merge` use.
|
||
*
|
||
* @private
|
||
* @param {*} objValue The destination value.
|
||
* @param {*} srcValue The source value.
|
||
* @param {string} key The key of the property to merge.
|
||
* @param {Object} object The parent object of `objValue`.
|
||
* @param {Object} source The parent object of `srcValue`.
|
||
* @param {Object} [stack] Tracks traversed source values and their merged
|
||
* counterparts.
|
||
* @returns {*} Returns the value to assign.
|
||
*/
|
||
function mergeDefaults(objValue, srcValue, key, object, source, stack) {
|
||
if (isObject(objValue) && isObject(srcValue)) {
|
||
baseMerge(objValue, srcValue, undefined, mergeDefaults, stack.set(srcValue, objValue));
|
||
}
|
||
return objValue;
|
||
}
|
||
|
||
/**
|
||
* Gets the parent value at `path` of `object`.
|
||
*
|
||
* @private
|
||
* @param {Object} object The object to query.
|
||
* @param {Array} path The path to get the parent value of.
|
||
* @returns {*} Returns the parent value.
|
||
*/
|
||
function parent(object, path) {
|
||
return path.length == 1 ? object : baseGet(object, baseSlice(path, 0, -1));
|
||
}
|
||
|
||
/**
|
||
* Reorder `array` according to the specified indexes where the element at
|
||
* the first index is assigned as the first element, the element at
|
||
* the second index is assigned as the second element, and so on.
|
||
*
|
||
* @private
|
||
* @param {Array} array The array to reorder.
|
||
* @param {Array} indexes The arranged array indexes.
|
||
* @returns {Array} Returns `array`.
|
||
*/
|
||
function reorder(array, indexes) {
|
||
var arrLength = array.length,
|
||
length = nativeMin(indexes.length, arrLength),
|
||
oldArray = copyArray(array);
|
||
|
||
while (length--) {
|
||
var index = indexes[length];
|
||
array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined;
|
||
}
|
||
return array;
|
||
}
|
||
|
||
/**
|
||
* Sets metadata for `func`.
|
||
*
|
||
* **Note:** If this function becomes hot, i.e. is invoked a lot in a short
|
||
* period of time, it will trip its breaker and transition to an identity
|
||
* function to avoid garbage collection pauses in V8. See
|
||
* [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070)
|
||
* for more details.
|
||
*
|
||
* @private
|
||
* @param {Function} func The function to associate metadata with.
|
||
* @param {*} data The metadata.
|
||
* @returns {Function} Returns `func`.
|
||
*/
|
||
var setData = (function() {
|
||
var count = 0,
|
||
lastCalled = 0;
|
||
|
||
return function(key, value) {
|
||
var stamp = now(),
|
||
remaining = HOT_SPAN - (stamp - lastCalled);
|
||
|
||
lastCalled = stamp;
|
||
if (remaining > 0) {
|
||
if (++count >= HOT_COUNT) {
|
||
return key;
|
||
}
|
||
} else {
|
||
count = 0;
|
||
}
|
||
return baseSetData(key, value);
|
||
};
|
||
}());
|
||
|
||
/**
|
||
* Converts `string` to a property path array.
|
||
*
|
||
* @private
|
||
* @param {string} string The string to convert.
|
||
* @returns {Array} Returns the property path array.
|
||
*/
|
||
var stringToPath = memoize(function(string) {
|
||
var result = [];
|
||
toString(string).replace(rePropName, function(match, number, quote, string) {
|
||
result.push(quote ? string.replace(reEscapeChar, '$1') : (number || match));
|
||
});
|
||
return result;
|
||
});
|
||
|
||
/**
|
||
* Converts `value` to a string key if it's not a string or symbol.
|
||
*
|
||
* @private
|
||
* @param {*} value The value to inspect.
|
||
* @returns {string|symbol} Returns the key.
|
||
*/
|
||
function toKey(key) {
|
||
return (typeof key == 'string' || isSymbol(key)) ? key : (key + '');
|
||
}
|
||
|
||
/**
|
||
* Converts `func` to its source code.
|
||
*
|
||
* @private
|
||
* @param {Function} func The function to process.
|
||
* @returns {string} Returns the source code.
|
||
*/
|
||
function toSource(func) {
|
||
if (func != null) {
|
||
try {
|
||
return funcToString.call(func);
|
||
} catch (e) {}
|
||
try {
|
||
return (func + '');
|
||
} catch (e) {}
|
||
}
|
||
return '';
|
||
}
|
||
|
||
/**
|
||
* Creates a clone of `wrapper`.
|
||
*
|
||
* @private
|
||
* @param {Object} wrapper The wrapper to clone.
|
||
* @returns {Object} Returns the cloned wrapper.
|
||
*/
|
||
function wrapperClone(wrapper) {
|
||
if (wrapper instanceof LazyWrapper) {
|
||
return wrapper.clone();
|
||
}
|
||
var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__);
|
||
result.__actions__ = copyArray(wrapper.__actions__);
|
||
result.__index__ = wrapper.__index__;
|
||
result.__values__ = wrapper.__values__;
|
||
return result;
|
||
}
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Creates an array of elements split into groups the length of `size`.
|
||
* If `array` can't be split evenly, the final chunk will be the remaining
|
||
* elements.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to process.
|
||
* @param {number} [size=1] The length of each chunk
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {Array} Returns the new array containing chunks.
|
||
* @example
|
||
*
|
||
* _.chunk(['a', 'b', 'c', 'd'], 2);
|
||
* // => [['a', 'b'], ['c', 'd']]
|
||
*
|
||
* _.chunk(['a', 'b', 'c', 'd'], 3);
|
||
* // => [['a', 'b', 'c'], ['d']]
|
||
*/
|
||
function chunk(array, size, guard) {
|
||
if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) {
|
||
size = 1;
|
||
} else {
|
||
size = nativeMax(toInteger(size), 0);
|
||
}
|
||
var length = array ? array.length : 0;
|
||
if (!length || size < 1) {
|
||
return [];
|
||
}
|
||
var index = 0,
|
||
resIndex = 0,
|
||
result = Array(nativeCeil(length / size));
|
||
|
||
while (index < length) {
|
||
result[resIndex++] = baseSlice(array, index, (index += size));
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Creates an array with all falsey values removed. The values `false`, `null`,
|
||
* `0`, `""`, `undefined`, and `NaN` are falsey.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Array
|
||
* @param {Array} array The array to compact.
|
||
* @returns {Array} Returns the new array of filtered values.
|
||
* @example
|
||
*
|
||
* _.compact([0, 1, false, 2, '', 3]);
|
||
* // => [1, 2, 3]
|
||
*/
|
||
function compact(array) {
|
||
var index = -1,
|
||
length = array ? array.length : 0,
|
||
resIndex = 0,
|
||
result = [];
|
||
|
||
while (++index < length) {
|
||
var value = array[index];
|
||
if (value) {
|
||
result[resIndex++] = value;
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Creates a new array concatenating `array` with any additional arrays
|
||
* and/or values.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to concatenate.
|
||
* @param {...*} [values] The values to concatenate.
|
||
* @returns {Array} Returns the new concatenated array.
|
||
* @example
|
||
*
|
||
* var array = [1];
|
||
* var other = _.concat(array, 2, [3], [[4]]);
|
||
*
|
||
* console.log(other);
|
||
* // => [1, 2, 3, [4]]
|
||
*
|
||
* console.log(array);
|
||
* // => [1]
|
||
*/
|
||
function concat() {
|
||
var length = arguments.length,
|
||
array = castArray(arguments[0]);
|
||
|
||
if (length < 2) {
|
||
return length ? copyArray(array) : [];
|
||
}
|
||
var args = Array(length - 1);
|
||
while (length--) {
|
||
args[length - 1] = arguments[length];
|
||
}
|
||
return arrayConcat(array, baseFlatten(args, 1));
|
||
}
|
||
|
||
/**
|
||
* Creates an array of unique `array` values not included in the other given
|
||
* arrays using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
|
||
* for equality comparisons. The order of result values is determined by the
|
||
* order they occur in the first array.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Array
|
||
* @param {Array} array The array to inspect.
|
||
* @param {...Array} [values] The values to exclude.
|
||
* @returns {Array} Returns the new array of filtered values.
|
||
* @example
|
||
*
|
||
* _.difference([3, 2, 1], [4, 2]);
|
||
* // => [3, 1]
|
||
*/
|
||
var difference = rest(function(array, values) {
|
||
return isArrayLikeObject(array)
|
||
? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true))
|
||
: [];
|
||
});
|
||
|
||
/**
|
||
* This method is like `_.difference` except that it accepts `iteratee` which
|
||
* is invoked for each element of `array` and `values` to generate the criterion
|
||
* by which they're compared. Result values are chosen from the first array.
|
||
* The iteratee is invoked with one argument: (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to inspect.
|
||
* @param {...Array} [values] The values to exclude.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee invoked per element.
|
||
* @returns {Array} Returns the new array of filtered values.
|
||
* @example
|
||
*
|
||
* _.differenceBy([3.1, 2.2, 1.3], [4.4, 2.5], Math.floor);
|
||
* // => [3.1, 1.3]
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.differenceBy([{ 'x': 2 }, { 'x': 1 }], [{ 'x': 1 }], 'x');
|
||
* // => [{ 'x': 2 }]
|
||
*/
|
||
var differenceBy = rest(function(array, values) {
|
||
var iteratee = last(values);
|
||
if (isArrayLikeObject(iteratee)) {
|
||
iteratee = undefined;
|
||
}
|
||
return isArrayLikeObject(array)
|
||
? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), getIteratee(iteratee))
|
||
: [];
|
||
});
|
||
|
||
/**
|
||
* This method is like `_.difference` except that it accepts `comparator`
|
||
* which is invoked to compare elements of `array` to `values`. Result values
|
||
* are chosen from the first array. The comparator is invoked with two arguments:
|
||
* (arrVal, othVal).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to inspect.
|
||
* @param {...Array} [values] The values to exclude.
|
||
* @param {Function} [comparator] The comparator invoked per element.
|
||
* @returns {Array} Returns the new array of filtered values.
|
||
* @example
|
||
*
|
||
* var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
|
||
*
|
||
* _.differenceWith(objects, [{ 'x': 1, 'y': 2 }], _.isEqual);
|
||
* // => [{ 'x': 2, 'y': 1 }]
|
||
*/
|
||
var differenceWith = rest(function(array, values) {
|
||
var comparator = last(values);
|
||
if (isArrayLikeObject(comparator)) {
|
||
comparator = undefined;
|
||
}
|
||
return isArrayLikeObject(array)
|
||
? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true), undefined, comparator)
|
||
: [];
|
||
});
|
||
|
||
/**
|
||
* Creates a slice of `array` with `n` elements dropped from the beginning.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.5.0
|
||
* @category Array
|
||
* @param {Array} array The array to query.
|
||
* @param {number} [n=1] The number of elements to drop.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {Array} Returns the slice of `array`.
|
||
* @example
|
||
*
|
||
* _.drop([1, 2, 3]);
|
||
* // => [2, 3]
|
||
*
|
||
* _.drop([1, 2, 3], 2);
|
||
* // => [3]
|
||
*
|
||
* _.drop([1, 2, 3], 5);
|
||
* // => []
|
||
*
|
||
* _.drop([1, 2, 3], 0);
|
||
* // => [1, 2, 3]
|
||
*/
|
||
function drop(array, n, guard) {
|
||
var length = array ? array.length : 0;
|
||
if (!length) {
|
||
return [];
|
||
}
|
||
n = (guard || n === undefined) ? 1 : toInteger(n);
|
||
return baseSlice(array, n < 0 ? 0 : n, length);
|
||
}
|
||
|
||
/**
|
||
* Creates a slice of `array` with `n` elements dropped from the end.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to query.
|
||
* @param {number} [n=1] The number of elements to drop.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {Array} Returns the slice of `array`.
|
||
* @example
|
||
*
|
||
* _.dropRight([1, 2, 3]);
|
||
* // => [1, 2]
|
||
*
|
||
* _.dropRight([1, 2, 3], 2);
|
||
* // => [1]
|
||
*
|
||
* _.dropRight([1, 2, 3], 5);
|
||
* // => []
|
||
*
|
||
* _.dropRight([1, 2, 3], 0);
|
||
* // => [1, 2, 3]
|
||
*/
|
||
function dropRight(array, n, guard) {
|
||
var length = array ? array.length : 0;
|
||
if (!length) {
|
||
return [];
|
||
}
|
||
n = (guard || n === undefined) ? 1 : toInteger(n);
|
||
n = length - n;
|
||
return baseSlice(array, 0, n < 0 ? 0 : n);
|
||
}
|
||
|
||
/**
|
||
* Creates a slice of `array` excluding elements dropped from the end.
|
||
* Elements are dropped until `predicate` returns falsey. The predicate is
|
||
* invoked with three arguments: (value, index, array).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to query.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {Array} Returns the slice of `array`.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'active': true },
|
||
* { 'user': 'fred', 'active': false },
|
||
* { 'user': 'pebbles', 'active': false }
|
||
* ];
|
||
*
|
||
* _.dropRightWhile(users, function(o) { return !o.active; });
|
||
* // => objects for ['barney']
|
||
*
|
||
* // The `_.matches` iteratee shorthand.
|
||
* _.dropRightWhile(users, { 'user': 'pebbles', 'active': false });
|
||
* // => objects for ['barney', 'fred']
|
||
*
|
||
* // The `_.matchesProperty` iteratee shorthand.
|
||
* _.dropRightWhile(users, ['active', false]);
|
||
* // => objects for ['barney']
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.dropRightWhile(users, 'active');
|
||
* // => objects for ['barney', 'fred', 'pebbles']
|
||
*/
|
||
function dropRightWhile(array, predicate) {
|
||
return (array && array.length)
|
||
? baseWhile(array, getIteratee(predicate, 3), true, true)
|
||
: [];
|
||
}
|
||
|
||
/**
|
||
* Creates a slice of `array` excluding elements dropped from the beginning.
|
||
* Elements are dropped until `predicate` returns falsey. The predicate is
|
||
* invoked with three arguments: (value, index, array).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to query.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {Array} Returns the slice of `array`.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'active': false },
|
||
* { 'user': 'fred', 'active': false },
|
||
* { 'user': 'pebbles', 'active': true }
|
||
* ];
|
||
*
|
||
* _.dropWhile(users, function(o) { return !o.active; });
|
||
* // => objects for ['pebbles']
|
||
*
|
||
* // The `_.matches` iteratee shorthand.
|
||
* _.dropWhile(users, { 'user': 'barney', 'active': false });
|
||
* // => objects for ['fred', 'pebbles']
|
||
*
|
||
* // The `_.matchesProperty` iteratee shorthand.
|
||
* _.dropWhile(users, ['active', false]);
|
||
* // => objects for ['pebbles']
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.dropWhile(users, 'active');
|
||
* // => objects for ['barney', 'fred', 'pebbles']
|
||
*/
|
||
function dropWhile(array, predicate) {
|
||
return (array && array.length)
|
||
? baseWhile(array, getIteratee(predicate, 3), true)
|
||
: [];
|
||
}
|
||
|
||
/**
|
||
* Fills elements of `array` with `value` from `start` up to, but not
|
||
* including, `end`.
|
||
*
|
||
* **Note:** This method mutates `array`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.2.0
|
||
* @category Array
|
||
* @param {Array} array The array to fill.
|
||
* @param {*} value The value to fill `array` with.
|
||
* @param {number} [start=0] The start position.
|
||
* @param {number} [end=array.length] The end position.
|
||
* @returns {Array} Returns `array`.
|
||
* @example
|
||
*
|
||
* var array = [1, 2, 3];
|
||
*
|
||
* _.fill(array, 'a');
|
||
* console.log(array);
|
||
* // => ['a', 'a', 'a']
|
||
*
|
||
* _.fill(Array(3), 2);
|
||
* // => [2, 2, 2]
|
||
*
|
||
* _.fill([4, 6, 8, 10], '*', 1, 3);
|
||
* // => [4, '*', '*', 10]
|
||
*/
|
||
function fill(array, value, start, end) {
|
||
var length = array ? array.length : 0;
|
||
if (!length) {
|
||
return [];
|
||
}
|
||
if (start && typeof start != 'number' && isIterateeCall(array, value, start)) {
|
||
start = 0;
|
||
end = length;
|
||
}
|
||
return baseFill(array, value, start, end);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.find` except that it returns the index of the first
|
||
* element `predicate` returns truthy for instead of the element itself.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 1.1.0
|
||
* @category Array
|
||
* @param {Array} array The array to search.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {number} Returns the index of the found element, else `-1`.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'active': false },
|
||
* { 'user': 'fred', 'active': false },
|
||
* { 'user': 'pebbles', 'active': true }
|
||
* ];
|
||
*
|
||
* _.findIndex(users, function(o) { return o.user == 'barney'; });
|
||
* // => 0
|
||
*
|
||
* // The `_.matches` iteratee shorthand.
|
||
* _.findIndex(users, { 'user': 'fred', 'active': false });
|
||
* // => 1
|
||
*
|
||
* // The `_.matchesProperty` iteratee shorthand.
|
||
* _.findIndex(users, ['active', false]);
|
||
* // => 0
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.findIndex(users, 'active');
|
||
* // => 2
|
||
*/
|
||
function findIndex(array, predicate) {
|
||
return (array && array.length)
|
||
? baseFindIndex(array, getIteratee(predicate, 3))
|
||
: -1;
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.findIndex` except that it iterates over elements
|
||
* of `collection` from right to left.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to search.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {number} Returns the index of the found element, else `-1`.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'active': true },
|
||
* { 'user': 'fred', 'active': false },
|
||
* { 'user': 'pebbles', 'active': false }
|
||
* ];
|
||
*
|
||
* _.findLastIndex(users, function(o) { return o.user == 'pebbles'; });
|
||
* // => 2
|
||
*
|
||
* // The `_.matches` iteratee shorthand.
|
||
* _.findLastIndex(users, { 'user': 'barney', 'active': true });
|
||
* // => 0
|
||
*
|
||
* // The `_.matchesProperty` iteratee shorthand.
|
||
* _.findLastIndex(users, ['active', false]);
|
||
* // => 2
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.findLastIndex(users, 'active');
|
||
* // => 0
|
||
*/
|
||
function findLastIndex(array, predicate) {
|
||
return (array && array.length)
|
||
? baseFindIndex(array, getIteratee(predicate, 3), true)
|
||
: -1;
|
||
}
|
||
|
||
/**
|
||
* Flattens `array` a single level deep.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Array
|
||
* @param {Array} array The array to flatten.
|
||
* @returns {Array} Returns the new flattened array.
|
||
* @example
|
||
*
|
||
* _.flatten([1, [2, [3, [4]], 5]]);
|
||
* // => [1, 2, [3, [4]], 5]
|
||
*/
|
||
function flatten(array) {
|
||
var length = array ? array.length : 0;
|
||
return length ? baseFlatten(array, 1) : [];
|
||
}
|
||
|
||
/**
|
||
* Recursively flattens `array`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to flatten.
|
||
* @returns {Array} Returns the new flattened array.
|
||
* @example
|
||
*
|
||
* _.flattenDeep([1, [2, [3, [4]], 5]]);
|
||
* // => [1, 2, 3, 4, 5]
|
||
*/
|
||
function flattenDeep(array) {
|
||
var length = array ? array.length : 0;
|
||
return length ? baseFlatten(array, INFINITY) : [];
|
||
}
|
||
|
||
/**
|
||
* Recursively flatten `array` up to `depth` times.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.4.0
|
||
* @category Array
|
||
* @param {Array} array The array to flatten.
|
||
* @param {number} [depth=1] The maximum recursion depth.
|
||
* @returns {Array} Returns the new flattened array.
|
||
* @example
|
||
*
|
||
* var array = [1, [2, [3, [4]], 5]];
|
||
*
|
||
* _.flattenDepth(array, 1);
|
||
* // => [1, 2, [3, [4]], 5]
|
||
*
|
||
* _.flattenDepth(array, 2);
|
||
* // => [1, 2, 3, [4], 5]
|
||
*/
|
||
function flattenDepth(array, depth) {
|
||
var length = array ? array.length : 0;
|
||
if (!length) {
|
||
return [];
|
||
}
|
||
depth = depth === undefined ? 1 : toInteger(depth);
|
||
return baseFlatten(array, depth);
|
||
}
|
||
|
||
/**
|
||
* The inverse of `_.toPairs`; this method returns an object composed
|
||
* from key-value `pairs`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} pairs The key-value pairs.
|
||
* @returns {Object} Returns the new object.
|
||
* @example
|
||
*
|
||
* _.fromPairs([['fred', 30], ['barney', 40]]);
|
||
* // => { 'fred': 30, 'barney': 40 }
|
||
*/
|
||
function fromPairs(pairs) {
|
||
var index = -1,
|
||
length = pairs ? pairs.length : 0,
|
||
result = {};
|
||
|
||
while (++index < length) {
|
||
var pair = pairs[index];
|
||
result[pair[0]] = pair[1];
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Gets the first element of `array`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @alias first
|
||
* @category Array
|
||
* @param {Array} array The array to query.
|
||
* @returns {*} Returns the first element of `array`.
|
||
* @example
|
||
*
|
||
* _.head([1, 2, 3]);
|
||
* // => 1
|
||
*
|
||
* _.head([]);
|
||
* // => undefined
|
||
*/
|
||
function head(array) {
|
||
return (array && array.length) ? array[0] : undefined;
|
||
}
|
||
|
||
/**
|
||
* Gets the index at which the first occurrence of `value` is found in `array`
|
||
* using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
|
||
* for equality comparisons. If `fromIndex` is negative, it's used as the
|
||
* offset from the end of `array`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Array
|
||
* @param {Array} array The array to search.
|
||
* @param {*} value The value to search for.
|
||
* @param {number} [fromIndex=0] The index to search from.
|
||
* @returns {number} Returns the index of the matched value, else `-1`.
|
||
* @example
|
||
*
|
||
* _.indexOf([1, 2, 1, 2], 2);
|
||
* // => 1
|
||
*
|
||
* // Search from the `fromIndex`.
|
||
* _.indexOf([1, 2, 1, 2], 2, 2);
|
||
* // => 3
|
||
*/
|
||
function indexOf(array, value, fromIndex) {
|
||
var length = array ? array.length : 0;
|
||
if (!length) {
|
||
return -1;
|
||
}
|
||
fromIndex = toInteger(fromIndex);
|
||
if (fromIndex < 0) {
|
||
fromIndex = nativeMax(length + fromIndex, 0);
|
||
}
|
||
return baseIndexOf(array, value, fromIndex);
|
||
}
|
||
|
||
/**
|
||
* Gets all but the last element of `array`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Array
|
||
* @param {Array} array The array to query.
|
||
* @returns {Array} Returns the slice of `array`.
|
||
* @example
|
||
*
|
||
* _.initial([1, 2, 3]);
|
||
* // => [1, 2]
|
||
*/
|
||
function initial(array) {
|
||
return dropRight(array, 1);
|
||
}
|
||
|
||
/**
|
||
* Creates an array of unique values that are included in all given arrays
|
||
* using [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
|
||
* for equality comparisons. The order of result values is determined by the
|
||
* order they occur in the first array.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Array
|
||
* @param {...Array} [arrays] The arrays to inspect.
|
||
* @returns {Array} Returns the new array of intersecting values.
|
||
* @example
|
||
*
|
||
* _.intersection([2, 1], [4, 2], [1, 2]);
|
||
* // => [2]
|
||
*/
|
||
var intersection = rest(function(arrays) {
|
||
var mapped = arrayMap(arrays, castArrayLikeObject);
|
||
return (mapped.length && mapped[0] === arrays[0])
|
||
? baseIntersection(mapped)
|
||
: [];
|
||
});
|
||
|
||
/**
|
||
* This method is like `_.intersection` except that it accepts `iteratee`
|
||
* which is invoked for each element of each `arrays` to generate the criterion
|
||
* by which they're compared. Result values are chosen from the first array.
|
||
* The iteratee is invoked with one argument: (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {...Array} [arrays] The arrays to inspect.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee invoked per element.
|
||
* @returns {Array} Returns the new array of intersecting values.
|
||
* @example
|
||
*
|
||
* _.intersectionBy([2.1, 1.2], [4.3, 2.4], Math.floor);
|
||
* // => [2.1]
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.intersectionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
|
||
* // => [{ 'x': 1 }]
|
||
*/
|
||
var intersectionBy = rest(function(arrays) {
|
||
var iteratee = last(arrays),
|
||
mapped = arrayMap(arrays, castArrayLikeObject);
|
||
|
||
if (iteratee === last(mapped)) {
|
||
iteratee = undefined;
|
||
} else {
|
||
mapped.pop();
|
||
}
|
||
return (mapped.length && mapped[0] === arrays[0])
|
||
? baseIntersection(mapped, getIteratee(iteratee))
|
||
: [];
|
||
});
|
||
|
||
/**
|
||
* This method is like `_.intersection` except that it accepts `comparator`
|
||
* which is invoked to compare elements of `arrays`. Result values are chosen
|
||
* from the first array. The comparator is invoked with two arguments:
|
||
* (arrVal, othVal).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {...Array} [arrays] The arrays to inspect.
|
||
* @param {Function} [comparator] The comparator invoked per element.
|
||
* @returns {Array} Returns the new array of intersecting values.
|
||
* @example
|
||
*
|
||
* var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
|
||
* var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
|
||
*
|
||
* _.intersectionWith(objects, others, _.isEqual);
|
||
* // => [{ 'x': 1, 'y': 2 }]
|
||
*/
|
||
var intersectionWith = rest(function(arrays) {
|
||
var comparator = last(arrays),
|
||
mapped = arrayMap(arrays, castArrayLikeObject);
|
||
|
||
if (comparator === last(mapped)) {
|
||
comparator = undefined;
|
||
} else {
|
||
mapped.pop();
|
||
}
|
||
return (mapped.length && mapped[0] === arrays[0])
|
||
? baseIntersection(mapped, undefined, comparator)
|
||
: [];
|
||
});
|
||
|
||
/**
|
||
* Converts all elements in `array` into a string separated by `separator`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to convert.
|
||
* @param {string} [separator=','] The element separator.
|
||
* @returns {string} Returns the joined string.
|
||
* @example
|
||
*
|
||
* _.join(['a', 'b', 'c'], '~');
|
||
* // => 'a~b~c'
|
||
*/
|
||
function join(array, separator) {
|
||
return array ? nativeJoin.call(array, separator) : '';
|
||
}
|
||
|
||
/**
|
||
* Gets the last element of `array`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Array
|
||
* @param {Array} array The array to query.
|
||
* @returns {*} Returns the last element of `array`.
|
||
* @example
|
||
*
|
||
* _.last([1, 2, 3]);
|
||
* // => 3
|
||
*/
|
||
function last(array) {
|
||
var length = array ? array.length : 0;
|
||
return length ? array[length - 1] : undefined;
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.indexOf` except that it iterates over elements of
|
||
* `array` from right to left.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Array
|
||
* @param {Array} array The array to search.
|
||
* @param {*} 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, else `-1`.
|
||
* @example
|
||
*
|
||
* _.lastIndexOf([1, 2, 1, 2], 2);
|
||
* // => 3
|
||
*
|
||
* // Search from the `fromIndex`.
|
||
* _.lastIndexOf([1, 2, 1, 2], 2, 2);
|
||
* // => 1
|
||
*/
|
||
function lastIndexOf(array, value, fromIndex) {
|
||
var length = array ? array.length : 0;
|
||
if (!length) {
|
||
return -1;
|
||
}
|
||
var index = length;
|
||
if (fromIndex !== undefined) {
|
||
index = toInteger(fromIndex);
|
||
index = (
|
||
index < 0
|
||
? nativeMax(length + index, 0)
|
||
: nativeMin(index, length - 1)
|
||
) + 1;
|
||
}
|
||
if (value !== value) {
|
||
return indexOfNaN(array, index, true);
|
||
}
|
||
while (index--) {
|
||
if (array[index] === value) {
|
||
return index;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* Gets the nth element of `array`. If `n` is negative, the nth element
|
||
* from the end is returned.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.11.0
|
||
* @category Array
|
||
* @param {Array} array The array to query.
|
||
* @param {number} [n=0] The index of the element to return.
|
||
* @returns {*} Returns the nth element of `array`.
|
||
* @example
|
||
*
|
||
* var array = ['a', 'b', 'c', 'd'];
|
||
*
|
||
* _.nth(array, 1);
|
||
* // => 'b'
|
||
*
|
||
* _.nth(array, -2);
|
||
* // => 'c';
|
||
*/
|
||
function nth(array, n) {
|
||
return (array && array.length) ? baseNth(array, toInteger(n)) : undefined;
|
||
}
|
||
|
||
/**
|
||
* Removes all given values from `array` using
|
||
* [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
|
||
* for equality comparisons.
|
||
*
|
||
* **Note:** Unlike `_.without`, this method mutates `array`. Use `_.remove`
|
||
* to remove elements from an array by predicate.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to modify.
|
||
* @param {...*} [values] The values to remove.
|
||
* @returns {Array} Returns `array`.
|
||
* @example
|
||
*
|
||
* var array = [1, 2, 3, 1, 2, 3];
|
||
*
|
||
* _.pull(array, 2, 3);
|
||
* console.log(array);
|
||
* // => [1, 1]
|
||
*/
|
||
var pull = rest(pullAll);
|
||
|
||
/**
|
||
* This method is like `_.pull` except that it accepts an array of values to remove.
|
||
*
|
||
* **Note:** Unlike `_.difference`, this method mutates `array`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to modify.
|
||
* @param {Array} values The values to remove.
|
||
* @returns {Array} Returns `array`.
|
||
* @example
|
||
*
|
||
* var array = [1, 2, 3, 1, 2, 3];
|
||
*
|
||
* _.pullAll(array, [2, 3]);
|
||
* console.log(array);
|
||
* // => [1, 1]
|
||
*/
|
||
function pullAll(array, values) {
|
||
return (array && array.length && values && values.length)
|
||
? basePullAll(array, values)
|
||
: array;
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.pullAll` except that it accepts `iteratee` which is
|
||
* invoked for each element of `array` and `values` to generate the criterion
|
||
* by which they're compared. The iteratee is invoked with one argument: (value).
|
||
*
|
||
* **Note:** Unlike `_.differenceBy`, this method mutates `array`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to modify.
|
||
* @param {Array} values The values to remove.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee invoked per element.
|
||
* @returns {Array} Returns `array`.
|
||
* @example
|
||
*
|
||
* var array = [{ 'x': 1 }, { 'x': 2 }, { 'x': 3 }, { 'x': 1 }];
|
||
*
|
||
* _.pullAllBy(array, [{ 'x': 1 }, { 'x': 3 }], 'x');
|
||
* console.log(array);
|
||
* // => [{ 'x': 2 }]
|
||
*/
|
||
function pullAllBy(array, values, iteratee) {
|
||
return (array && array.length && values && values.length)
|
||
? basePullAll(array, values, getIteratee(iteratee))
|
||
: array;
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.pullAll` except that it accepts `comparator` which
|
||
* is invoked to compare elements of `array` to `values`. The comparator is
|
||
* invoked with two arguments: (arrVal, othVal).
|
||
*
|
||
* **Note:** Unlike `_.differenceWith`, this method mutates `array`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.6.0
|
||
* @category Array
|
||
* @param {Array} array The array to modify.
|
||
* @param {Array} values The values to remove.
|
||
* @param {Function} [comparator] The comparator invoked per element.
|
||
* @returns {Array} Returns `array`.
|
||
* @example
|
||
*
|
||
* var array = [{ 'x': 1, 'y': 2 }, { 'x': 3, 'y': 4 }, { 'x': 5, 'y': 6 }];
|
||
*
|
||
* _.pullAllWith(array, [{ 'x': 3, 'y': 4 }], _.isEqual);
|
||
* console.log(array);
|
||
* // => [{ 'x': 1, 'y': 2 }, { 'x': 5, 'y': 6 }]
|
||
*/
|
||
function pullAllWith(array, values, comparator) {
|
||
return (array && array.length && values && values.length)
|
||
? basePullAll(array, values, undefined, comparator)
|
||
: array;
|
||
}
|
||
|
||
/**
|
||
* Removes elements from `array` corresponding to `indexes` and returns an
|
||
* array of removed elements.
|
||
*
|
||
* **Note:** Unlike `_.at`, this method mutates `array`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to modify.
|
||
* @param {...(number|number[])} [indexes] The indexes of elements to remove.
|
||
* @returns {Array} Returns the new array of removed elements.
|
||
* @example
|
||
*
|
||
* var array = [5, 10, 15, 20];
|
||
* var evens = _.pullAt(array, 1, 3);
|
||
*
|
||
* console.log(array);
|
||
* // => [5, 15]
|
||
*
|
||
* console.log(evens);
|
||
* // => [10, 20]
|
||
*/
|
||
var pullAt = rest(function(array, indexes) {
|
||
indexes = arrayMap(baseFlatten(indexes, 1), String);
|
||
|
||
var result = baseAt(array, indexes);
|
||
basePullAt(array, indexes.sort(compareAscending));
|
||
return result;
|
||
});
|
||
|
||
/**
|
||
* Removes all elements from `array` that `predicate` returns truthy for
|
||
* and returns an array of the removed elements. The predicate is invoked
|
||
* with three arguments: (value, index, array).
|
||
*
|
||
* **Note:** Unlike `_.filter`, this method mutates `array`. Use `_.pull`
|
||
* to pull elements from an array by value.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to modify.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {Array} Returns the new array of removed elements.
|
||
* @example
|
||
*
|
||
* var array = [1, 2, 3, 4];
|
||
* var evens = _.remove(array, function(n) {
|
||
* return n % 2 == 0;
|
||
* });
|
||
*
|
||
* console.log(array);
|
||
* // => [1, 3]
|
||
*
|
||
* console.log(evens);
|
||
* // => [2, 4]
|
||
*/
|
||
function remove(array, predicate) {
|
||
var result = [];
|
||
if (!(array && array.length)) {
|
||
return result;
|
||
}
|
||
var index = -1,
|
||
indexes = [],
|
||
length = array.length;
|
||
|
||
predicate = getIteratee(predicate, 3);
|
||
while (++index < length) {
|
||
var value = array[index];
|
||
if (predicate(value, index, array)) {
|
||
result.push(value);
|
||
indexes.push(index);
|
||
}
|
||
}
|
||
basePullAt(array, indexes);
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Reverses `array` so that the first element becomes the last, the second
|
||
* element becomes the second to last, and so on.
|
||
*
|
||
* **Note:** This method mutates `array` and is based on
|
||
* [`Array#reverse`](https://mdn.io/Array/reverse).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to modify.
|
||
* @returns {Array} Returns `array`.
|
||
* @example
|
||
*
|
||
* var array = [1, 2, 3];
|
||
*
|
||
* _.reverse(array);
|
||
* // => [3, 2, 1]
|
||
*
|
||
* console.log(array);
|
||
* // => [3, 2, 1]
|
||
*/
|
||
function reverse(array) {
|
||
return array ? nativeReverse.call(array) : array;
|
||
}
|
||
|
||
/**
|
||
* Creates a slice of `array` from `start` up to, but not including, `end`.
|
||
*
|
||
* **Note:** This method is used instead of
|
||
* [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are
|
||
* returned.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to slice.
|
||
* @param {number} [start=0] The start position.
|
||
* @param {number} [end=array.length] The end position.
|
||
* @returns {Array} Returns the slice of `array`.
|
||
*/
|
||
function slice(array, start, end) {
|
||
var length = array ? array.length : 0;
|
||
if (!length) {
|
||
return [];
|
||
}
|
||
if (end && typeof end != 'number' && isIterateeCall(array, start, end)) {
|
||
start = 0;
|
||
end = length;
|
||
}
|
||
else {
|
||
start = start == null ? 0 : toInteger(start);
|
||
end = end === undefined ? length : toInteger(end);
|
||
}
|
||
return baseSlice(array, start, end);
|
||
}
|
||
|
||
/**
|
||
* Uses a binary search to determine the lowest index at which `value`
|
||
* should be inserted into `array` in order to maintain its sort order.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Array
|
||
* @param {Array} array The sorted array to inspect.
|
||
* @param {*} value The value to evaluate.
|
||
* @returns {number} Returns the index at which `value` should be inserted
|
||
* into `array`.
|
||
* @example
|
||
*
|
||
* _.sortedIndex([30, 50], 40);
|
||
* // => 1
|
||
*
|
||
* _.sortedIndex([4, 5], 4);
|
||
* // => 0
|
||
*/
|
||
function sortedIndex(array, value) {
|
||
return baseSortedIndex(array, value);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.sortedIndex` except that it accepts `iteratee`
|
||
* which is invoked for `value` and each element of `array` to compute their
|
||
* sort ranking. The iteratee is invoked with one argument: (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The sorted array to inspect.
|
||
* @param {*} value The value to evaluate.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee invoked per element.
|
||
* @returns {number} Returns the index at which `value` should be inserted
|
||
* into `array`.
|
||
* @example
|
||
*
|
||
* var dict = { 'thirty': 30, 'forty': 40, 'fifty': 50 };
|
||
*
|
||
* _.sortedIndexBy(['thirty', 'fifty'], 'forty', _.propertyOf(dict));
|
||
* // => 1
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.sortedIndexBy([{ 'x': 4 }, { 'x': 5 }], { 'x': 4 }, 'x');
|
||
* // => 0
|
||
*/
|
||
function sortedIndexBy(array, value, iteratee) {
|
||
return baseSortedIndexBy(array, value, getIteratee(iteratee));
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.indexOf` except that it performs a binary
|
||
* search on a sorted `array`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to search.
|
||
* @param {*} value The value to search for.
|
||
* @returns {number} Returns the index of the matched value, else `-1`.
|
||
* @example
|
||
*
|
||
* _.sortedIndexOf([1, 1, 2, 2], 2);
|
||
* // => 2
|
||
*/
|
||
function sortedIndexOf(array, value) {
|
||
var length = array ? array.length : 0;
|
||
if (length) {
|
||
var index = baseSortedIndex(array, value);
|
||
if (index < length && eq(array[index], value)) {
|
||
return index;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.sortedIndex` except that it returns the highest
|
||
* index at which `value` should be inserted into `array` in order to
|
||
* maintain its sort order.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Array
|
||
* @param {Array} array The sorted array to inspect.
|
||
* @param {*} value The value to evaluate.
|
||
* @returns {number} Returns the index at which `value` should be inserted
|
||
* into `array`.
|
||
* @example
|
||
*
|
||
* _.sortedLastIndex([4, 5], 4);
|
||
* // => 1
|
||
*/
|
||
function sortedLastIndex(array, value) {
|
||
return baseSortedIndex(array, value, true);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.sortedLastIndex` except that it accepts `iteratee`
|
||
* which is invoked for `value` and each element of `array` to compute their
|
||
* sort ranking. The iteratee is invoked with one argument: (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The sorted array to inspect.
|
||
* @param {*} value The value to evaluate.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee invoked per element.
|
||
* @returns {number} Returns the index at which `value` should be inserted
|
||
* into `array`.
|
||
* @example
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.sortedLastIndexBy([{ 'x': 4 }, { 'x': 5 }], { 'x': 4 }, 'x');
|
||
* // => 1
|
||
*/
|
||
function sortedLastIndexBy(array, value, iteratee) {
|
||
return baseSortedIndexBy(array, value, getIteratee(iteratee), true);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.lastIndexOf` except that it performs a binary
|
||
* search on a sorted `array`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to search.
|
||
* @param {*} value The value to search for.
|
||
* @returns {number} Returns the index of the matched value, else `-1`.
|
||
* @example
|
||
*
|
||
* _.sortedLastIndexOf([1, 1, 2, 2], 2);
|
||
* // => 3
|
||
*/
|
||
function sortedLastIndexOf(array, value) {
|
||
var length = array ? array.length : 0;
|
||
if (length) {
|
||
var index = baseSortedIndex(array, value, true) - 1;
|
||
if (eq(array[index], value)) {
|
||
return index;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.uniq` except that it's designed and optimized
|
||
* for sorted arrays.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to inspect.
|
||
* @returns {Array} Returns the new duplicate free array.
|
||
* @example
|
||
*
|
||
* _.sortedUniq([1, 1, 2]);
|
||
* // => [1, 2]
|
||
*/
|
||
function sortedUniq(array) {
|
||
return (array && array.length)
|
||
? baseSortedUniq(array)
|
||
: [];
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.uniqBy` except that it's designed and optimized
|
||
* for sorted arrays.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to inspect.
|
||
* @param {Function} [iteratee] The iteratee invoked per element.
|
||
* @returns {Array} Returns the new duplicate free array.
|
||
* @example
|
||
*
|
||
* _.sortedUniqBy([1.1, 1.2, 2.3, 2.4], Math.floor);
|
||
* // => [1.1, 2.3]
|
||
*/
|
||
function sortedUniqBy(array, iteratee) {
|
||
return (array && array.length)
|
||
? baseSortedUniqBy(array, getIteratee(iteratee))
|
||
: [];
|
||
}
|
||
|
||
/**
|
||
* Gets all but the first element of `array`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to query.
|
||
* @returns {Array} Returns the slice of `array`.
|
||
* @example
|
||
*
|
||
* _.tail([1, 2, 3]);
|
||
* // => [2, 3]
|
||
*/
|
||
function tail(array) {
|
||
return drop(array, 1);
|
||
}
|
||
|
||
/**
|
||
* Creates a slice of `array` with `n` elements taken from the beginning.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Array
|
||
* @param {Array} array The array to query.
|
||
* @param {number} [n=1] The number of elements to take.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {Array} Returns the slice of `array`.
|
||
* @example
|
||
*
|
||
* _.take([1, 2, 3]);
|
||
* // => [1]
|
||
*
|
||
* _.take([1, 2, 3], 2);
|
||
* // => [1, 2]
|
||
*
|
||
* _.take([1, 2, 3], 5);
|
||
* // => [1, 2, 3]
|
||
*
|
||
* _.take([1, 2, 3], 0);
|
||
* // => []
|
||
*/
|
||
function take(array, n, guard) {
|
||
if (!(array && array.length)) {
|
||
return [];
|
||
}
|
||
n = (guard || n === undefined) ? 1 : toInteger(n);
|
||
return baseSlice(array, 0, n < 0 ? 0 : n);
|
||
}
|
||
|
||
/**
|
||
* Creates a slice of `array` with `n` elements taken from the end.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to query.
|
||
* @param {number} [n=1] The number of elements to take.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {Array} Returns the slice of `array`.
|
||
* @example
|
||
*
|
||
* _.takeRight([1, 2, 3]);
|
||
* // => [3]
|
||
*
|
||
* _.takeRight([1, 2, 3], 2);
|
||
* // => [2, 3]
|
||
*
|
||
* _.takeRight([1, 2, 3], 5);
|
||
* // => [1, 2, 3]
|
||
*
|
||
* _.takeRight([1, 2, 3], 0);
|
||
* // => []
|
||
*/
|
||
function takeRight(array, n, guard) {
|
||
var length = array ? array.length : 0;
|
||
if (!length) {
|
||
return [];
|
||
}
|
||
n = (guard || n === undefined) ? 1 : toInteger(n);
|
||
n = length - n;
|
||
return baseSlice(array, n < 0 ? 0 : n, length);
|
||
}
|
||
|
||
/**
|
||
* Creates a slice of `array` with elements taken from the end. Elements are
|
||
* taken until `predicate` returns falsey. The predicate is invoked with
|
||
* three arguments: (value, index, array).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to query.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {Array} Returns the slice of `array`.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'active': true },
|
||
* { 'user': 'fred', 'active': false },
|
||
* { 'user': 'pebbles', 'active': false }
|
||
* ];
|
||
*
|
||
* _.takeRightWhile(users, function(o) { return !o.active; });
|
||
* // => objects for ['fred', 'pebbles']
|
||
*
|
||
* // The `_.matches` iteratee shorthand.
|
||
* _.takeRightWhile(users, { 'user': 'pebbles', 'active': false });
|
||
* // => objects for ['pebbles']
|
||
*
|
||
* // The `_.matchesProperty` iteratee shorthand.
|
||
* _.takeRightWhile(users, ['active', false]);
|
||
* // => objects for ['fred', 'pebbles']
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.takeRightWhile(users, 'active');
|
||
* // => []
|
||
*/
|
||
function takeRightWhile(array, predicate) {
|
||
return (array && array.length)
|
||
? baseWhile(array, getIteratee(predicate, 3), false, true)
|
||
: [];
|
||
}
|
||
|
||
/**
|
||
* Creates a slice of `array` with elements taken from the beginning. Elements
|
||
* are taken until `predicate` returns falsey. The predicate is invoked with
|
||
* three arguments: (value, index, array).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to query.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {Array} Returns the slice of `array`.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'active': false },
|
||
* { 'user': 'fred', 'active': false},
|
||
* { 'user': 'pebbles', 'active': true }
|
||
* ];
|
||
*
|
||
* _.takeWhile(users, function(o) { return !o.active; });
|
||
* // => objects for ['barney', 'fred']
|
||
*
|
||
* // The `_.matches` iteratee shorthand.
|
||
* _.takeWhile(users, { 'user': 'barney', 'active': false });
|
||
* // => objects for ['barney']
|
||
*
|
||
* // The `_.matchesProperty` iteratee shorthand.
|
||
* _.takeWhile(users, ['active', false]);
|
||
* // => objects for ['barney', 'fred']
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.takeWhile(users, 'active');
|
||
* // => []
|
||
*/
|
||
function takeWhile(array, predicate) {
|
||
return (array && array.length)
|
||
? baseWhile(array, getIteratee(predicate, 3))
|
||
: [];
|
||
}
|
||
|
||
/**
|
||
* Creates an array of unique values, in order, from all given arrays using
|
||
* [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
|
||
* for equality comparisons.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Array
|
||
* @param {...Array} [arrays] The arrays to inspect.
|
||
* @returns {Array} Returns the new array of combined values.
|
||
* @example
|
||
*
|
||
* _.union([2, 1], [4, 2], [1, 2]);
|
||
* // => [2, 1, 4]
|
||
*/
|
||
var union = rest(function(arrays) {
|
||
return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true));
|
||
});
|
||
|
||
/**
|
||
* This method is like `_.union` except that it accepts `iteratee` which is
|
||
* invoked for each element of each `arrays` to generate the criterion by
|
||
* which uniqueness is computed. The iteratee is invoked with one argument:
|
||
* (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {...Array} [arrays] The arrays to inspect.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee invoked per element.
|
||
* @returns {Array} Returns the new array of combined values.
|
||
* @example
|
||
*
|
||
* _.unionBy([2.1, 1.2], [4.3, 2.4], Math.floor);
|
||
* // => [2.1, 1.2, 4.3]
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.unionBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
|
||
* // => [{ 'x': 1 }, { 'x': 2 }]
|
||
*/
|
||
var unionBy = rest(function(arrays) {
|
||
var iteratee = last(arrays);
|
||
if (isArrayLikeObject(iteratee)) {
|
||
iteratee = undefined;
|
||
}
|
||
return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), getIteratee(iteratee));
|
||
});
|
||
|
||
/**
|
||
* This method is like `_.union` except that it accepts `comparator` which
|
||
* is invoked to compare elements of `arrays`. The comparator is invoked
|
||
* with two arguments: (arrVal, othVal).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {...Array} [arrays] The arrays to inspect.
|
||
* @param {Function} [comparator] The comparator invoked per element.
|
||
* @returns {Array} Returns the new array of combined values.
|
||
* @example
|
||
*
|
||
* var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
|
||
* var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
|
||
*
|
||
* _.unionWith(objects, others, _.isEqual);
|
||
* // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
|
||
*/
|
||
var unionWith = rest(function(arrays) {
|
||
var comparator = last(arrays);
|
||
if (isArrayLikeObject(comparator)) {
|
||
comparator = undefined;
|
||
}
|
||
return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true), undefined, comparator);
|
||
});
|
||
|
||
/**
|
||
* Creates a duplicate-free version of an array, using
|
||
* [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
|
||
* for equality comparisons, in which only the first occurrence of each
|
||
* element is kept.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Array
|
||
* @param {Array} array The array to inspect.
|
||
* @returns {Array} Returns the new duplicate free array.
|
||
* @example
|
||
*
|
||
* _.uniq([2, 1, 2]);
|
||
* // => [2, 1]
|
||
*/
|
||
function uniq(array) {
|
||
return (array && array.length)
|
||
? baseUniq(array)
|
||
: [];
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.uniq` except that it accepts `iteratee` which is
|
||
* invoked for each element in `array` to generate the criterion by which
|
||
* uniqueness is computed. The iteratee is invoked with one argument: (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to inspect.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee invoked per element.
|
||
* @returns {Array} Returns the new duplicate free array.
|
||
* @example
|
||
*
|
||
* _.uniqBy([2.1, 1.2, 2.3], Math.floor);
|
||
* // => [2.1, 1.2]
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
|
||
* // => [{ 'x': 1 }, { 'x': 2 }]
|
||
*/
|
||
function uniqBy(array, iteratee) {
|
||
return (array && array.length)
|
||
? baseUniq(array, getIteratee(iteratee))
|
||
: [];
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.uniq` except that it accepts `comparator` which
|
||
* is invoked to compare elements of `array`. The comparator is invoked with
|
||
* two arguments: (arrVal, othVal).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {Array} array The array to inspect.
|
||
* @param {Function} [comparator] The comparator invoked per element.
|
||
* @returns {Array} Returns the new duplicate free array.
|
||
* @example
|
||
*
|
||
* var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
|
||
*
|
||
* _.uniqWith(objects, _.isEqual);
|
||
* // => [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }]
|
||
*/
|
||
function uniqWith(array, comparator) {
|
||
return (array && array.length)
|
||
? baseUniq(array, undefined, comparator)
|
||
: [];
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.zip` except that it accepts an array of grouped
|
||
* elements and creates an array regrouping the elements to their pre-zip
|
||
* configuration.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 1.2.0
|
||
* @category Array
|
||
* @param {Array} array The array of grouped elements to process.
|
||
* @returns {Array} Returns the new array of regrouped elements.
|
||
* @example
|
||
*
|
||
* var zipped = _.zip(['fred', 'barney'], [30, 40], [true, false]);
|
||
* // => [['fred', 30, true], ['barney', 40, false]]
|
||
*
|
||
* _.unzip(zipped);
|
||
* // => [['fred', 'barney'], [30, 40], [true, false]]
|
||
*/
|
||
function unzip(array) {
|
||
if (!(array && array.length)) {
|
||
return [];
|
||
}
|
||
var length = 0;
|
||
array = arrayFilter(array, function(group) {
|
||
if (isArrayLikeObject(group)) {
|
||
length = nativeMax(group.length, length);
|
||
return true;
|
||
}
|
||
});
|
||
return baseTimes(length, function(index) {
|
||
return arrayMap(array, baseProperty(index));
|
||
});
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.unzip` except that it accepts `iteratee` to specify
|
||
* how regrouped values should be combined. The iteratee is invoked with the
|
||
* elements of each group: (...group).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.8.0
|
||
* @category Array
|
||
* @param {Array} array The array of grouped elements to process.
|
||
* @param {Function} [iteratee=_.identity] The function to combine
|
||
* regrouped values.
|
||
* @returns {Array} Returns the new array of regrouped elements.
|
||
* @example
|
||
*
|
||
* var zipped = _.zip([1, 2], [10, 20], [100, 200]);
|
||
* // => [[1, 10, 100], [2, 20, 200]]
|
||
*
|
||
* _.unzipWith(zipped, _.add);
|
||
* // => [3, 30, 300]
|
||
*/
|
||
function unzipWith(array, iteratee) {
|
||
if (!(array && array.length)) {
|
||
return [];
|
||
}
|
||
var result = unzip(array);
|
||
if (iteratee == null) {
|
||
return result;
|
||
}
|
||
return arrayMap(result, function(group) {
|
||
return apply(iteratee, undefined, group);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Creates an array excluding all given values using
|
||
* [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
|
||
* for equality comparisons.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Array
|
||
* @param {Array} array The array to filter.
|
||
* @param {...*} [values] The values to exclude.
|
||
* @returns {Array} Returns the new array of filtered values.
|
||
* @example
|
||
*
|
||
* _.without([1, 2, 1, 3], 1, 2);
|
||
* // => [3]
|
||
*/
|
||
var without = rest(function(array, values) {
|
||
return isArrayLikeObject(array)
|
||
? baseDifference(array, values)
|
||
: [];
|
||
});
|
||
|
||
/**
|
||
* Creates an array of unique values that is the
|
||
* [symmetric difference](https://en.wikipedia.org/wiki/Symmetric_difference)
|
||
* of the given arrays. The order of result values is determined by the order
|
||
* they occur in the arrays.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.4.0
|
||
* @category Array
|
||
* @param {...Array} [arrays] The arrays to inspect.
|
||
* @returns {Array} Returns the new array of values.
|
||
* @example
|
||
*
|
||
* _.xor([2, 1], [4, 2]);
|
||
* // => [1, 4]
|
||
*/
|
||
var xor = rest(function(arrays) {
|
||
return baseXor(arrayFilter(arrays, isArrayLikeObject));
|
||
});
|
||
|
||
/**
|
||
* This method is like `_.xor` except that it accepts `iteratee` which is
|
||
* invoked for each element of each `arrays` to generate the criterion by
|
||
* which by which they're compared. The iteratee is invoked with one argument:
|
||
* (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {...Array} [arrays] The arrays to inspect.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee invoked per element.
|
||
* @returns {Array} Returns the new array of values.
|
||
* @example
|
||
*
|
||
* _.xorBy([2.1, 1.2], [4.3, 2.4], Math.floor);
|
||
* // => [1.2, 4.3]
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.xorBy([{ 'x': 1 }], [{ 'x': 2 }, { 'x': 1 }], 'x');
|
||
* // => [{ 'x': 2 }]
|
||
*/
|
||
var xorBy = rest(function(arrays) {
|
||
var iteratee = last(arrays);
|
||
if (isArrayLikeObject(iteratee)) {
|
||
iteratee = undefined;
|
||
}
|
||
return baseXor(arrayFilter(arrays, isArrayLikeObject), getIteratee(iteratee));
|
||
});
|
||
|
||
/**
|
||
* This method is like `_.xor` except that it accepts `comparator` which is
|
||
* invoked to compare elements of `arrays`. The comparator is invoked with
|
||
* two arguments: (arrVal, othVal).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Array
|
||
* @param {...Array} [arrays] The arrays to inspect.
|
||
* @param {Function} [comparator] The comparator invoked per element.
|
||
* @returns {Array} Returns the new array of values.
|
||
* @example
|
||
*
|
||
* var objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }];
|
||
* var others = [{ 'x': 1, 'y': 1 }, { 'x': 1, 'y': 2 }];
|
||
*
|
||
* _.xorWith(objects, others, _.isEqual);
|
||
* // => [{ 'x': 2, 'y': 1 }, { 'x': 1, 'y': 1 }]
|
||
*/
|
||
var xorWith = rest(function(arrays) {
|
||
var comparator = last(arrays);
|
||
if (isArrayLikeObject(comparator)) {
|
||
comparator = undefined;
|
||
}
|
||
return baseXor(arrayFilter(arrays, isArrayLikeObject), undefined, comparator);
|
||
});
|
||
|
||
/**
|
||
* Creates an array of grouped elements, the first of which contains the
|
||
* first elements of the given arrays, the second of which contains the
|
||
* second elements of the given arrays, and so on.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Array
|
||
* @param {...Array} [arrays] The arrays to process.
|
||
* @returns {Array} Returns the new array of grouped elements.
|
||
* @example
|
||
*
|
||
* _.zip(['fred', 'barney'], [30, 40], [true, false]);
|
||
* // => [['fred', 30, true], ['barney', 40, false]]
|
||
*/
|
||
var zip = rest(unzip);
|
||
|
||
/**
|
||
* This method is like `_.fromPairs` except that it accepts two arrays,
|
||
* one of property identifiers and one of corresponding values.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.4.0
|
||
* @category Array
|
||
* @param {Array} [props=[]] The property identifiers.
|
||
* @param {Array} [values=[]] The property values.
|
||
* @returns {Object} Returns the new object.
|
||
* @example
|
||
*
|
||
* _.zipObject(['a', 'b'], [1, 2]);
|
||
* // => { 'a': 1, 'b': 2 }
|
||
*/
|
||
function zipObject(props, values) {
|
||
return baseZipObject(props || [], values || [], assignValue);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.zipObject` except that it supports property paths.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.1.0
|
||
* @category Array
|
||
* @param {Array} [props=[]] The property identifiers.
|
||
* @param {Array} [values=[]] The property values.
|
||
* @returns {Object} Returns the new object.
|
||
* @example
|
||
*
|
||
* _.zipObjectDeep(['a.b[0].c', 'a.b[1].d'], [1, 2]);
|
||
* // => { 'a': { 'b': [{ 'c': 1 }, { 'd': 2 }] } }
|
||
*/
|
||
function zipObjectDeep(props, values) {
|
||
return baseZipObject(props || [], values || [], baseSet);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.zip` except that it accepts `iteratee` to specify
|
||
* how grouped values should be combined. The iteratee is invoked with the
|
||
* elements of each group: (...group).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.8.0
|
||
* @category Array
|
||
* @param {...Array} [arrays] The arrays to process.
|
||
* @param {Function} [iteratee=_.identity] The function to combine grouped values.
|
||
* @returns {Array} Returns the new array of grouped elements.
|
||
* @example
|
||
*
|
||
* _.zipWith([1, 2], [10, 20], [100, 200], function(a, b, c) {
|
||
* return a + b + c;
|
||
* });
|
||
* // => [111, 222]
|
||
*/
|
||
var zipWith = rest(function(arrays) {
|
||
var length = arrays.length,
|
||
iteratee = length > 1 ? arrays[length - 1] : undefined;
|
||
|
||
iteratee = typeof iteratee == 'function' ? (arrays.pop(), iteratee) : undefined;
|
||
return unzipWith(arrays, iteratee);
|
||
});
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Creates a `lodash` wrapper instance that wraps `value` with explicit method
|
||
* chain sequences enabled. The result of such sequences must be unwrapped
|
||
* with `_#value`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 1.3.0
|
||
* @category Seq
|
||
* @param {*} value The value to wrap.
|
||
* @returns {Object} Returns the new `lodash` wrapper instance.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'age': 36 },
|
||
* { 'user': 'fred', 'age': 40 },
|
||
* { 'user': 'pebbles', 'age': 1 }
|
||
* ];
|
||
*
|
||
* var youngest = _
|
||
* .chain(users)
|
||
* .sortBy('age')
|
||
* .map(function(o) {
|
||
* return o.user + ' is ' + o.age;
|
||
* })
|
||
* .head()
|
||
* .value();
|
||
* // => 'pebbles is 1'
|
||
*/
|
||
function chain(value) {
|
||
var result = lodash(value);
|
||
result.__chain__ = true;
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* This method invokes `interceptor` and returns `value`. The interceptor
|
||
* is invoked with one argument; (value). The purpose of this method is to
|
||
* "tap into" a method chain sequence in order to modify intermediate results.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Seq
|
||
* @param {*} value The value to provide to `interceptor`.
|
||
* @param {Function} interceptor The function to invoke.
|
||
* @returns {*} Returns `value`.
|
||
* @example
|
||
*
|
||
* _([1, 2, 3])
|
||
* .tap(function(array) {
|
||
* // Mutate input array.
|
||
* array.pop();
|
||
* })
|
||
* .reverse()
|
||
* .value();
|
||
* // => [2, 1]
|
||
*/
|
||
function tap(value, interceptor) {
|
||
interceptor(value);
|
||
return value;
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.tap` except that it returns the result of `interceptor`.
|
||
* The purpose of this method is to "pass thru" values replacing intermediate
|
||
* results in a method chain sequence.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Seq
|
||
* @param {*} value The value to provide to `interceptor`.
|
||
* @param {Function} interceptor The function to invoke.
|
||
* @returns {*} Returns the result of `interceptor`.
|
||
* @example
|
||
*
|
||
* _(' abc ')
|
||
* .chain()
|
||
* .trim()
|
||
* .thru(function(value) {
|
||
* return [value];
|
||
* })
|
||
* .value();
|
||
* // => ['abc']
|
||
*/
|
||
function thru(value, interceptor) {
|
||
return interceptor(value);
|
||
}
|
||
|
||
/**
|
||
* This method is the wrapper version of `_.at`.
|
||
*
|
||
* @name at
|
||
* @memberOf _
|
||
* @since 1.0.0
|
||
* @category Seq
|
||
* @param {...(string|string[])} [paths] The property paths of elements to pick.
|
||
* @returns {Object} Returns the new `lodash` wrapper instance.
|
||
* @example
|
||
*
|
||
* var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
|
||
*
|
||
* _(object).at(['a[0].b.c', 'a[1]']).value();
|
||
* // => [3, 4]
|
||
*
|
||
* _(['a', 'b', 'c']).at(0, 2).value();
|
||
* // => ['a', 'c']
|
||
*/
|
||
var wrapperAt = rest(function(paths) {
|
||
paths = baseFlatten(paths, 1);
|
||
var length = paths.length,
|
||
start = length ? paths[0] : 0,
|
||
value = this.__wrapped__,
|
||
interceptor = function(object) { return baseAt(object, paths); };
|
||
|
||
if (length > 1 || this.__actions__.length ||
|
||
!(value instanceof LazyWrapper) || !isIndex(start)) {
|
||
return this.thru(interceptor);
|
||
}
|
||
value = value.slice(start, +start + (length ? 1 : 0));
|
||
value.__actions__.push({
|
||
'func': thru,
|
||
'args': [interceptor],
|
||
'thisArg': undefined
|
||
});
|
||
return new LodashWrapper(value, this.__chain__).thru(function(array) {
|
||
if (length && !array.length) {
|
||
array.push(undefined);
|
||
}
|
||
return array;
|
||
});
|
||
});
|
||
|
||
/**
|
||
* Creates a `lodash` wrapper instance with explicit method chain sequences enabled.
|
||
*
|
||
* @name chain
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Seq
|
||
* @returns {Object} Returns the new `lodash` wrapper instance.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'age': 36 },
|
||
* { 'user': 'fred', 'age': 40 }
|
||
* ];
|
||
*
|
||
* // A sequence without explicit chaining.
|
||
* _(users).head();
|
||
* // => { 'user': 'barney', 'age': 36 }
|
||
*
|
||
* // A sequence with explicit chaining.
|
||
* _(users)
|
||
* .chain()
|
||
* .head()
|
||
* .pick('user')
|
||
* .value();
|
||
* // => { 'user': 'barney' }
|
||
*/
|
||
function wrapperChain() {
|
||
return chain(this);
|
||
}
|
||
|
||
/**
|
||
* Executes the chain sequence and returns the wrapped result.
|
||
*
|
||
* @name commit
|
||
* @memberOf _
|
||
* @since 3.2.0
|
||
* @category Seq
|
||
* @returns {Object} Returns the new `lodash` wrapper instance.
|
||
* @example
|
||
*
|
||
* var array = [1, 2];
|
||
* var wrapped = _(array).push(3);
|
||
*
|
||
* console.log(array);
|
||
* // => [1, 2]
|
||
*
|
||
* wrapped = wrapped.commit();
|
||
* console.log(array);
|
||
* // => [1, 2, 3]
|
||
*
|
||
* wrapped.last();
|
||
* // => 3
|
||
*
|
||
* console.log(array);
|
||
* // => [1, 2, 3]
|
||
*/
|
||
function wrapperCommit() {
|
||
return new LodashWrapper(this.value(), this.__chain__);
|
||
}
|
||
|
||
/**
|
||
* Gets the next value on a wrapped object following the
|
||
* [iterator protocol](https://mdn.io/iteration_protocols#iterator).
|
||
*
|
||
* @name next
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Seq
|
||
* @returns {Object} Returns the next iterator value.
|
||
* @example
|
||
*
|
||
* var wrapped = _([1, 2]);
|
||
*
|
||
* wrapped.next();
|
||
* // => { 'done': false, 'value': 1 }
|
||
*
|
||
* wrapped.next();
|
||
* // => { 'done': false, 'value': 2 }
|
||
*
|
||
* wrapped.next();
|
||
* // => { 'done': true, 'value': undefined }
|
||
*/
|
||
function wrapperNext() {
|
||
if (this.__values__ === undefined) {
|
||
this.__values__ = toArray(this.value());
|
||
}
|
||
var done = this.__index__ >= this.__values__.length,
|
||
value = done ? undefined : this.__values__[this.__index__++];
|
||
|
||
return { 'done': done, 'value': value };
|
||
}
|
||
|
||
/**
|
||
* Enables the wrapper to be iterable.
|
||
*
|
||
* @name Symbol.iterator
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Seq
|
||
* @returns {Object} Returns the wrapper object.
|
||
* @example
|
||
*
|
||
* var wrapped = _([1, 2]);
|
||
*
|
||
* wrapped[Symbol.iterator]() === wrapped;
|
||
* // => true
|
||
*
|
||
* Array.from(wrapped);
|
||
* // => [1, 2]
|
||
*/
|
||
function wrapperToIterator() {
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* Creates a clone of the chain sequence planting `value` as the wrapped value.
|
||
*
|
||
* @name plant
|
||
* @memberOf _
|
||
* @since 3.2.0
|
||
* @category Seq
|
||
* @param {*} value The value to plant.
|
||
* @returns {Object} Returns the new `lodash` wrapper instance.
|
||
* @example
|
||
*
|
||
* function square(n) {
|
||
* return n * n;
|
||
* }
|
||
*
|
||
* var wrapped = _([1, 2]).map(square);
|
||
* var other = wrapped.plant([3, 4]);
|
||
*
|
||
* other.value();
|
||
* // => [9, 16]
|
||
*
|
||
* wrapped.value();
|
||
* // => [1, 4]
|
||
*/
|
||
function wrapperPlant(value) {
|
||
var result,
|
||
parent = this;
|
||
|
||
while (parent instanceof baseLodash) {
|
||
var clone = wrapperClone(parent);
|
||
clone.__index__ = 0;
|
||
clone.__values__ = undefined;
|
||
if (result) {
|
||
previous.__wrapped__ = clone;
|
||
} else {
|
||
result = clone;
|
||
}
|
||
var previous = clone;
|
||
parent = parent.__wrapped__;
|
||
}
|
||
previous.__wrapped__ = value;
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* This method is the wrapper version of `_.reverse`.
|
||
*
|
||
* **Note:** This method mutates the wrapped array.
|
||
*
|
||
* @name reverse
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Seq
|
||
* @returns {Object} Returns the new `lodash` wrapper instance.
|
||
* @example
|
||
*
|
||
* var array = [1, 2, 3];
|
||
*
|
||
* _(array).reverse().value()
|
||
* // => [3, 2, 1]
|
||
*
|
||
* console.log(array);
|
||
* // => [3, 2, 1]
|
||
*/
|
||
function wrapperReverse() {
|
||
var value = this.__wrapped__;
|
||
if (value instanceof LazyWrapper) {
|
||
var wrapped = value;
|
||
if (this.__actions__.length) {
|
||
wrapped = new LazyWrapper(this);
|
||
}
|
||
wrapped = wrapped.reverse();
|
||
wrapped.__actions__.push({
|
||
'func': thru,
|
||
'args': [reverse],
|
||
'thisArg': undefined
|
||
});
|
||
return new LodashWrapper(wrapped, this.__chain__);
|
||
}
|
||
return this.thru(reverse);
|
||
}
|
||
|
||
/**
|
||
* Executes the chain sequence to resolve the unwrapped value.
|
||
*
|
||
* @name value
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @alias toJSON, valueOf
|
||
* @category Seq
|
||
* @returns {*} Returns the resolved unwrapped value.
|
||
* @example
|
||
*
|
||
* _([1, 2, 3]).value();
|
||
* // => [1, 2, 3]
|
||
*/
|
||
function wrapperValue() {
|
||
return baseWrapperValue(this.__wrapped__, this.__actions__);
|
||
}
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Creates an object composed of keys generated from the results of running
|
||
* each element of `collection` thru `iteratee`. The corresponding value of
|
||
* each key is the number of times the key was returned by `iteratee`. The
|
||
* iteratee is invoked with one argument: (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.5.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee to transform keys.
|
||
* @returns {Object} Returns the composed aggregate object.
|
||
* @example
|
||
*
|
||
* _.countBy([6.1, 4.2, 6.3], Math.floor);
|
||
* // => { '4': 1, '6': 2 }
|
||
*
|
||
* _.countBy(['one', 'two', 'three'], 'length');
|
||
* // => { '3': 2, '5': 1 }
|
||
*/
|
||
var countBy = createAggregator(function(result, value, key) {
|
||
hasOwnProperty.call(result, key) ? ++result[key] : (result[key] = 1);
|
||
});
|
||
|
||
/**
|
||
* Checks if `predicate` returns truthy for **all** elements of `collection`.
|
||
* Iteration is stopped once `predicate` returns falsey. The predicate is
|
||
* invoked with three arguments: (value, index|key, collection).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {boolean} Returns `true` if all elements pass the predicate check,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.every([true, 1, null, 'yes'], Boolean);
|
||
* // => false
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'age': 36, 'active': false },
|
||
* { 'user': 'fred', 'age': 40, 'active': false }
|
||
* ];
|
||
*
|
||
* // The `_.matches` iteratee shorthand.
|
||
* _.every(users, { 'user': 'barney', 'active': false });
|
||
* // => false
|
||
*
|
||
* // The `_.matchesProperty` iteratee shorthand.
|
||
* _.every(users, ['active', false]);
|
||
* // => true
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.every(users, 'active');
|
||
* // => false
|
||
*/
|
||
function every(collection, predicate, guard) {
|
||
var func = isArray(collection) ? arrayEvery : baseEvery;
|
||
if (guard && isIterateeCall(collection, predicate, guard)) {
|
||
predicate = undefined;
|
||
}
|
||
return func(collection, getIteratee(predicate, 3));
|
||
}
|
||
|
||
/**
|
||
* Iterates over elements of `collection`, returning an array of all elements
|
||
* `predicate` returns truthy for. The predicate is invoked with three
|
||
* arguments: (value, index|key, collection).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {Array} Returns the new filtered array.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'age': 36, 'active': true },
|
||
* { 'user': 'fred', 'age': 40, 'active': false }
|
||
* ];
|
||
*
|
||
* _.filter(users, function(o) { return !o.active; });
|
||
* // => objects for ['fred']
|
||
*
|
||
* // The `_.matches` iteratee shorthand.
|
||
* _.filter(users, { 'age': 36, 'active': true });
|
||
* // => objects for ['barney']
|
||
*
|
||
* // The `_.matchesProperty` iteratee shorthand.
|
||
* _.filter(users, ['active', false]);
|
||
* // => objects for ['fred']
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.filter(users, 'active');
|
||
* // => objects for ['barney']
|
||
*/
|
||
function filter(collection, predicate) {
|
||
var func = isArray(collection) ? arrayFilter : baseFilter;
|
||
return func(collection, getIteratee(predicate, 3));
|
||
}
|
||
|
||
/**
|
||
* Iterates over elements of `collection`, returning the first element
|
||
* `predicate` returns truthy for. The predicate is invoked with three
|
||
* arguments: (value, index|key, collection).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to search.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {*} Returns the matched element, else `undefined`.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'age': 36, 'active': true },
|
||
* { 'user': 'fred', 'age': 40, 'active': false },
|
||
* { 'user': 'pebbles', 'age': 1, 'active': true }
|
||
* ];
|
||
*
|
||
* _.find(users, function(o) { return o.age < 40; });
|
||
* // => object for 'barney'
|
||
*
|
||
* // The `_.matches` iteratee shorthand.
|
||
* _.find(users, { 'age': 1, 'active': true });
|
||
* // => object for 'pebbles'
|
||
*
|
||
* // The `_.matchesProperty` iteratee shorthand.
|
||
* _.find(users, ['active', false]);
|
||
* // => object for 'fred'
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.find(users, 'active');
|
||
* // => object for 'barney'
|
||
*/
|
||
function find(collection, predicate) {
|
||
predicate = getIteratee(predicate, 3);
|
||
if (isArray(collection)) {
|
||
var index = baseFindIndex(collection, predicate);
|
||
return index > -1 ? collection[index] : undefined;
|
||
}
|
||
return baseFind(collection, predicate, baseEach);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.find` except that it iterates over elements of
|
||
* `collection` from right to left.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.0.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to search.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {*} Returns the matched element, else `undefined`.
|
||
* @example
|
||
*
|
||
* _.findLast([1, 2, 3, 4], function(n) {
|
||
* return n % 2 == 1;
|
||
* });
|
||
* // => 3
|
||
*/
|
||
function findLast(collection, predicate) {
|
||
predicate = getIteratee(predicate, 3);
|
||
if (isArray(collection)) {
|
||
var index = baseFindIndex(collection, predicate, true);
|
||
return index > -1 ? collection[index] : undefined;
|
||
}
|
||
return baseFind(collection, predicate, baseEachRight);
|
||
}
|
||
|
||
/**
|
||
* Creates a flattened array of values by running each element in `collection`
|
||
* thru `iteratee` and flattening the mapped results. The iteratee is invoked
|
||
* with three arguments: (value, index|key, collection).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {Array} Returns the new flattened array.
|
||
* @example
|
||
*
|
||
* function duplicate(n) {
|
||
* return [n, n];
|
||
* }
|
||
*
|
||
* _.flatMap([1, 2], duplicate);
|
||
* // => [1, 1, 2, 2]
|
||
*/
|
||
function flatMap(collection, iteratee) {
|
||
return baseFlatten(map(collection, iteratee), 1);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.flatMap` except that it recursively flattens the
|
||
* mapped results.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.7.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {Array} Returns the new flattened array.
|
||
* @example
|
||
*
|
||
* function duplicate(n) {
|
||
* return [[[n, n]]];
|
||
* }
|
||
*
|
||
* _.flatMapDeep([1, 2], duplicate);
|
||
* // => [1, 1, 2, 2]
|
||
*/
|
||
function flatMapDeep(collection, iteratee) {
|
||
return baseFlatten(map(collection, iteratee), INFINITY);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.flatMap` except that it recursively flattens the
|
||
* mapped results up to `depth` times.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.7.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The function invoked per iteration.
|
||
* @param {number} [depth=1] The maximum recursion depth.
|
||
* @returns {Array} Returns the new flattened array.
|
||
* @example
|
||
*
|
||
* function duplicate(n) {
|
||
* return [[[n, n]]];
|
||
* }
|
||
*
|
||
* _.flatMapDepth([1, 2], duplicate, 2);
|
||
* // => [[1, 1], [2, 2]]
|
||
*/
|
||
function flatMapDepth(collection, iteratee, depth) {
|
||
depth = depth === undefined ? 1 : toInteger(depth);
|
||
return baseFlatten(map(collection, iteratee), depth);
|
||
}
|
||
|
||
/**
|
||
* Iterates over elements of `collection` and invokes `iteratee` for each element.
|
||
* The iteratee is invoked with three arguments: (value, index|key, collection).
|
||
* Iteratee functions may exit iteration early by explicitly returning `false`.
|
||
*
|
||
* **Note:** As with other "Collections" methods, objects with a "length"
|
||
* property are iterated like arrays. To avoid this behavior use `_.forIn`
|
||
* or `_.forOwn` for object iteration.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @alias each
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
|
||
* @returns {Array|Object} Returns `collection`.
|
||
* @example
|
||
*
|
||
* _([1, 2]).forEach(function(value) {
|
||
* console.log(value);
|
||
* });
|
||
* // => Logs `1` then `2`.
|
||
*
|
||
* _.forEach({ 'a': 1, 'b': 2 }, function(value, key) {
|
||
* console.log(key);
|
||
* });
|
||
* // => Logs 'a' then 'b' (iteration order is not guaranteed).
|
||
*/
|
||
function forEach(collection, iteratee) {
|
||
return (typeof iteratee == 'function' && isArray(collection))
|
||
? arrayEach(collection, iteratee)
|
||
: baseEach(collection, getIteratee(iteratee));
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.forEach` except that it iterates over elements of
|
||
* `collection` from right to left.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.0.0
|
||
* @alias eachRight
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
|
||
* @returns {Array|Object} Returns `collection`.
|
||
* @example
|
||
*
|
||
* _.forEachRight([1, 2], function(value) {
|
||
* console.log(value);
|
||
* });
|
||
* // => Logs `2` then `1`.
|
||
*/
|
||
function forEachRight(collection, iteratee) {
|
||
return (typeof iteratee == 'function' && isArray(collection))
|
||
? arrayEachRight(collection, iteratee)
|
||
: baseEachRight(collection, getIteratee(iteratee));
|
||
}
|
||
|
||
/**
|
||
* Creates an object composed of keys generated from the results of running
|
||
* each element of `collection` thru `iteratee`. The order of grouped values
|
||
* is determined by the order they occur in `collection`. The corresponding
|
||
* value of each key is an array of elements responsible for generating the
|
||
* key. The iteratee is invoked with one argument: (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee to transform keys.
|
||
* @returns {Object} Returns the composed aggregate object.
|
||
* @example
|
||
*
|
||
* _.groupBy([6.1, 4.2, 6.3], Math.floor);
|
||
* // => { '4': [4.2], '6': [6.1, 6.3] }
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.groupBy(['one', 'two', 'three'], 'length');
|
||
* // => { '3': ['one', 'two'], '5': ['three'] }
|
||
*/
|
||
var groupBy = createAggregator(function(result, value, key) {
|
||
if (hasOwnProperty.call(result, key)) {
|
||
result[key].push(value);
|
||
} else {
|
||
result[key] = [value];
|
||
}
|
||
});
|
||
|
||
/**
|
||
* Checks if `value` is in `collection`. If `collection` is a string, it's
|
||
* checked for a substring of `value`, otherwise
|
||
* [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
|
||
* is used for equality comparisons. If `fromIndex` is negative, it's used as
|
||
* the offset from the end of `collection`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Collection
|
||
* @param {Array|Object|string} collection The collection to search.
|
||
* @param {*} value The value to search for.
|
||
* @param {number} [fromIndex=0] The index to search from.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
|
||
* @returns {boolean} Returns `true` if `value` is found, else `false`.
|
||
* @example
|
||
*
|
||
* _.includes([1, 2, 3], 1);
|
||
* // => true
|
||
*
|
||
* _.includes([1, 2, 3], 1, 2);
|
||
* // => false
|
||
*
|
||
* _.includes({ 'user': 'fred', 'age': 40 }, 'fred');
|
||
* // => true
|
||
*
|
||
* _.includes('pebbles', 'eb');
|
||
* // => true
|
||
*/
|
||
function includes(collection, value, fromIndex, guard) {
|
||
collection = isArrayLike(collection) ? collection : values(collection);
|
||
fromIndex = (fromIndex && !guard) ? toInteger(fromIndex) : 0;
|
||
|
||
var length = collection.length;
|
||
if (fromIndex < 0) {
|
||
fromIndex = nativeMax(length + fromIndex, 0);
|
||
}
|
||
return isString(collection)
|
||
? (fromIndex <= length && collection.indexOf(value, fromIndex) > -1)
|
||
: (!!length && baseIndexOf(collection, value, fromIndex) > -1);
|
||
}
|
||
|
||
/**
|
||
* Invokes the method at `path` of each element in `collection`, returning
|
||
* an array of the results of each invoked method. Any additional arguments
|
||
* are provided to each invoked method. If `methodName` is a function, it's
|
||
* invoked for and `this` bound to, each element in `collection`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Array|Function|string} path The path of the method to invoke or
|
||
* the function invoked per iteration.
|
||
* @param {...*} [args] The arguments to invoke each method with.
|
||
* @returns {Array} Returns the array of results.
|
||
* @example
|
||
*
|
||
* _.invokeMap([[5, 1, 7], [3, 2, 1]], 'sort');
|
||
* // => [[1, 5, 7], [1, 2, 3]]
|
||
*
|
||
* _.invokeMap([123, 456], String.prototype.split, '');
|
||
* // => [['1', '2', '3'], ['4', '5', '6']]
|
||
*/
|
||
var invokeMap = rest(function(collection, path, args) {
|
||
var index = -1,
|
||
isFunc = typeof path == 'function',
|
||
isProp = isKey(path),
|
||
result = isArrayLike(collection) ? Array(collection.length) : [];
|
||
|
||
baseEach(collection, function(value) {
|
||
var func = isFunc ? path : ((isProp && value != null) ? value[path] : undefined);
|
||
result[++index] = func ? apply(func, value, args) : baseInvoke(value, path, args);
|
||
});
|
||
return result;
|
||
});
|
||
|
||
/**
|
||
* Creates an object composed of keys generated from the results of running
|
||
* each element of `collection` thru `iteratee`. The corresponding value of
|
||
* each key is the last element responsible for generating the key. The
|
||
* iteratee is invoked with one argument: (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee to transform keys.
|
||
* @returns {Object} Returns the composed aggregate object.
|
||
* @example
|
||
*
|
||
* var array = [
|
||
* { 'dir': 'left', 'code': 97 },
|
||
* { 'dir': 'right', 'code': 100 }
|
||
* ];
|
||
*
|
||
* _.keyBy(array, function(o) {
|
||
* return String.fromCharCode(o.code);
|
||
* });
|
||
* // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } }
|
||
*
|
||
* _.keyBy(array, 'dir');
|
||
* // => { 'left': { 'dir': 'left', 'code': 97 }, 'right': { 'dir': 'right', 'code': 100 } }
|
||
*/
|
||
var keyBy = createAggregator(function(result, value, key) {
|
||
result[key] = value;
|
||
});
|
||
|
||
/**
|
||
* Creates an array of values by running each element in `collection` thru
|
||
* `iteratee`. The iteratee is invoked with three arguments:
|
||
* (value, index|key, collection).
|
||
*
|
||
* Many lodash methods are guarded to work as iteratees for methods like
|
||
* `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`.
|
||
*
|
||
* The guarded methods are:
|
||
* `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`,
|
||
* `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`,
|
||
* `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`,
|
||
* `template`, `trim`, `trimEnd`, `trimStart`, and `words`
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {Array} Returns the new mapped array.
|
||
* @example
|
||
*
|
||
* function square(n) {
|
||
* return n * n;
|
||
* }
|
||
*
|
||
* _.map([4, 8], square);
|
||
* // => [16, 64]
|
||
*
|
||
* _.map({ 'a': 4, 'b': 8 }, square);
|
||
* // => [16, 64] (iteration order is not guaranteed)
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney' },
|
||
* { 'user': 'fred' }
|
||
* ];
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.map(users, 'user');
|
||
* // => ['barney', 'fred']
|
||
*/
|
||
function map(collection, iteratee) {
|
||
var func = isArray(collection) ? arrayMap : baseMap;
|
||
return func(collection, getIteratee(iteratee, 3));
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.sortBy` except that it allows specifying the sort
|
||
* orders of the iteratees to sort by. If `orders` is unspecified, all values
|
||
* are sorted in ascending order. Otherwise, specify an order of "desc" for
|
||
* descending or "asc" for ascending sort order of corresponding values.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Array[]|Function[]|Object[]|string[]} [iteratees=[_.identity]]
|
||
* The iteratees to sort by.
|
||
* @param {string[]} [orders] The sort orders of `iteratees`.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.reduce`.
|
||
* @returns {Array} Returns the new sorted array.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'fred', 'age': 48 },
|
||
* { 'user': 'barney', 'age': 34 },
|
||
* { 'user': 'fred', 'age': 40 },
|
||
* { 'user': 'barney', 'age': 36 }
|
||
* ];
|
||
*
|
||
* // Sort by `user` in ascending order and by `age` in descending order.
|
||
* _.orderBy(users, ['user', 'age'], ['asc', 'desc']);
|
||
* // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
|
||
*/
|
||
function orderBy(collection, iteratees, orders, guard) {
|
||
if (collection == null) {
|
||
return [];
|
||
}
|
||
if (!isArray(iteratees)) {
|
||
iteratees = iteratees == null ? [] : [iteratees];
|
||
}
|
||
orders = guard ? undefined : orders;
|
||
if (!isArray(orders)) {
|
||
orders = orders == null ? [] : [orders];
|
||
}
|
||
return baseOrderBy(collection, iteratees, orders);
|
||
}
|
||
|
||
/**
|
||
* Creates an array of elements split into two groups, the first of which
|
||
* contains elements `predicate` returns truthy for, the second of which
|
||
* contains elements `predicate` returns falsey for. The predicate is
|
||
* invoked with one argument: (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {Array} Returns the array of grouped elements.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'age': 36, 'active': false },
|
||
* { 'user': 'fred', 'age': 40, 'active': true },
|
||
* { 'user': 'pebbles', 'age': 1, 'active': false }
|
||
* ];
|
||
*
|
||
* _.partition(users, function(o) { return o.active; });
|
||
* // => objects for [['fred'], ['barney', 'pebbles']]
|
||
*
|
||
* // The `_.matches` iteratee shorthand.
|
||
* _.partition(users, { 'age': 1, 'active': false });
|
||
* // => objects for [['pebbles'], ['barney', 'fred']]
|
||
*
|
||
* // The `_.matchesProperty` iteratee shorthand.
|
||
* _.partition(users, ['active', false]);
|
||
* // => objects for [['barney', 'pebbles'], ['fred']]
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.partition(users, 'active');
|
||
* // => objects for [['fred'], ['barney', 'pebbles']]
|
||
*/
|
||
var partition = createAggregator(function(result, value, key) {
|
||
result[key ? 0 : 1].push(value);
|
||
}, function() { return [[], []]; });
|
||
|
||
/**
|
||
* Reduces `collection` to a value which is the accumulated result of running
|
||
* each element in `collection` thru `iteratee`, where each successive
|
||
* invocation is supplied the return value of the previous. If `accumulator`
|
||
* is not given, the first element of `collection` is used as the initial
|
||
* value. The iteratee is invoked with four arguments:
|
||
* (accumulator, value, index|key, collection).
|
||
*
|
||
* Many lodash methods are guarded to work as iteratees for methods like
|
||
* `_.reduce`, `_.reduceRight`, and `_.transform`.
|
||
*
|
||
* The guarded methods are:
|
||
* `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`,
|
||
* and `sortBy`
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
|
||
* @param {*} [accumulator] The initial value.
|
||
* @returns {*} Returns the accumulated value.
|
||
* @example
|
||
*
|
||
* _.reduce([1, 2], function(sum, n) {
|
||
* return sum + n;
|
||
* }, 0);
|
||
* // => 3
|
||
*
|
||
* _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
|
||
* (result[value] || (result[value] = [])).push(key);
|
||
* return result;
|
||
* }, {});
|
||
* // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed)
|
||
*/
|
||
function reduce(collection, iteratee, accumulator) {
|
||
var func = isArray(collection) ? arrayReduce : baseReduce,
|
||
initAccum = arguments.length < 3;
|
||
|
||
return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEach);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.reduce` except that it iterates over elements of
|
||
* `collection` from right to left.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
|
||
* @param {*} [accumulator] The initial value.
|
||
* @returns {*} Returns the accumulated value.
|
||
* @example
|
||
*
|
||
* var array = [[0, 1], [2, 3], [4, 5]];
|
||
*
|
||
* _.reduceRight(array, function(flattened, other) {
|
||
* return flattened.concat(other);
|
||
* }, []);
|
||
* // => [4, 5, 2, 3, 0, 1]
|
||
*/
|
||
function reduceRight(collection, iteratee, accumulator) {
|
||
var func = isArray(collection) ? arrayReduceRight : baseReduce,
|
||
initAccum = arguments.length < 3;
|
||
|
||
return func(collection, getIteratee(iteratee, 4), accumulator, initAccum, baseEachRight);
|
||
}
|
||
|
||
/**
|
||
* The opposite of `_.filter`; this method returns the elements of `collection`
|
||
* that `predicate` does **not** return truthy for.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {Array} Returns the new filtered array.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'age': 36, 'active': false },
|
||
* { 'user': 'fred', 'age': 40, 'active': true }
|
||
* ];
|
||
*
|
||
* _.reject(users, function(o) { return !o.active; });
|
||
* // => objects for ['fred']
|
||
*
|
||
* // The `_.matches` iteratee shorthand.
|
||
* _.reject(users, { 'age': 40, 'active': true });
|
||
* // => objects for ['barney']
|
||
*
|
||
* // The `_.matchesProperty` iteratee shorthand.
|
||
* _.reject(users, ['active', false]);
|
||
* // => objects for ['fred']
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.reject(users, 'active');
|
||
* // => objects for ['barney']
|
||
*/
|
||
function reject(collection, predicate) {
|
||
var func = isArray(collection) ? arrayFilter : baseFilter;
|
||
predicate = getIteratee(predicate, 3);
|
||
return func(collection, function(value, index, collection) {
|
||
return !predicate(value, index, collection);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Gets a random element from `collection`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.0.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to sample.
|
||
* @returns {*} Returns the random element.
|
||
* @example
|
||
*
|
||
* _.sample([1, 2, 3, 4]);
|
||
* // => 2
|
||
*/
|
||
function sample(collection) {
|
||
var array = isArrayLike(collection) ? collection : values(collection),
|
||
length = array.length;
|
||
|
||
return length > 0 ? array[baseRandom(0, length - 1)] : undefined;
|
||
}
|
||
|
||
/**
|
||
* Gets `n` random elements at unique keys from `collection` up to the
|
||
* size of `collection`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to sample.
|
||
* @param {number} [n=1] The number of elements to sample.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {Array} Returns the random elements.
|
||
* @example
|
||
*
|
||
* _.sampleSize([1, 2, 3], 2);
|
||
* // => [3, 1]
|
||
*
|
||
* _.sampleSize([1, 2, 3], 4);
|
||
* // => [2, 3, 1]
|
||
*/
|
||
function sampleSize(collection, n, guard) {
|
||
var index = -1,
|
||
result = toArray(collection),
|
||
length = result.length,
|
||
lastIndex = length - 1;
|
||
|
||
if ((guard ? isIterateeCall(collection, n, guard) : n === undefined)) {
|
||
n = 1;
|
||
} else {
|
||
n = baseClamp(toInteger(n), 0, length);
|
||
}
|
||
while (++index < n) {
|
||
var rand = baseRandom(index, lastIndex),
|
||
value = result[rand];
|
||
|
||
result[rand] = result[index];
|
||
result[index] = value;
|
||
}
|
||
result.length = n;
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Creates an array of shuffled values, using a version of the
|
||
* [Fisher-Yates shuffle](https://en.wikipedia.org/wiki/Fisher-Yates_shuffle).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to shuffle.
|
||
* @returns {Array} Returns the new shuffled array.
|
||
* @example
|
||
*
|
||
* _.shuffle([1, 2, 3, 4]);
|
||
* // => [4, 1, 3, 2]
|
||
*/
|
||
function shuffle(collection) {
|
||
return sampleSize(collection, MAX_ARRAY_LENGTH);
|
||
}
|
||
|
||
/**
|
||
* Gets the size of `collection` by returning its length for array-like
|
||
* values or the number of own enumerable string keyed properties for objects.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to inspect.
|
||
* @returns {number} Returns the collection size.
|
||
* @example
|
||
*
|
||
* _.size([1, 2, 3]);
|
||
* // => 3
|
||
*
|
||
* _.size({ 'a': 1, 'b': 2 });
|
||
* // => 2
|
||
*
|
||
* _.size('pebbles');
|
||
* // => 7
|
||
*/
|
||
function size(collection) {
|
||
if (collection == null) {
|
||
return 0;
|
||
}
|
||
if (isArrayLike(collection)) {
|
||
var result = collection.length;
|
||
return (result && isString(collection)) ? stringSize(collection) : result;
|
||
}
|
||
if (isObjectLike(collection)) {
|
||
var tag = getTag(collection);
|
||
if (tag == mapTag || tag == setTag) {
|
||
return collection.size;
|
||
}
|
||
}
|
||
return keys(collection).length;
|
||
}
|
||
|
||
/**
|
||
* Checks if `predicate` returns truthy for **any** element of `collection`.
|
||
* Iteration is stopped once `predicate` returns truthy. The predicate is
|
||
* invoked with three arguments: (value, index|key, collection).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {boolean} Returns `true` if any element passes the predicate check,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.some([null, 0, 'yes', false], Boolean);
|
||
* // => true
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'active': true },
|
||
* { 'user': 'fred', 'active': false }
|
||
* ];
|
||
*
|
||
* // The `_.matches` iteratee shorthand.
|
||
* _.some(users, { 'user': 'barney', 'active': false });
|
||
* // => false
|
||
*
|
||
* // The `_.matchesProperty` iteratee shorthand.
|
||
* _.some(users, ['active', false]);
|
||
* // => true
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.some(users, 'active');
|
||
* // => true
|
||
*/
|
||
function some(collection, predicate, guard) {
|
||
var func = isArray(collection) ? arraySome : baseSome;
|
||
if (guard && isIterateeCall(collection, predicate, guard)) {
|
||
predicate = undefined;
|
||
}
|
||
return func(collection, getIteratee(predicate, 3));
|
||
}
|
||
|
||
/**
|
||
* Creates an array of elements, sorted in ascending order by the results of
|
||
* running each element in a collection thru each iteratee. This method
|
||
* performs a stable sort, that is, it preserves the original sort order of
|
||
* equal elements. The iteratees are invoked with one argument: (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Collection
|
||
* @param {Array|Object} collection The collection to iterate over.
|
||
* @param {...(Array|Array[]|Function|Function[]|Object|Object[]|string|string[])}
|
||
* [iteratees=[_.identity]] The iteratees to sort by.
|
||
* @returns {Array} Returns the new sorted array.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'fred', 'age': 48 },
|
||
* { 'user': 'barney', 'age': 36 },
|
||
* { 'user': 'fred', 'age': 40 },
|
||
* { 'user': 'barney', 'age': 34 }
|
||
* ];
|
||
*
|
||
* _.sortBy(users, function(o) { return o.user; });
|
||
* // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
|
||
*
|
||
* _.sortBy(users, ['user', 'age']);
|
||
* // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]]
|
||
*
|
||
* _.sortBy(users, 'user', function(o) {
|
||
* return Math.floor(o.age / 10);
|
||
* });
|
||
* // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]]
|
||
*/
|
||
var sortBy = rest(function(collection, iteratees) {
|
||
if (collection == null) {
|
||
return [];
|
||
}
|
||
var length = iteratees.length;
|
||
if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) {
|
||
iteratees = [];
|
||
} else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) {
|
||
iteratees = [iteratees[0]];
|
||
}
|
||
iteratees = (iteratees.length == 1 && isArray(iteratees[0]))
|
||
? iteratees[0]
|
||
: baseFlatten(iteratees, 1, isFlattenableIteratee);
|
||
|
||
return baseOrderBy(collection, iteratees, []);
|
||
});
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Gets the timestamp of the number of milliseconds that have elapsed since
|
||
* the Unix epoch (1 January 1970 00:00:00 UTC).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.4.0
|
||
* @type {Function}
|
||
* @category Date
|
||
* @returns {number} Returns the timestamp.
|
||
* @example
|
||
*
|
||
* _.defer(function(stamp) {
|
||
* console.log(_.now() - stamp);
|
||
* }, _.now());
|
||
* // => Logs the number of milliseconds it took for the deferred function to be invoked.
|
||
*/
|
||
var now = Date.now;
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* The opposite of `_.before`; this method creates a function that invokes
|
||
* `func` once it's called `n` or more times.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Function
|
||
* @param {number} n The number of calls before `func` is invoked.
|
||
* @param {Function} func The function to restrict.
|
||
* @returns {Function} Returns the new restricted function.
|
||
* @example
|
||
*
|
||
* var saves = ['profile', 'settings'];
|
||
*
|
||
* var done = _.after(saves.length, function() {
|
||
* console.log('done saving!');
|
||
* });
|
||
*
|
||
* _.forEach(saves, function(type) {
|
||
* asyncSave({ 'type': type, 'complete': done });
|
||
* });
|
||
* // => Logs 'done saving!' after the two async saves have completed.
|
||
*/
|
||
function after(n, func) {
|
||
if (typeof func != 'function') {
|
||
throw new TypeError(FUNC_ERROR_TEXT);
|
||
}
|
||
n = toInteger(n);
|
||
return function() {
|
||
if (--n < 1) {
|
||
return func.apply(this, arguments);
|
||
}
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates a function that invokes `func`, with up to `n` arguments,
|
||
* ignoring any additional arguments.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Function
|
||
* @param {Function} func The function to cap arguments for.
|
||
* @param {number} [n=func.length] The arity cap.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* _.map(['6', '8', '10'], _.ary(parseInt, 1));
|
||
* // => [6, 8, 10]
|
||
*/
|
||
function ary(func, n, guard) {
|
||
n = guard ? undefined : n;
|
||
n = (func && n == null) ? func.length : n;
|
||
return createWrapper(func, ARY_FLAG, undefined, undefined, undefined, undefined, n);
|
||
}
|
||
|
||
/**
|
||
* Creates a function that invokes `func`, with the `this` binding and arguments
|
||
* of the created function, while it's called less than `n` times. Subsequent
|
||
* calls to the created function return the result of the last `func` invocation.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Function
|
||
* @param {number} n The number of calls at which `func` is no longer invoked.
|
||
* @param {Function} func The function to restrict.
|
||
* @returns {Function} Returns the new restricted function.
|
||
* @example
|
||
*
|
||
* jQuery(element).on('click', _.before(5, addContactToList));
|
||
* // => allows adding up to 4 contacts to the list
|
||
*/
|
||
function before(n, func) {
|
||
var result;
|
||
if (typeof func != 'function') {
|
||
throw new TypeError(FUNC_ERROR_TEXT);
|
||
}
|
||
n = toInteger(n);
|
||
return function() {
|
||
if (--n > 0) {
|
||
result = func.apply(this, arguments);
|
||
}
|
||
if (n <= 1) {
|
||
func = undefined;
|
||
}
|
||
return result;
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates a function that invokes `func` with the `this` binding of `thisArg`
|
||
* and `partials` prepended to the arguments it receives.
|
||
*
|
||
* The `_.bind.placeholder` value, which defaults to `_` in monolithic builds,
|
||
* may be used as a placeholder for partially applied arguments.
|
||
*
|
||
* **Note:** Unlike native `Function#bind` this method doesn't set the "length"
|
||
* property of bound functions.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Function
|
||
* @param {Function} func The function to bind.
|
||
* @param {*} thisArg The `this` binding of `func`.
|
||
* @param {...*} [partials] The arguments to be partially applied.
|
||
* @returns {Function} Returns the new bound function.
|
||
* @example
|
||
*
|
||
* var greet = function(greeting, punctuation) {
|
||
* return greeting + ' ' + this.user + punctuation;
|
||
* };
|
||
*
|
||
* var object = { 'user': 'fred' };
|
||
*
|
||
* var bound = _.bind(greet, object, 'hi');
|
||
* bound('!');
|
||
* // => 'hi fred!'
|
||
*
|
||
* // Bound with placeholders.
|
||
* var bound = _.bind(greet, object, _, '!');
|
||
* bound('hi');
|
||
* // => 'hi fred!'
|
||
*/
|
||
var bind = rest(function(func, thisArg, partials) {
|
||
var bitmask = BIND_FLAG;
|
||
if (partials.length) {
|
||
var holders = replaceHolders(partials, getPlaceholder(bind));
|
||
bitmask |= PARTIAL_FLAG;
|
||
}
|
||
return createWrapper(func, bitmask, thisArg, partials, holders);
|
||
});
|
||
|
||
/**
|
||
* Creates a function that invokes the method at `object[key]` with `partials`
|
||
* prepended to the arguments it receives.
|
||
*
|
||
* This method differs from `_.bind` by allowing bound functions to reference
|
||
* methods that may be redefined or don't yet exist. See
|
||
* [Peter Michaux's article](http://peter.michaux.ca/articles/lazy-function-definition-pattern)
|
||
* for more details.
|
||
*
|
||
* The `_.bindKey.placeholder` value, which defaults to `_` in monolithic
|
||
* builds, may be used as a placeholder for partially applied arguments.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.10.0
|
||
* @category Function
|
||
* @param {Object} object The object to invoke the method on.
|
||
* @param {string} key The key of the method.
|
||
* @param {...*} [partials] The arguments to be partially applied.
|
||
* @returns {Function} Returns the new bound function.
|
||
* @example
|
||
*
|
||
* var object = {
|
||
* 'user': 'fred',
|
||
* 'greet': function(greeting, punctuation) {
|
||
* return greeting + ' ' + this.user + punctuation;
|
||
* }
|
||
* };
|
||
*
|
||
* var bound = _.bindKey(object, 'greet', 'hi');
|
||
* bound('!');
|
||
* // => 'hi fred!'
|
||
*
|
||
* object.greet = function(greeting, punctuation) {
|
||
* return greeting + 'ya ' + this.user + punctuation;
|
||
* };
|
||
*
|
||
* bound('!');
|
||
* // => 'hiya fred!'
|
||
*
|
||
* // Bound with placeholders.
|
||
* var bound = _.bindKey(object, 'greet', _, '!');
|
||
* bound('hi');
|
||
* // => 'hiya fred!'
|
||
*/
|
||
var bindKey = rest(function(object, key, partials) {
|
||
var bitmask = BIND_FLAG | BIND_KEY_FLAG;
|
||
if (partials.length) {
|
||
var holders = replaceHolders(partials, getPlaceholder(bindKey));
|
||
bitmask |= PARTIAL_FLAG;
|
||
}
|
||
return createWrapper(key, bitmask, object, partials, holders);
|
||
});
|
||
|
||
/**
|
||
* Creates a function that accepts arguments of `func` and either invokes
|
||
* `func` returning its result, if at least `arity` number of arguments have
|
||
* been provided, or returns a function that accepts the remaining `func`
|
||
* arguments, and so on. The arity of `func` may be specified if `func.length`
|
||
* is not sufficient.
|
||
*
|
||
* The `_.curry.placeholder` value, which defaults to `_` in monolithic builds,
|
||
* may be used as a placeholder for provided arguments.
|
||
*
|
||
* **Note:** This method doesn't set the "length" property of curried functions.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.0.0
|
||
* @category Function
|
||
* @param {Function} func The function to curry.
|
||
* @param {number} [arity=func.length] The arity of `func`.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {Function} Returns the new curried function.
|
||
* @example
|
||
*
|
||
* var abc = function(a, b, c) {
|
||
* return [a, b, c];
|
||
* };
|
||
*
|
||
* var curried = _.curry(abc);
|
||
*
|
||
* curried(1)(2)(3);
|
||
* // => [1, 2, 3]
|
||
*
|
||
* curried(1, 2)(3);
|
||
* // => [1, 2, 3]
|
||
*
|
||
* curried(1, 2, 3);
|
||
* // => [1, 2, 3]
|
||
*
|
||
* // Curried with placeholders.
|
||
* curried(1)(_, 3)(2);
|
||
* // => [1, 2, 3]
|
||
*/
|
||
function curry(func, arity, guard) {
|
||
arity = guard ? undefined : arity;
|
||
var result = createWrapper(func, CURRY_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
|
||
result.placeholder = curry.placeholder;
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.curry` except that arguments are applied to `func`
|
||
* in the manner of `_.partialRight` instead of `_.partial`.
|
||
*
|
||
* The `_.curryRight.placeholder` value, which defaults to `_` in monolithic
|
||
* builds, may be used as a placeholder for provided arguments.
|
||
*
|
||
* **Note:** This method doesn't set the "length" property of curried functions.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Function
|
||
* @param {Function} func The function to curry.
|
||
* @param {number} [arity=func.length] The arity of `func`.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {Function} Returns the new curried function.
|
||
* @example
|
||
*
|
||
* var abc = function(a, b, c) {
|
||
* return [a, b, c];
|
||
* };
|
||
*
|
||
* var curried = _.curryRight(abc);
|
||
*
|
||
* curried(3)(2)(1);
|
||
* // => [1, 2, 3]
|
||
*
|
||
* curried(2, 3)(1);
|
||
* // => [1, 2, 3]
|
||
*
|
||
* curried(1, 2, 3);
|
||
* // => [1, 2, 3]
|
||
*
|
||
* // Curried with placeholders.
|
||
* curried(3)(1, _)(2);
|
||
* // => [1, 2, 3]
|
||
*/
|
||
function curryRight(func, arity, guard) {
|
||
arity = guard ? undefined : arity;
|
||
var result = createWrapper(func, CURRY_RIGHT_FLAG, undefined, undefined, undefined, undefined, undefined, arity);
|
||
result.placeholder = curryRight.placeholder;
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Creates a debounced function that delays invoking `func` until after `wait`
|
||
* milliseconds have elapsed since the last time the debounced function was
|
||
* invoked. The debounced function comes with a `cancel` method to cancel
|
||
* delayed `func` invocations and a `flush` method to immediately invoke them.
|
||
* Provide an options object to indicate whether `func` should be invoked on
|
||
* the leading and/or trailing edge of the `wait` timeout. The `func` is invoked
|
||
* with the last arguments provided to the debounced function. Subsequent calls
|
||
* to the debounced function return the result of the last `func` invocation.
|
||
*
|
||
* **Note:** If `leading` and `trailing` options are `true`, `func` is invoked
|
||
* on the trailing edge of the timeout only if the debounced function is
|
||
* invoked more than once during the `wait` timeout.
|
||
*
|
||
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
|
||
* for details over the differences between `_.debounce` and `_.throttle`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Function
|
||
* @param {Function} func The function to debounce.
|
||
* @param {number} [wait=0] The number of milliseconds to delay.
|
||
* @param {Object} [options={}] The options object.
|
||
* @param {boolean} [options.leading=false]
|
||
* Specify invoking on the leading edge of the timeout.
|
||
* @param {number} [options.maxWait]
|
||
* The maximum time `func` is allowed to be delayed before it's invoked.
|
||
* @param {boolean} [options.trailing=true]
|
||
* Specify invoking on the trailing edge of the timeout.
|
||
* @returns {Function} Returns the new debounced function.
|
||
* @example
|
||
*
|
||
* // Avoid costly calculations while the window size is in flux.
|
||
* jQuery(window).on('resize', _.debounce(calculateLayout, 150));
|
||
*
|
||
* // Invoke `sendMail` when clicked, debouncing subsequent calls.
|
||
* jQuery(element).on('click', _.debounce(sendMail, 300, {
|
||
* 'leading': true,
|
||
* 'trailing': false
|
||
* }));
|
||
*
|
||
* // Ensure `batchLog` is invoked once after 1 second of debounced calls.
|
||
* var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 });
|
||
* var source = new EventSource('/stream');
|
||
* jQuery(source).on('message', debounced);
|
||
*
|
||
* // Cancel the trailing debounced invocation.
|
||
* jQuery(window).on('popstate', debounced.cancel);
|
||
*/
|
||
function debounce(func, wait, options) {
|
||
var lastArgs,
|
||
lastThis,
|
||
maxWait,
|
||
result,
|
||
timerId,
|
||
lastCallTime = 0,
|
||
lastInvokeTime = 0,
|
||
leading = false,
|
||
maxing = false,
|
||
trailing = true;
|
||
|
||
if (typeof func != 'function') {
|
||
throw new TypeError(FUNC_ERROR_TEXT);
|
||
}
|
||
wait = toNumber(wait) || 0;
|
||
if (isObject(options)) {
|
||
leading = !!options.leading;
|
||
maxing = 'maxWait' in options;
|
||
maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait;
|
||
trailing = 'trailing' in options ? !!options.trailing : trailing;
|
||
}
|
||
|
||
function invokeFunc(time) {
|
||
var args = lastArgs,
|
||
thisArg = lastThis;
|
||
|
||
lastArgs = lastThis = undefined;
|
||
lastInvokeTime = time;
|
||
result = func.apply(thisArg, args);
|
||
return result;
|
||
}
|
||
|
||
function leadingEdge(time) {
|
||
// Reset any `maxWait` timer.
|
||
lastInvokeTime = time;
|
||
// Start the timer for the trailing edge.
|
||
timerId = setTimeout(timerExpired, wait);
|
||
// Invoke the leading edge.
|
||
return leading ? invokeFunc(time) : result;
|
||
}
|
||
|
||
function remainingWait(time) {
|
||
var timeSinceLastCall = time - lastCallTime,
|
||
timeSinceLastInvoke = time - lastInvokeTime,
|
||
result = wait - timeSinceLastCall;
|
||
|
||
return maxing ? nativeMin(result, maxWait - timeSinceLastInvoke) : result;
|
||
}
|
||
|
||
function shouldInvoke(time) {
|
||
var timeSinceLastCall = time - lastCallTime,
|
||
timeSinceLastInvoke = time - lastInvokeTime;
|
||
|
||
// Either this is the first call, activity has stopped and we're at the
|
||
// trailing edge, the system time has gone backwards and we're treating
|
||
// it as the trailing edge, or we've hit the `maxWait` limit.
|
||
return (!lastCallTime || (timeSinceLastCall >= wait) ||
|
||
(timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait));
|
||
}
|
||
|
||
function timerExpired() {
|
||
var time = now();
|
||
if (shouldInvoke(time)) {
|
||
return trailingEdge(time);
|
||
}
|
||
// Restart the timer.
|
||
timerId = setTimeout(timerExpired, remainingWait(time));
|
||
}
|
||
|
||
function trailingEdge(time) {
|
||
clearTimeout(timerId);
|
||
timerId = undefined;
|
||
|
||
// Only invoke if we have `lastArgs` which means `func` has been
|
||
// debounced at least once.
|
||
if (trailing && lastArgs) {
|
||
return invokeFunc(time);
|
||
}
|
||
lastArgs = lastThis = undefined;
|
||
return result;
|
||
}
|
||
|
||
function cancel() {
|
||
if (timerId !== undefined) {
|
||
clearTimeout(timerId);
|
||
}
|
||
lastCallTime = lastInvokeTime = 0;
|
||
lastArgs = lastThis = timerId = undefined;
|
||
}
|
||
|
||
function flush() {
|
||
return timerId === undefined ? result : trailingEdge(now());
|
||
}
|
||
|
||
function debounced() {
|
||
var time = now(),
|
||
isInvoking = shouldInvoke(time);
|
||
|
||
lastArgs = arguments;
|
||
lastThis = this;
|
||
lastCallTime = time;
|
||
|
||
if (isInvoking) {
|
||
if (timerId === undefined) {
|
||
return leadingEdge(lastCallTime);
|
||
}
|
||
if (maxing) {
|
||
// Handle invocations in a tight loop.
|
||
clearTimeout(timerId);
|
||
timerId = setTimeout(timerExpired, wait);
|
||
return invokeFunc(lastCallTime);
|
||
}
|
||
}
|
||
if (timerId === undefined) {
|
||
timerId = setTimeout(timerExpired, wait);
|
||
}
|
||
return result;
|
||
}
|
||
debounced.cancel = cancel;
|
||
debounced.flush = flush;
|
||
return debounced;
|
||
}
|
||
|
||
/**
|
||
* Defers invoking the `func` until the current call stack has cleared. Any
|
||
* additional arguments are provided to `func` when it's invoked.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Function
|
||
* @param {Function} func The function to defer.
|
||
* @param {...*} [args] The arguments to invoke `func` with.
|
||
* @returns {number} Returns the timer id.
|
||
* @example
|
||
*
|
||
* _.defer(function(text) {
|
||
* console.log(text);
|
||
* }, 'deferred');
|
||
* // => Logs 'deferred' after one or more milliseconds.
|
||
*/
|
||
var defer = rest(function(func, args) {
|
||
return baseDelay(func, 1, args);
|
||
});
|
||
|
||
/**
|
||
* Invokes `func` after `wait` milliseconds. Any additional arguments are
|
||
* provided to `func` when it's invoked.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Function
|
||
* @param {Function} func The function to delay.
|
||
* @param {number} wait The number of milliseconds to delay invocation.
|
||
* @param {...*} [args] The arguments to invoke `func` with.
|
||
* @returns {number} Returns the timer id.
|
||
* @example
|
||
*
|
||
* _.delay(function(text) {
|
||
* console.log(text);
|
||
* }, 1000, 'later');
|
||
* // => Logs 'later' after one second.
|
||
*/
|
||
var delay = rest(function(func, wait, args) {
|
||
return baseDelay(func, toNumber(wait) || 0, args);
|
||
});
|
||
|
||
/**
|
||
* Creates a function that invokes `func` with arguments reversed.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Function
|
||
* @param {Function} func The function to flip arguments for.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var flipped = _.flip(function() {
|
||
* return _.toArray(arguments);
|
||
* });
|
||
*
|
||
* flipped('a', 'b', 'c', 'd');
|
||
* // => ['d', 'c', 'b', 'a']
|
||
*/
|
||
function flip(func) {
|
||
return createWrapper(func, FLIP_FLAG);
|
||
}
|
||
|
||
/**
|
||
* Creates a function that memoizes the result of `func`. If `resolver` is
|
||
* provided, it determines the cache key for storing the result based on the
|
||
* arguments provided to the memoized function. By default, the first argument
|
||
* provided to the memoized function is used as the map cache key. The `func`
|
||
* is invoked with the `this` binding of the memoized function.
|
||
*
|
||
* **Note:** The cache is exposed as the `cache` property on the memoized
|
||
* function. Its creation may be customized by replacing the `_.memoize.Cache`
|
||
* constructor with one whose instances implement the
|
||
* [`Map`](http://ecma-international.org/ecma-262/6.0/#sec-properties-of-the-map-prototype-object)
|
||
* method interface of `delete`, `get`, `has`, and `set`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Function
|
||
* @param {Function} func The function to have its output memoized.
|
||
* @param {Function} [resolver] The function to resolve the cache key.
|
||
* @returns {Function} Returns the new memoizing function.
|
||
* @example
|
||
*
|
||
* var object = { 'a': 1, 'b': 2 };
|
||
* var other = { 'c': 3, 'd': 4 };
|
||
*
|
||
* var values = _.memoize(_.values);
|
||
* values(object);
|
||
* // => [1, 2]
|
||
*
|
||
* values(other);
|
||
* // => [3, 4]
|
||
*
|
||
* object.a = 2;
|
||
* values(object);
|
||
* // => [1, 2]
|
||
*
|
||
* // Modify the result cache.
|
||
* values.cache.set(object, ['a', 'b']);
|
||
* values(object);
|
||
* // => ['a', 'b']
|
||
*
|
||
* // Replace `_.memoize.Cache`.
|
||
* _.memoize.Cache = WeakMap;
|
||
*/
|
||
function memoize(func, resolver) {
|
||
if (typeof func != 'function' || (resolver && typeof resolver != 'function')) {
|
||
throw new TypeError(FUNC_ERROR_TEXT);
|
||
}
|
||
var memoized = function() {
|
||
var args = arguments,
|
||
key = resolver ? resolver.apply(this, args) : args[0],
|
||
cache = memoized.cache;
|
||
|
||
if (cache.has(key)) {
|
||
return cache.get(key);
|
||
}
|
||
var result = func.apply(this, args);
|
||
memoized.cache = cache.set(key, result);
|
||
return result;
|
||
};
|
||
memoized.cache = new (memoize.Cache || MapCache);
|
||
return memoized;
|
||
}
|
||
|
||
// Assign cache to `_.memoize`.
|
||
memoize.Cache = MapCache;
|
||
|
||
/**
|
||
* Creates a function that negates the result of the predicate `func`. The
|
||
* `func` predicate is invoked with the `this` binding and arguments of the
|
||
* created function.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Function
|
||
* @param {Function} predicate The predicate to negate.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* function isEven(n) {
|
||
* return n % 2 == 0;
|
||
* }
|
||
*
|
||
* _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven));
|
||
* // => [1, 3, 5]
|
||
*/
|
||
function negate(predicate) {
|
||
if (typeof predicate != 'function') {
|
||
throw new TypeError(FUNC_ERROR_TEXT);
|
||
}
|
||
return function() {
|
||
return !predicate.apply(this, arguments);
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates a function that is restricted to invoking `func` once. Repeat calls
|
||
* to the function return the value of the first invocation. The `func` is
|
||
* invoked with the `this` binding and arguments of the created function.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Function
|
||
* @param {Function} func The function to restrict.
|
||
* @returns {Function} Returns the new restricted function.
|
||
* @example
|
||
*
|
||
* var initialize = _.once(createApplication);
|
||
* initialize();
|
||
* initialize();
|
||
* // `initialize` invokes `createApplication` once
|
||
*/
|
||
function once(func) {
|
||
return before(2, func);
|
||
}
|
||
|
||
/**
|
||
* Creates a function that invokes `func` with arguments transformed by
|
||
* corresponding `transforms`.
|
||
*
|
||
* @static
|
||
* @since 4.0.0
|
||
* @memberOf _
|
||
* @category Function
|
||
* @param {Function} func The function to wrap.
|
||
* @param {...(Array|Array[]|Function|Function[]|Object|Object[]|string|string[])}
|
||
* [transforms[_.identity]] The functions to transform.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* function doubled(n) {
|
||
* return n * 2;
|
||
* }
|
||
*
|
||
* function square(n) {
|
||
* return n * n;
|
||
* }
|
||
*
|
||
* var func = _.overArgs(function(x, y) {
|
||
* return [x, y];
|
||
* }, square, doubled);
|
||
*
|
||
* func(9, 3);
|
||
* // => [81, 6]
|
||
*
|
||
* func(10, 5);
|
||
* // => [100, 10]
|
||
*/
|
||
var overArgs = rest(function(func, transforms) {
|
||
transforms = (transforms.length == 1 && isArray(transforms[0]))
|
||
? arrayMap(transforms[0], baseUnary(getIteratee()))
|
||
: arrayMap(baseFlatten(transforms, 1, isFlattenableIteratee), baseUnary(getIteratee()));
|
||
|
||
var funcsLength = transforms.length;
|
||
return rest(function(args) {
|
||
var index = -1,
|
||
length = nativeMin(args.length, funcsLength);
|
||
|
||
while (++index < length) {
|
||
args[index] = transforms[index].call(this, args[index]);
|
||
}
|
||
return apply(func, this, args);
|
||
});
|
||
});
|
||
|
||
/**
|
||
* Creates a function that invokes `func` with `partials` prepended to the
|
||
* arguments it receives. This method is like `_.bind` except it does **not**
|
||
* alter the `this` binding.
|
||
*
|
||
* The `_.partial.placeholder` value, which defaults to `_` in monolithic
|
||
* builds, may be used as a placeholder for partially applied arguments.
|
||
*
|
||
* **Note:** This method doesn't set the "length" property of partially
|
||
* applied functions.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.2.0
|
||
* @category Function
|
||
* @param {Function} func The function to partially apply arguments to.
|
||
* @param {...*} [partials] The arguments to be partially applied.
|
||
* @returns {Function} Returns the new partially applied function.
|
||
* @example
|
||
*
|
||
* var greet = function(greeting, name) {
|
||
* return greeting + ' ' + name;
|
||
* };
|
||
*
|
||
* var sayHelloTo = _.partial(greet, 'hello');
|
||
* sayHelloTo('fred');
|
||
* // => 'hello fred'
|
||
*
|
||
* // Partially applied with placeholders.
|
||
* var greetFred = _.partial(greet, _, 'fred');
|
||
* greetFred('hi');
|
||
* // => 'hi fred'
|
||
*/
|
||
var partial = rest(function(func, partials) {
|
||
var holders = replaceHolders(partials, getPlaceholder(partial));
|
||
return createWrapper(func, PARTIAL_FLAG, undefined, partials, holders);
|
||
});
|
||
|
||
/**
|
||
* This method is like `_.partial` except that partially applied arguments
|
||
* are appended to the arguments it receives.
|
||
*
|
||
* The `_.partialRight.placeholder` value, which defaults to `_` in monolithic
|
||
* builds, may be used as a placeholder for partially applied arguments.
|
||
*
|
||
* **Note:** This method doesn't set the "length" property of partially
|
||
* applied functions.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 1.0.0
|
||
* @category Function
|
||
* @param {Function} func The function to partially apply arguments to.
|
||
* @param {...*} [partials] The arguments to be partially applied.
|
||
* @returns {Function} Returns the new partially applied function.
|
||
* @example
|
||
*
|
||
* var greet = function(greeting, name) {
|
||
* return greeting + ' ' + name;
|
||
* };
|
||
*
|
||
* var greetFred = _.partialRight(greet, 'fred');
|
||
* greetFred('hi');
|
||
* // => 'hi fred'
|
||
*
|
||
* // Partially applied with placeholders.
|
||
* var sayHelloTo = _.partialRight(greet, 'hello', _);
|
||
* sayHelloTo('fred');
|
||
* // => 'hello fred'
|
||
*/
|
||
var partialRight = rest(function(func, partials) {
|
||
var holders = replaceHolders(partials, getPlaceholder(partialRight));
|
||
return createWrapper(func, PARTIAL_RIGHT_FLAG, undefined, partials, holders);
|
||
});
|
||
|
||
/**
|
||
* Creates a function that invokes `func` with arguments arranged according
|
||
* to the specified `indexes` where the argument value at the first index is
|
||
* provided as the first argument, the argument value at the second index is
|
||
* provided as the second argument, and so on.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Function
|
||
* @param {Function} func The function to rearrange arguments for.
|
||
* @param {...(number|number[])} indexes The arranged argument indexes.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var rearged = _.rearg(function(a, b, c) {
|
||
* return [a, b, c];
|
||
* }, 2, 0, 1);
|
||
*
|
||
* rearged('b', 'c', 'a')
|
||
* // => ['a', 'b', 'c']
|
||
*/
|
||
var rearg = rest(function(func, indexes) {
|
||
return createWrapper(func, REARG_FLAG, undefined, undefined, undefined, baseFlatten(indexes, 1));
|
||
});
|
||
|
||
/**
|
||
* Creates a function that invokes `func` with the `this` binding of the
|
||
* created function and arguments from `start` and beyond provided as
|
||
* an array.
|
||
*
|
||
* **Note:** This method is based on the
|
||
* [rest parameter](https://mdn.io/rest_parameters).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Function
|
||
* @param {Function} func The function to apply a rest parameter to.
|
||
* @param {number} [start=func.length-1] The start position of the rest parameter.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var say = _.rest(function(what, names) {
|
||
* return what + ' ' + _.initial(names).join(', ') +
|
||
* (_.size(names) > 1 ? ', & ' : '') + _.last(names);
|
||
* });
|
||
*
|
||
* say('hello', 'fred', 'barney', 'pebbles');
|
||
* // => 'hello fred, barney, & pebbles'
|
||
*/
|
||
function rest(func, start) {
|
||
if (typeof func != 'function') {
|
||
throw new TypeError(FUNC_ERROR_TEXT);
|
||
}
|
||
start = nativeMax(start === undefined ? (func.length - 1) : toInteger(start), 0);
|
||
return function() {
|
||
var args = arguments,
|
||
index = -1,
|
||
length = nativeMax(args.length - start, 0),
|
||
array = Array(length);
|
||
|
||
while (++index < length) {
|
||
array[index] = args[start + index];
|
||
}
|
||
switch (start) {
|
||
case 0: return func.call(this, array);
|
||
case 1: return func.call(this, args[0], array);
|
||
case 2: return func.call(this, args[0], args[1], array);
|
||
}
|
||
var otherArgs = Array(start + 1);
|
||
index = -1;
|
||
while (++index < start) {
|
||
otherArgs[index] = args[index];
|
||
}
|
||
otherArgs[start] = array;
|
||
return apply(func, this, otherArgs);
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates a function that invokes `func` with the `this` binding of the
|
||
* create function and an array of arguments much like
|
||
* [`Function#apply`](http://www.ecma-international.org/ecma-262/6.0/#sec-function.prototype.apply).
|
||
*
|
||
* **Note:** This method is based on the
|
||
* [spread operator](https://mdn.io/spread_operator).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.2.0
|
||
* @category Function
|
||
* @param {Function} func The function to spread arguments over.
|
||
* @param {number} [start=0] The start position of the spread.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var say = _.spread(function(who, what) {
|
||
* return who + ' says ' + what;
|
||
* });
|
||
*
|
||
* say(['fred', 'hello']);
|
||
* // => 'fred says hello'
|
||
*
|
||
* var numbers = Promise.all([
|
||
* Promise.resolve(40),
|
||
* Promise.resolve(36)
|
||
* ]);
|
||
*
|
||
* numbers.then(_.spread(function(x, y) {
|
||
* return x + y;
|
||
* }));
|
||
* // => a Promise of 76
|
||
*/
|
||
function spread(func, start) {
|
||
if (typeof func != 'function') {
|
||
throw new TypeError(FUNC_ERROR_TEXT);
|
||
}
|
||
start = start === undefined ? 0 : nativeMax(toInteger(start), 0);
|
||
return rest(function(args) {
|
||
var array = args[start],
|
||
otherArgs = castSlice(args, 0, start);
|
||
|
||
if (array) {
|
||
arrayPush(otherArgs, array);
|
||
}
|
||
return apply(func, this, otherArgs);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Creates a throttled function that only invokes `func` at most once per
|
||
* every `wait` milliseconds. The throttled function comes with a `cancel`
|
||
* method to cancel delayed `func` invocations and a `flush` method to
|
||
* immediately invoke them. Provide an options object to indicate whether
|
||
* `func` should be invoked on the leading and/or trailing edge of the `wait`
|
||
* timeout. The `func` is invoked with the last arguments provided to the
|
||
* throttled function. Subsequent calls to the throttled function return the
|
||
* result of the last `func` invocation.
|
||
*
|
||
* **Note:** If `leading` and `trailing` options are `true`, `func` is
|
||
* invoked on the trailing edge of the timeout only if the throttled function
|
||
* is invoked more than once during the `wait` timeout.
|
||
*
|
||
* See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/)
|
||
* for details over the differences between `_.throttle` and `_.debounce`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Function
|
||
* @param {Function} func The function to throttle.
|
||
* @param {number} [wait=0] The number of milliseconds to throttle invocations to.
|
||
* @param {Object} [options={}] The options object.
|
||
* @param {boolean} [options.leading=true]
|
||
* Specify invoking on the leading edge of the timeout.
|
||
* @param {boolean} [options.trailing=true]
|
||
* Specify invoking on the trailing edge of the timeout.
|
||
* @returns {Function} Returns the new throttled function.
|
||
* @example
|
||
*
|
||
* // Avoid excessively updating the position while scrolling.
|
||
* jQuery(window).on('scroll', _.throttle(updatePosition, 100));
|
||
*
|
||
* // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes.
|
||
* var throttled = _.throttle(renewToken, 300000, { 'trailing': false });
|
||
* jQuery(element).on('click', throttled);
|
||
*
|
||
* // Cancel the trailing throttled invocation.
|
||
* jQuery(window).on('popstate', throttled.cancel);
|
||
*/
|
||
function throttle(func, wait, options) {
|
||
var leading = true,
|
||
trailing = true;
|
||
|
||
if (typeof func != 'function') {
|
||
throw new TypeError(FUNC_ERROR_TEXT);
|
||
}
|
||
if (isObject(options)) {
|
||
leading = 'leading' in options ? !!options.leading : leading;
|
||
trailing = 'trailing' in options ? !!options.trailing : trailing;
|
||
}
|
||
return debounce(func, wait, {
|
||
'leading': leading,
|
||
'maxWait': wait,
|
||
'trailing': trailing
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Creates a function that accepts up to one argument, ignoring any
|
||
* additional arguments.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Function
|
||
* @param {Function} func The function to cap arguments for.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* _.map(['6', '8', '10'], _.unary(parseInt));
|
||
* // => [6, 8, 10]
|
||
*/
|
||
function unary(func) {
|
||
return ary(func, 1);
|
||
}
|
||
|
||
/**
|
||
* Creates a function that provides `value` to the wrapper function as its
|
||
* first argument. Any additional arguments provided to the function are
|
||
* appended to those provided to the wrapper function. The wrapper is invoked
|
||
* with the `this` binding of the created function.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Function
|
||
* @param {*} value The value to wrap.
|
||
* @param {Function} [wrapper=identity] The wrapper function.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var p = _.wrap(_.escape, function(func, text) {
|
||
* return '<p>' + func(text) + '</p>';
|
||
* });
|
||
*
|
||
* p('fred, barney, & pebbles');
|
||
* // => '<p>fred, barney, & pebbles</p>'
|
||
*/
|
||
function wrap(value, wrapper) {
|
||
wrapper = wrapper == null ? identity : wrapper;
|
||
return partial(wrapper, value);
|
||
}
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Casts `value` as an array if it's not one.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.4.0
|
||
* @category Lang
|
||
* @param {*} value The value to inspect.
|
||
* @returns {Array} Returns the cast array.
|
||
* @example
|
||
*
|
||
* _.castArray(1);
|
||
* // => [1]
|
||
*
|
||
* _.castArray({ 'a': 1 });
|
||
* // => [{ 'a': 1 }]
|
||
*
|
||
* _.castArray('abc');
|
||
* // => ['abc']
|
||
*
|
||
* _.castArray(null);
|
||
* // => [null]
|
||
*
|
||
* _.castArray(undefined);
|
||
* // => [undefined]
|
||
*
|
||
* _.castArray();
|
||
* // => []
|
||
*
|
||
* var array = [1, 2, 3];
|
||
* console.log(_.castArray(array) === array);
|
||
* // => true
|
||
*/
|
||
function castArray() {
|
||
if (!arguments.length) {
|
||
return [];
|
||
}
|
||
var value = arguments[0];
|
||
return isArray(value) ? value : [value];
|
||
}
|
||
|
||
/**
|
||
* Creates a shallow clone of `value`.
|
||
*
|
||
* **Note:** This method is loosely based on the
|
||
* [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)
|
||
* and supports cloning arrays, array buffers, booleans, date objects, maps,
|
||
* numbers, `Object` objects, regexes, sets, strings, symbols, and typed
|
||
* arrays. The own enumerable properties of `arguments` objects are cloned
|
||
* as plain objects. An empty object is returned for uncloneable values such
|
||
* as error objects, functions, DOM nodes, and WeakMaps.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Lang
|
||
* @param {*} value The value to clone.
|
||
* @returns {*} Returns the cloned value.
|
||
* @example
|
||
*
|
||
* var objects = [{ 'a': 1 }, { 'b': 2 }];
|
||
*
|
||
* var shallow = _.clone(objects);
|
||
* console.log(shallow[0] === objects[0]);
|
||
* // => true
|
||
*/
|
||
function clone(value) {
|
||
return baseClone(value, false, true);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.clone` except that it accepts `customizer` which
|
||
* is invoked to produce the cloned value. If `customizer` returns `undefined`,
|
||
* cloning is handled by the method instead. The `customizer` is invoked with
|
||
* up to four arguments; (value [, index|key, object, stack]).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to clone.
|
||
* @param {Function} [customizer] The function to customize cloning.
|
||
* @returns {*} Returns the cloned value.
|
||
* @example
|
||
*
|
||
* function customizer(value) {
|
||
* if (_.isElement(value)) {
|
||
* return value.cloneNode(false);
|
||
* }
|
||
* }
|
||
*
|
||
* var el = _.cloneWith(document.body, customizer);
|
||
*
|
||
* console.log(el === document.body);
|
||
* // => false
|
||
* console.log(el.nodeName);
|
||
* // => 'BODY'
|
||
* console.log(el.childNodes.length);
|
||
* // => 0
|
||
*/
|
||
function cloneWith(value, customizer) {
|
||
return baseClone(value, false, true, customizer);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.clone` except that it recursively clones `value`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 1.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to recursively clone.
|
||
* @returns {*} Returns the deep cloned value.
|
||
* @example
|
||
*
|
||
* var objects = [{ 'a': 1 }, { 'b': 2 }];
|
||
*
|
||
* var deep = _.cloneDeep(objects);
|
||
* console.log(deep[0] === objects[0]);
|
||
* // => false
|
||
*/
|
||
function cloneDeep(value) {
|
||
return baseClone(value, true, true);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.cloneWith` except that it recursively clones `value`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to recursively clone.
|
||
* @param {Function} [customizer] The function to customize cloning.
|
||
* @returns {*} Returns the deep cloned value.
|
||
* @example
|
||
*
|
||
* function customizer(value) {
|
||
* if (_.isElement(value)) {
|
||
* return value.cloneNode(true);
|
||
* }
|
||
* }
|
||
*
|
||
* var el = _.cloneDeepWith(document.body, customizer);
|
||
*
|
||
* console.log(el === document.body);
|
||
* // => false
|
||
* console.log(el.nodeName);
|
||
* // => 'BODY'
|
||
* console.log(el.childNodes.length);
|
||
* // => 20
|
||
*/
|
||
function cloneDeepWith(value, customizer) {
|
||
return baseClone(value, true, true, customizer);
|
||
}
|
||
|
||
/**
|
||
* Performs a
|
||
* [`SameValueZero`](http://ecma-international.org/ecma-262/6.0/#sec-samevaluezero)
|
||
* comparison between two values to determine if they are equivalent.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to compare.
|
||
* @param {*} other The other value to compare.
|
||
* @returns {boolean} Returns `true` if the values are equivalent, else `false`.
|
||
* @example
|
||
*
|
||
* var object = { 'user': 'fred' };
|
||
* var other = { 'user': 'fred' };
|
||
*
|
||
* _.eq(object, object);
|
||
* // => true
|
||
*
|
||
* _.eq(object, other);
|
||
* // => false
|
||
*
|
||
* _.eq('a', 'a');
|
||
* // => true
|
||
*
|
||
* _.eq('a', Object('a'));
|
||
* // => false
|
||
*
|
||
* _.eq(NaN, NaN);
|
||
* // => true
|
||
*/
|
||
function eq(value, other) {
|
||
return value === other || (value !== value && other !== other);
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is greater than `other`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.9.0
|
||
* @category Lang
|
||
* @param {*} value The value to compare.
|
||
* @param {*} other The other value to compare.
|
||
* @returns {boolean} Returns `true` if `value` is greater than `other`,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.gt(3, 1);
|
||
* // => true
|
||
*
|
||
* _.gt(3, 3);
|
||
* // => false
|
||
*
|
||
* _.gt(1, 3);
|
||
* // => false
|
||
*/
|
||
function gt(value, other) {
|
||
return value > other;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is greater than or equal to `other`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.9.0
|
||
* @category Lang
|
||
* @param {*} value The value to compare.
|
||
* @param {*} other The other value to compare.
|
||
* @returns {boolean} Returns `true` if `value` is greater than or equal to
|
||
* `other`, else `false`.
|
||
* @example
|
||
*
|
||
* _.gte(3, 1);
|
||
* // => true
|
||
*
|
||
* _.gte(3, 3);
|
||
* // => true
|
||
*
|
||
* _.gte(1, 3);
|
||
* // => false
|
||
*/
|
||
function gte(value, other) {
|
||
return value >= other;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is likely an `arguments` object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is correctly classified,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isArguments(function() { return arguments; }());
|
||
* // => true
|
||
*
|
||
* _.isArguments([1, 2, 3]);
|
||
* // => false
|
||
*/
|
||
function isArguments(value) {
|
||
// Safari 8.1 incorrectly makes `arguments.callee` enumerable in strict mode.
|
||
return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') &&
|
||
(!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag);
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is classified as an `Array` object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @type {Function}
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is correctly classified,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isArray([1, 2, 3]);
|
||
* // => true
|
||
*
|
||
* _.isArray(document.body.children);
|
||
* // => false
|
||
*
|
||
* _.isArray('abc');
|
||
* // => false
|
||
*
|
||
* _.isArray(_.noop);
|
||
* // => false
|
||
*/
|
||
var isArray = Array.isArray;
|
||
|
||
/**
|
||
* Checks if `value` is classified as an `ArrayBuffer` object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.3.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is correctly classified,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isArrayBuffer(new ArrayBuffer(2));
|
||
* // => true
|
||
*
|
||
* _.isArrayBuffer(new Array(2));
|
||
* // => false
|
||
*/
|
||
function isArrayBuffer(value) {
|
||
return isObjectLike(value) && objectToString.call(value) == arrayBufferTag;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is array-like. A value is considered array-like if it's
|
||
* not a function and has a `value.length` that's an integer greater than or
|
||
* equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is array-like, else `false`.
|
||
* @example
|
||
*
|
||
* _.isArrayLike([1, 2, 3]);
|
||
* // => true
|
||
*
|
||
* _.isArrayLike(document.body.children);
|
||
* // => true
|
||
*
|
||
* _.isArrayLike('abc');
|
||
* // => true
|
||
*
|
||
* _.isArrayLike(_.noop);
|
||
* // => false
|
||
*/
|
||
function isArrayLike(value) {
|
||
return value != null && isLength(getLength(value)) && !isFunction(value);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.isArrayLike` except that it also checks if `value`
|
||
* is an object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is an array-like object,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isArrayLikeObject([1, 2, 3]);
|
||
* // => true
|
||
*
|
||
* _.isArrayLikeObject(document.body.children);
|
||
* // => true
|
||
*
|
||
* _.isArrayLikeObject('abc');
|
||
* // => false
|
||
*
|
||
* _.isArrayLikeObject(_.noop);
|
||
* // => false
|
||
*/
|
||
function isArrayLikeObject(value) {
|
||
return isObjectLike(value) && isArrayLike(value);
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is classified as a boolean primitive or object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is correctly classified,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isBoolean(false);
|
||
* // => true
|
||
*
|
||
* _.isBoolean(null);
|
||
* // => false
|
||
*/
|
||
function isBoolean(value) {
|
||
return value === true || value === false ||
|
||
(isObjectLike(value) && objectToString.call(value) == boolTag);
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is a buffer.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.3.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is a buffer, else `false`.
|
||
* @example
|
||
*
|
||
* _.isBuffer(new Buffer(2));
|
||
* // => true
|
||
*
|
||
* _.isBuffer(new Uint8Array(2));
|
||
* // => false
|
||
*/
|
||
var isBuffer = !Buffer ? constant(false) : function(value) {
|
||
return value instanceof Buffer;
|
||
};
|
||
|
||
/**
|
||
* Checks if `value` is classified as a `Date` object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is correctly classified,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isDate(new Date);
|
||
* // => true
|
||
*
|
||
* _.isDate('Mon April 23 2012');
|
||
* // => false
|
||
*/
|
||
function isDate(value) {
|
||
return isObjectLike(value) && objectToString.call(value) == dateTag;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is likely a DOM element.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is a DOM element,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isElement(document.body);
|
||
* // => true
|
||
*
|
||
* _.isElement('<body>');
|
||
* // => false
|
||
*/
|
||
function isElement(value) {
|
||
return !!value && value.nodeType === 1 && isObjectLike(value) && !isPlainObject(value);
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is an empty object, collection, map, or set.
|
||
*
|
||
* Objects are considered empty if they have no own enumerable string keyed
|
||
* properties.
|
||
*
|
||
* Array-like values such as `arguments` objects, arrays, buffers, strings, or
|
||
* jQuery-like collections are considered empty if they have a `length` of `0`.
|
||
* Similarly, maps and sets are considered empty if they have a `size` of `0`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is empty, else `false`.
|
||
* @example
|
||
*
|
||
* _.isEmpty(null);
|
||
* // => true
|
||
*
|
||
* _.isEmpty(true);
|
||
* // => true
|
||
*
|
||
* _.isEmpty(1);
|
||
* // => true
|
||
*
|
||
* _.isEmpty([1, 2, 3]);
|
||
* // => false
|
||
*
|
||
* _.isEmpty({ 'a': 1 });
|
||
* // => false
|
||
*/
|
||
function isEmpty(value) {
|
||
if (isArrayLike(value) &&
|
||
(isArray(value) || isString(value) || isFunction(value.splice) ||
|
||
isArguments(value) || isBuffer(value))) {
|
||
return !value.length;
|
||
}
|
||
if (isObjectLike(value)) {
|
||
var tag = getTag(value);
|
||
if (tag == mapTag || tag == setTag) {
|
||
return !value.size;
|
||
}
|
||
}
|
||
for (var key in value) {
|
||
if (hasOwnProperty.call(value, key)) {
|
||
return false;
|
||
}
|
||
}
|
||
return !(nonEnumShadows && keys(value).length);
|
||
}
|
||
|
||
/**
|
||
* Performs a deep comparison between two values to determine if they are
|
||
* equivalent.
|
||
*
|
||
* **Note:** This method supports comparing arrays, array buffers, booleans,
|
||
* date objects, error objects, maps, numbers, `Object` objects, regexes,
|
||
* sets, strings, symbols, and typed arrays. `Object` objects are compared
|
||
* by their own, not inherited, enumerable properties. Functions and DOM
|
||
* nodes are **not** supported.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Lang
|
||
* @param {*} value The value to compare.
|
||
* @param {*} other The other value to compare.
|
||
* @returns {boolean} Returns `true` if the values are equivalent,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* var object = { 'user': 'fred' };
|
||
* var other = { 'user': 'fred' };
|
||
*
|
||
* _.isEqual(object, other);
|
||
* // => true
|
||
*
|
||
* object === other;
|
||
* // => false
|
||
*/
|
||
function isEqual(value, other) {
|
||
return baseIsEqual(value, other);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.isEqual` except that it accepts `customizer` which
|
||
* is invoked to compare values. If `customizer` returns `undefined`, comparisons
|
||
* are handled by the method instead. The `customizer` is invoked with up to
|
||
* six arguments: (objValue, othValue [, index|key, object, other, stack]).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to compare.
|
||
* @param {*} other The other value to compare.
|
||
* @param {Function} [customizer] The function to customize comparisons.
|
||
* @returns {boolean} Returns `true` if the values are equivalent,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* function isGreeting(value) {
|
||
* return /^h(?:i|ello)$/.test(value);
|
||
* }
|
||
*
|
||
* function customizer(objValue, othValue) {
|
||
* if (isGreeting(objValue) && isGreeting(othValue)) {
|
||
* return true;
|
||
* }
|
||
* }
|
||
*
|
||
* var array = ['hello', 'goodbye'];
|
||
* var other = ['hi', 'goodbye'];
|
||
*
|
||
* _.isEqualWith(array, other, customizer);
|
||
* // => true
|
||
*/
|
||
function isEqualWith(value, other, customizer) {
|
||
customizer = typeof customizer == 'function' ? customizer : undefined;
|
||
var result = customizer ? customizer(value, other) : undefined;
|
||
return result === undefined ? baseIsEqual(value, other, customizer) : !!result;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
|
||
* `SyntaxError`, `TypeError`, or `URIError` object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is an error object,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isError(new Error);
|
||
* // => true
|
||
*
|
||
* _.isError(Error);
|
||
* // => false
|
||
*/
|
||
function isError(value) {
|
||
if (!isObjectLike(value)) {
|
||
return false;
|
||
}
|
||
return (objectToString.call(value) == errorTag) ||
|
||
(typeof value.message == 'string' && typeof value.name == 'string');
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is a finite primitive number.
|
||
*
|
||
* **Note:** This method is based on
|
||
* [`Number.isFinite`](https://mdn.io/Number/isFinite).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is a finite number,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isFinite(3);
|
||
* // => true
|
||
*
|
||
* _.isFinite(Number.MAX_VALUE);
|
||
* // => true
|
||
*
|
||
* _.isFinite(3.14);
|
||
* // => true
|
||
*
|
||
* _.isFinite(Infinity);
|
||
* // => false
|
||
*/
|
||
function isFinite(value) {
|
||
return typeof value == 'number' && nativeIsFinite(value);
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is classified as a `Function` object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is correctly classified,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isFunction(_);
|
||
* // => true
|
||
*
|
||
* _.isFunction(/abc/);
|
||
* // => false
|
||
*/
|
||
function isFunction(value) {
|
||
// The use of `Object#toString` avoids issues with the `typeof` operator
|
||
// in Safari 8 which returns 'object' for typed array and weak map constructors,
|
||
// and PhantomJS 1.9 which returns 'function' for `NodeList` instances.
|
||
var tag = isObject(value) ? objectToString.call(value) : '';
|
||
return tag == funcTag || tag == genTag;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is an integer.
|
||
*
|
||
* **Note:** This method is based on
|
||
* [`Number.isInteger`](https://mdn.io/Number/isInteger).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is an integer, else `false`.
|
||
* @example
|
||
*
|
||
* _.isInteger(3);
|
||
* // => true
|
||
*
|
||
* _.isInteger(Number.MIN_VALUE);
|
||
* // => false
|
||
*
|
||
* _.isInteger(Infinity);
|
||
* // => false
|
||
*
|
||
* _.isInteger('3');
|
||
* // => false
|
||
*/
|
||
function isInteger(value) {
|
||
return typeof value == 'number' && value == toInteger(value);
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is a valid array-like length.
|
||
*
|
||
* **Note:** This function is loosely based on
|
||
* [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is a valid length,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isLength(3);
|
||
* // => true
|
||
*
|
||
* _.isLength(Number.MIN_VALUE);
|
||
* // => false
|
||
*
|
||
* _.isLength(Infinity);
|
||
* // => false
|
||
*
|
||
* _.isLength('3');
|
||
* // => false
|
||
*/
|
||
function isLength(value) {
|
||
return typeof value == 'number' &&
|
||
value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is the
|
||
* [language type](http://www.ecma-international.org/ecma-262/6.0/#sec-ecmascript-language-types)
|
||
* of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is an object, else `false`.
|
||
* @example
|
||
*
|
||
* _.isObject({});
|
||
* // => true
|
||
*
|
||
* _.isObject([1, 2, 3]);
|
||
* // => true
|
||
*
|
||
* _.isObject(_.noop);
|
||
* // => true
|
||
*
|
||
* _.isObject(null);
|
||
* // => false
|
||
*/
|
||
function isObject(value) {
|
||
var type = typeof value;
|
||
return !!value && (type == 'object' || type == 'function');
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is object-like. A value is object-like if it's not `null`
|
||
* and has a `typeof` result of "object".
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
|
||
* @example
|
||
*
|
||
* _.isObjectLike({});
|
||
* // => true
|
||
*
|
||
* _.isObjectLike([1, 2, 3]);
|
||
* // => true
|
||
*
|
||
* _.isObjectLike(_.noop);
|
||
* // => false
|
||
*
|
||
* _.isObjectLike(null);
|
||
* // => false
|
||
*/
|
||
function isObjectLike(value) {
|
||
return !!value && typeof value == 'object';
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is classified as a `Map` object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.3.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is correctly classified,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isMap(new Map);
|
||
* // => true
|
||
*
|
||
* _.isMap(new WeakMap);
|
||
* // => false
|
||
*/
|
||
function isMap(value) {
|
||
return isObjectLike(value) && getTag(value) == mapTag;
|
||
}
|
||
|
||
/**
|
||
* Performs a partial deep comparison between `object` and `source` to
|
||
* determine if `object` contains equivalent property values. This method is
|
||
* equivalent to a `_.matches` function when `source` is partially applied.
|
||
*
|
||
* **Note:** This method supports comparing the same values as `_.isEqual`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Lang
|
||
* @param {Object} object The object to inspect.
|
||
* @param {Object} source The object of property values to match.
|
||
* @returns {boolean} Returns `true` if `object` is a match, else `false`.
|
||
* @example
|
||
*
|
||
* var object = { 'user': 'fred', 'age': 40 };
|
||
*
|
||
* _.isMatch(object, { 'age': 40 });
|
||
* // => true
|
||
*
|
||
* _.isMatch(object, { 'age': 36 });
|
||
* // => false
|
||
*/
|
||
function isMatch(object, source) {
|
||
return object === source || baseIsMatch(object, source, getMatchData(source));
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.isMatch` except that it accepts `customizer` which
|
||
* is invoked to compare values. If `customizer` returns `undefined`, comparisons
|
||
* are handled by the method instead. The `customizer` is invoked with five
|
||
* arguments: (objValue, srcValue, index|key, object, source).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {Object} object The object to inspect.
|
||
* @param {Object} source The object of property values to match.
|
||
* @param {Function} [customizer] The function to customize comparisons.
|
||
* @returns {boolean} Returns `true` if `object` is a match, else `false`.
|
||
* @example
|
||
*
|
||
* function isGreeting(value) {
|
||
* return /^h(?:i|ello)$/.test(value);
|
||
* }
|
||
*
|
||
* function customizer(objValue, srcValue) {
|
||
* if (isGreeting(objValue) && isGreeting(srcValue)) {
|
||
* return true;
|
||
* }
|
||
* }
|
||
*
|
||
* var object = { 'greeting': 'hello' };
|
||
* var source = { 'greeting': 'hi' };
|
||
*
|
||
* _.isMatchWith(object, source, customizer);
|
||
* // => true
|
||
*/
|
||
function isMatchWith(object, source, customizer) {
|
||
customizer = typeof customizer == 'function' ? customizer : undefined;
|
||
return baseIsMatch(object, source, getMatchData(source), customizer);
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is `NaN`.
|
||
*
|
||
* **Note:** This method is based on
|
||
* [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as
|
||
* global [`isNaN`](https://mdn.io/isNaN) which returns `true` for
|
||
* `undefined` and other non-number values.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.
|
||
* @example
|
||
*
|
||
* _.isNaN(NaN);
|
||
* // => true
|
||
*
|
||
* _.isNaN(new Number(NaN));
|
||
* // => true
|
||
*
|
||
* isNaN(undefined);
|
||
* // => true
|
||
*
|
||
* _.isNaN(undefined);
|
||
* // => false
|
||
*/
|
||
function isNaN(value) {
|
||
// An `NaN` primitive is the only value that is not equal to itself.
|
||
// Perform the `toStringTag` check first to avoid errors with some
|
||
// ActiveX objects in IE.
|
||
return isNumber(value) && value != +value;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is a native function.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is a native function,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isNative(Array.prototype.push);
|
||
* // => true
|
||
*
|
||
* _.isNative(_);
|
||
* // => false
|
||
*/
|
||
function isNative(value) {
|
||
if (!isObject(value)) {
|
||
return false;
|
||
}
|
||
var pattern = (isFunction(value) || isHostObject(value)) ? reIsNative : reIsHostCtor;
|
||
return pattern.test(toSource(value));
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is `null`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is `null`, else `false`.
|
||
* @example
|
||
*
|
||
* _.isNull(null);
|
||
* // => true
|
||
*
|
||
* _.isNull(void 0);
|
||
* // => false
|
||
*/
|
||
function isNull(value) {
|
||
return value === null;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is `null` or `undefined`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is nullish, else `false`.
|
||
* @example
|
||
*
|
||
* _.isNil(null);
|
||
* // => true
|
||
*
|
||
* _.isNil(void 0);
|
||
* // => true
|
||
*
|
||
* _.isNil(NaN);
|
||
* // => false
|
||
*/
|
||
function isNil(value) {
|
||
return value == null;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is classified as a `Number` primitive or object.
|
||
*
|
||
* **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are
|
||
* classified as numbers, use the `_.isFinite` method.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is correctly classified,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isNumber(3);
|
||
* // => true
|
||
*
|
||
* _.isNumber(Number.MIN_VALUE);
|
||
* // => true
|
||
*
|
||
* _.isNumber(Infinity);
|
||
* // => true
|
||
*
|
||
* _.isNumber('3');
|
||
* // => false
|
||
*/
|
||
function isNumber(value) {
|
||
return typeof value == 'number' ||
|
||
(isObjectLike(value) && objectToString.call(value) == numberTag);
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is a plain object, that is, an object created by the
|
||
* `Object` constructor or one with a `[[Prototype]]` of `null`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.8.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is a plain object,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.a = 1;
|
||
* }
|
||
*
|
||
* _.isPlainObject(new Foo);
|
||
* // => false
|
||
*
|
||
* _.isPlainObject([1, 2, 3]);
|
||
* // => false
|
||
*
|
||
* _.isPlainObject({ 'x': 0, 'y': 0 });
|
||
* // => true
|
||
*
|
||
* _.isPlainObject(Object.create(null));
|
||
* // => true
|
||
*/
|
||
function isPlainObject(value) {
|
||
if (!isObjectLike(value) ||
|
||
objectToString.call(value) != objectTag || isHostObject(value)) {
|
||
return false;
|
||
}
|
||
var proto = getPrototype(value);
|
||
if (proto === null) {
|
||
return true;
|
||
}
|
||
var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
|
||
return (typeof Ctor == 'function' &&
|
||
Ctor instanceof Ctor && funcToString.call(Ctor) == objectCtorString);
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is classified as a `RegExp` object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.1.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is correctly classified,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isRegExp(/abc/);
|
||
* // => true
|
||
*
|
||
* _.isRegExp('/abc/');
|
||
* // => false
|
||
*/
|
||
function isRegExp(value) {
|
||
return isObject(value) && objectToString.call(value) == regexpTag;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754
|
||
* double precision number which isn't the result of a rounded unsafe integer.
|
||
*
|
||
* **Note:** This method is based on
|
||
* [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is a safe integer,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isSafeInteger(3);
|
||
* // => true
|
||
*
|
||
* _.isSafeInteger(Number.MIN_VALUE);
|
||
* // => false
|
||
*
|
||
* _.isSafeInteger(Infinity);
|
||
* // => false
|
||
*
|
||
* _.isSafeInteger('3');
|
||
* // => false
|
||
*/
|
||
function isSafeInteger(value) {
|
||
return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is classified as a `Set` object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.3.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is correctly classified,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isSet(new Set);
|
||
* // => true
|
||
*
|
||
* _.isSet(new WeakSet);
|
||
* // => false
|
||
*/
|
||
function isSet(value) {
|
||
return isObjectLike(value) && getTag(value) == setTag;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is classified as a `String` primitive or object.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is correctly classified,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isString('abc');
|
||
* // => true
|
||
*
|
||
* _.isString(1);
|
||
* // => false
|
||
*/
|
||
function isString(value) {
|
||
return typeof value == 'string' ||
|
||
(!isArray(value) && isObjectLike(value) && objectToString.call(value) == stringTag);
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is classified as a `Symbol` primitive or object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is correctly classified,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isSymbol(Symbol.iterator);
|
||
* // => true
|
||
*
|
||
* _.isSymbol('abc');
|
||
* // => false
|
||
*/
|
||
function isSymbol(value) {
|
||
return typeof value == 'symbol' ||
|
||
(isObjectLike(value) && objectToString.call(value) == symbolTag);
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is classified as a typed array.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is correctly classified,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isTypedArray(new Uint8Array);
|
||
* // => true
|
||
*
|
||
* _.isTypedArray([]);
|
||
* // => false
|
||
*/
|
||
function isTypedArray(value) {
|
||
return isObjectLike(value) &&
|
||
isLength(value.length) && !!typedArrayTags[objectToString.call(value)];
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is `undefined`.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.
|
||
* @example
|
||
*
|
||
* _.isUndefined(void 0);
|
||
* // => true
|
||
*
|
||
* _.isUndefined(null);
|
||
* // => false
|
||
*/
|
||
function isUndefined(value) {
|
||
return value === undefined;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is classified as a `WeakMap` object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.3.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is correctly classified,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isWeakMap(new WeakMap);
|
||
* // => true
|
||
*
|
||
* _.isWeakMap(new Map);
|
||
* // => false
|
||
*/
|
||
function isWeakMap(value) {
|
||
return isObjectLike(value) && getTag(value) == weakMapTag;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is classified as a `WeakSet` object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.3.0
|
||
* @category Lang
|
||
* @param {*} value The value to check.
|
||
* @returns {boolean} Returns `true` if `value` is correctly classified,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.isWeakSet(new WeakSet);
|
||
* // => true
|
||
*
|
||
* _.isWeakSet(new Set);
|
||
* // => false
|
||
*/
|
||
function isWeakSet(value) {
|
||
return isObjectLike(value) && objectToString.call(value) == weakSetTag;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is less than `other`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.9.0
|
||
* @category Lang
|
||
* @param {*} value The value to compare.
|
||
* @param {*} other The other value to compare.
|
||
* @returns {boolean} Returns `true` if `value` is less than `other`,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.lt(1, 3);
|
||
* // => true
|
||
*
|
||
* _.lt(3, 3);
|
||
* // => false
|
||
*
|
||
* _.lt(3, 1);
|
||
* // => false
|
||
*/
|
||
function lt(value, other) {
|
||
return value < other;
|
||
}
|
||
|
||
/**
|
||
* Checks if `value` is less than or equal to `other`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.9.0
|
||
* @category Lang
|
||
* @param {*} value The value to compare.
|
||
* @param {*} other The other value to compare.
|
||
* @returns {boolean} Returns `true` if `value` is less than or equal to
|
||
* `other`, else `false`.
|
||
* @example
|
||
*
|
||
* _.lte(1, 3);
|
||
* // => true
|
||
*
|
||
* _.lte(3, 3);
|
||
* // => true
|
||
*
|
||
* _.lte(3, 1);
|
||
* // => false
|
||
*/
|
||
function lte(value, other) {
|
||
return value <= other;
|
||
}
|
||
|
||
/**
|
||
* Converts `value` to an array.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Lang
|
||
* @param {*} value The value to convert.
|
||
* @returns {Array} Returns the converted array.
|
||
* @example
|
||
*
|
||
* _.toArray({ 'a': 1, 'b': 2 });
|
||
* // => [1, 2]
|
||
*
|
||
* _.toArray('abc');
|
||
* // => ['a', 'b', 'c']
|
||
*
|
||
* _.toArray(1);
|
||
* // => []
|
||
*
|
||
* _.toArray(null);
|
||
* // => []
|
||
*/
|
||
function toArray(value) {
|
||
if (!value) {
|
||
return [];
|
||
}
|
||
if (isArrayLike(value)) {
|
||
return isString(value) ? stringToArray(value) : copyArray(value);
|
||
}
|
||
if (iteratorSymbol && value[iteratorSymbol]) {
|
||
return iteratorToArray(value[iteratorSymbol]());
|
||
}
|
||
var tag = getTag(value),
|
||
func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values);
|
||
|
||
return func(value);
|
||
}
|
||
|
||
/**
|
||
* Converts `value` to an integer.
|
||
*
|
||
* **Note:** This function is loosely based on
|
||
* [`ToInteger`](http://www.ecma-international.org/ecma-262/6.0/#sec-tointeger).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to convert.
|
||
* @returns {number} Returns the converted integer.
|
||
* @example
|
||
*
|
||
* _.toInteger(3);
|
||
* // => 3
|
||
*
|
||
* _.toInteger(Number.MIN_VALUE);
|
||
* // => 0
|
||
*
|
||
* _.toInteger(Infinity);
|
||
* // => 1.7976931348623157e+308
|
||
*
|
||
* _.toInteger('3');
|
||
* // => 3
|
||
*/
|
||
function toInteger(value) {
|
||
if (!value) {
|
||
return value === 0 ? value : 0;
|
||
}
|
||
value = toNumber(value);
|
||
if (value === INFINITY || value === -INFINITY) {
|
||
var sign = (value < 0 ? -1 : 1);
|
||
return sign * MAX_INTEGER;
|
||
}
|
||
var remainder = value % 1;
|
||
return value === value ? (remainder ? value - remainder : value) : 0;
|
||
}
|
||
|
||
/**
|
||
* Converts `value` to an integer suitable for use as the length of an
|
||
* array-like object.
|
||
*
|
||
* **Note:** This method is based on
|
||
* [`ToLength`](http://ecma-international.org/ecma-262/6.0/#sec-tolength).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to convert.
|
||
* @returns {number} Returns the converted integer.
|
||
* @example
|
||
*
|
||
* _.toLength(3);
|
||
* // => 3
|
||
*
|
||
* _.toLength(Number.MIN_VALUE);
|
||
* // => 0
|
||
*
|
||
* _.toLength(Infinity);
|
||
* // => 4294967295
|
||
*
|
||
* _.toLength('3');
|
||
* // => 3
|
||
*/
|
||
function toLength(value) {
|
||
return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0;
|
||
}
|
||
|
||
/**
|
||
* Converts `value` to a number.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to process.
|
||
* @returns {number} Returns the number.
|
||
* @example
|
||
*
|
||
* _.toNumber(3);
|
||
* // => 3
|
||
*
|
||
* _.toNumber(Number.MIN_VALUE);
|
||
* // => 5e-324
|
||
*
|
||
* _.toNumber(Infinity);
|
||
* // => Infinity
|
||
*
|
||
* _.toNumber('3');
|
||
* // => 3
|
||
*/
|
||
function toNumber(value) {
|
||
if (typeof value == 'number') {
|
||
return value;
|
||
}
|
||
if (isSymbol(value)) {
|
||
return NAN;
|
||
}
|
||
if (isObject(value)) {
|
||
var other = isFunction(value.valueOf) ? value.valueOf() : value;
|
||
value = isObject(other) ? (other + '') : other;
|
||
}
|
||
if (typeof value != 'string') {
|
||
return value === 0 ? value : +value;
|
||
}
|
||
value = value.replace(reTrim, '');
|
||
var isBinary = reIsBinary.test(value);
|
||
return (isBinary || reIsOctal.test(value))
|
||
? freeParseInt(value.slice(2), isBinary ? 2 : 8)
|
||
: (reIsBadHex.test(value) ? NAN : +value);
|
||
}
|
||
|
||
/**
|
||
* Converts `value` to a plain object flattening inherited enumerable string
|
||
* keyed properties of `value` to own properties of the plain object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to convert.
|
||
* @returns {Object} Returns the converted plain object.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.b = 2;
|
||
* }
|
||
*
|
||
* Foo.prototype.c = 3;
|
||
*
|
||
* _.assign({ 'a': 1 }, new Foo);
|
||
* // => { 'a': 1, 'b': 2 }
|
||
*
|
||
* _.assign({ 'a': 1 }, _.toPlainObject(new Foo));
|
||
* // => { 'a': 1, 'b': 2, 'c': 3 }
|
||
*/
|
||
function toPlainObject(value) {
|
||
return copyObject(value, keysIn(value));
|
||
}
|
||
|
||
/**
|
||
* Converts `value` to a safe integer. A safe integer can be compared and
|
||
* represented correctly.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to convert.
|
||
* @returns {number} Returns the converted integer.
|
||
* @example
|
||
*
|
||
* _.toSafeInteger(3);
|
||
* // => 3
|
||
*
|
||
* _.toSafeInteger(Number.MIN_VALUE);
|
||
* // => 0
|
||
*
|
||
* _.toSafeInteger(Infinity);
|
||
* // => 9007199254740991
|
||
*
|
||
* _.toSafeInteger('3');
|
||
* // => 3
|
||
*/
|
||
function toSafeInteger(value) {
|
||
return baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER);
|
||
}
|
||
|
||
/**
|
||
* Converts `value` to a string. An empty string is returned for `null`
|
||
* and `undefined` values. The sign of `-0` is preserved.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Lang
|
||
* @param {*} value The value to process.
|
||
* @returns {string} Returns the string.
|
||
* @example
|
||
*
|
||
* _.toString(null);
|
||
* // => ''
|
||
*
|
||
* _.toString(-0);
|
||
* // => '-0'
|
||
*
|
||
* _.toString([1, 2, 3]);
|
||
* // => '1,2,3'
|
||
*/
|
||
function toString(value) {
|
||
// Exit early for strings to avoid a performance hit in some environments.
|
||
if (typeof value == 'string') {
|
||
return value;
|
||
}
|
||
if (value == null) {
|
||
return '';
|
||
}
|
||
if (isSymbol(value)) {
|
||
return symbolToString ? symbolToString.call(value) : '';
|
||
}
|
||
var result = (value + '');
|
||
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
|
||
}
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Assigns own enumerable string keyed properties of source objects to the
|
||
* destination object. Source objects are applied from left to right.
|
||
* Subsequent sources overwrite property assignments of previous sources.
|
||
*
|
||
* **Note:** This method mutates `object` and is loosely based on
|
||
* [`Object.assign`](https://mdn.io/Object/assign).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.10.0
|
||
* @category Object
|
||
* @param {Object} object The destination object.
|
||
* @param {...Object} [sources] The source objects.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.c = 3;
|
||
* }
|
||
*
|
||
* function Bar() {
|
||
* this.e = 5;
|
||
* }
|
||
*
|
||
* Foo.prototype.d = 4;
|
||
* Bar.prototype.f = 6;
|
||
*
|
||
* _.assign({ 'a': 1 }, new Foo, new Bar);
|
||
* // => { 'a': 1, 'c': 3, 'e': 5 }
|
||
*/
|
||
var assign = createAssigner(function(object, source) {
|
||
if (nonEnumShadows || isPrototype(source) || isArrayLike(source)) {
|
||
copyObject(source, keys(source), object);
|
||
return;
|
||
}
|
||
for (var key in source) {
|
||
if (hasOwnProperty.call(source, key)) {
|
||
assignValue(object, key, source[key]);
|
||
}
|
||
}
|
||
});
|
||
|
||
/**
|
||
* This method is like `_.assign` except that it iterates over own and
|
||
* inherited source properties.
|
||
*
|
||
* **Note:** This method mutates `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @alias extend
|
||
* @category Object
|
||
* @param {Object} object The destination object.
|
||
* @param {...Object} [sources] The source objects.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.b = 2;
|
||
* }
|
||
*
|
||
* function Bar() {
|
||
* this.d = 4;
|
||
* }
|
||
*
|
||
* Foo.prototype.c = 3;
|
||
* Bar.prototype.e = 5;
|
||
*
|
||
* _.assignIn({ 'a': 1 }, new Foo, new Bar);
|
||
* // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5 }
|
||
*/
|
||
var assignIn = createAssigner(function(object, source) {
|
||
if (nonEnumShadows || isPrototype(source) || isArrayLike(source)) {
|
||
copyObject(source, keysIn(source), object);
|
||
return;
|
||
}
|
||
for (var key in source) {
|
||
assignValue(object, key, source[key]);
|
||
}
|
||
});
|
||
|
||
/**
|
||
* This method is like `_.assignIn` except that it accepts `customizer`
|
||
* which is invoked to produce the assigned values. If `customizer` returns
|
||
* `undefined`, assignment is handled by the method instead. The `customizer`
|
||
* is invoked with five arguments: (objValue, srcValue, key, object, source).
|
||
*
|
||
* **Note:** This method mutates `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @alias extendWith
|
||
* @category Object
|
||
* @param {Object} object The destination object.
|
||
* @param {...Object} sources The source objects.
|
||
* @param {Function} [customizer] The function to customize assigned values.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* function customizer(objValue, srcValue) {
|
||
* return _.isUndefined(objValue) ? srcValue : objValue;
|
||
* }
|
||
*
|
||
* var defaults = _.partialRight(_.assignInWith, customizer);
|
||
*
|
||
* defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
|
||
* // => { 'a': 1, 'b': 2 }
|
||
*/
|
||
var assignInWith = createAssigner(function(object, source, srcIndex, customizer) {
|
||
copyObject(source, keysIn(source), object, customizer);
|
||
});
|
||
|
||
/**
|
||
* This method is like `_.assign` except that it accepts `customizer`
|
||
* which is invoked to produce the assigned values. If `customizer` returns
|
||
* `undefined`, assignment is handled by the method instead. The `customizer`
|
||
* is invoked with five arguments: (objValue, srcValue, key, object, source).
|
||
*
|
||
* **Note:** This method mutates `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Object
|
||
* @param {Object} object The destination object.
|
||
* @param {...Object} sources The source objects.
|
||
* @param {Function} [customizer] The function to customize assigned values.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* function customizer(objValue, srcValue) {
|
||
* return _.isUndefined(objValue) ? srcValue : objValue;
|
||
* }
|
||
*
|
||
* var defaults = _.partialRight(_.assignWith, customizer);
|
||
*
|
||
* defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });
|
||
* // => { 'a': 1, 'b': 2 }
|
||
*/
|
||
var assignWith = createAssigner(function(object, source, srcIndex, customizer) {
|
||
copyObject(source, keys(source), object, customizer);
|
||
});
|
||
|
||
/**
|
||
* Creates an array of values corresponding to `paths` of `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 1.0.0
|
||
* @category Object
|
||
* @param {Object} object The object to iterate over.
|
||
* @param {...(string|string[])} [paths] The property paths of elements to pick.
|
||
* @returns {Array} Returns the new array of picked elements.
|
||
* @example
|
||
*
|
||
* var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };
|
||
*
|
||
* _.at(object, ['a[0].b.c', 'a[1]']);
|
||
* // => [3, 4]
|
||
*
|
||
* _.at(['a', 'b', 'c'], 0, 2);
|
||
* // => ['a', 'c']
|
||
*/
|
||
var at = rest(function(object, paths) {
|
||
return baseAt(object, baseFlatten(paths, 1));
|
||
});
|
||
|
||
/**
|
||
* Creates an object that inherits from the `prototype` object. If a
|
||
* `properties` object is given, its own enumerable string keyed properties
|
||
* are assigned to the created object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.3.0
|
||
* @category Object
|
||
* @param {Object} prototype The object to inherit from.
|
||
* @param {Object} [properties] The properties to assign to the object.
|
||
* @returns {Object} Returns the new object.
|
||
* @example
|
||
*
|
||
* function Shape() {
|
||
* this.x = 0;
|
||
* this.y = 0;
|
||
* }
|
||
*
|
||
* function Circle() {
|
||
* Shape.call(this);
|
||
* }
|
||
*
|
||
* Circle.prototype = _.create(Shape.prototype, {
|
||
* 'constructor': Circle
|
||
* });
|
||
*
|
||
* var circle = new Circle;
|
||
* circle instanceof Circle;
|
||
* // => true
|
||
*
|
||
* circle instanceof Shape;
|
||
* // => true
|
||
*/
|
||
function create(prototype, properties) {
|
||
var result = baseCreate(prototype);
|
||
return properties ? baseAssign(result, properties) : result;
|
||
}
|
||
|
||
/**
|
||
* Assigns own and inherited enumerable string keyed properties of source
|
||
* objects to the destination object for all destination properties that
|
||
* resolve to `undefined`. Source objects are applied from left to right.
|
||
* Once a property is set, additional values of the same property are ignored.
|
||
*
|
||
* **Note:** This method mutates `object`.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Object
|
||
* @param {Object} object The destination object.
|
||
* @param {...Object} [sources] The source objects.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* _.defaults({ 'user': 'barney' }, { 'age': 36 }, { 'user': 'fred' });
|
||
* // => { 'user': 'barney', 'age': 36 }
|
||
*/
|
||
var defaults = rest(function(args) {
|
||
args.push(undefined, assignInDefaults);
|
||
return apply(assignInWith, undefined, args);
|
||
});
|
||
|
||
/**
|
||
* This method is like `_.defaults` except that it recursively assigns
|
||
* default properties.
|
||
*
|
||
* **Note:** This method mutates `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.10.0
|
||
* @category Object
|
||
* @param {Object} object The destination object.
|
||
* @param {...Object} [sources] The source objects.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* _.defaultsDeep({ 'user': { 'name': 'barney' } }, { 'user': { 'name': 'fred', 'age': 36 } });
|
||
* // => { 'user': { 'name': 'barney', 'age': 36 } }
|
||
*
|
||
*/
|
||
var defaultsDeep = rest(function(args) {
|
||
args.push(undefined, mergeDefaults);
|
||
return apply(mergeWith, undefined, args);
|
||
});
|
||
|
||
/**
|
||
* This method is like `_.find` except that it returns the key of the first
|
||
* element `predicate` returns truthy for instead of the element itself.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 1.1.0
|
||
* @category Object
|
||
* @param {Object} object The object to search.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {string|undefined} Returns the key of the matched element,
|
||
* else `undefined`.
|
||
* @example
|
||
*
|
||
* var users = {
|
||
* 'barney': { 'age': 36, 'active': true },
|
||
* 'fred': { 'age': 40, 'active': false },
|
||
* 'pebbles': { 'age': 1, 'active': true }
|
||
* };
|
||
*
|
||
* _.findKey(users, function(o) { return o.age < 40; });
|
||
* // => 'barney' (iteration order is not guaranteed)
|
||
*
|
||
* // The `_.matches` iteratee shorthand.
|
||
* _.findKey(users, { 'age': 1, 'active': true });
|
||
* // => 'pebbles'
|
||
*
|
||
* // The `_.matchesProperty` iteratee shorthand.
|
||
* _.findKey(users, ['active', false]);
|
||
* // => 'fred'
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.findKey(users, 'active');
|
||
* // => 'barney'
|
||
*/
|
||
function findKey(object, predicate) {
|
||
return baseFind(object, getIteratee(predicate, 3), baseForOwn, true);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.findKey` except that it iterates over elements of
|
||
* a collection in the opposite order.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.0.0
|
||
* @category Object
|
||
* @param {Object} object The object to search.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {string|undefined} Returns the key of the matched element,
|
||
* else `undefined`.
|
||
* @example
|
||
*
|
||
* var users = {
|
||
* 'barney': { 'age': 36, 'active': true },
|
||
* 'fred': { 'age': 40, 'active': false },
|
||
* 'pebbles': { 'age': 1, 'active': true }
|
||
* };
|
||
*
|
||
* _.findLastKey(users, function(o) { return o.age < 40; });
|
||
* // => returns 'pebbles' assuming `_.findKey` returns 'barney'
|
||
*
|
||
* // The `_.matches` iteratee shorthand.
|
||
* _.findLastKey(users, { 'age': 36, 'active': true });
|
||
* // => 'barney'
|
||
*
|
||
* // The `_.matchesProperty` iteratee shorthand.
|
||
* _.findLastKey(users, ['active', false]);
|
||
* // => 'fred'
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.findLastKey(users, 'active');
|
||
* // => 'pebbles'
|
||
*/
|
||
function findLastKey(object, predicate) {
|
||
return baseFind(object, getIteratee(predicate, 3), baseForOwnRight, true);
|
||
}
|
||
|
||
/**
|
||
* Iterates over own and inherited enumerable string keyed properties of an
|
||
* object and invokes `iteratee` for each property. The iteratee is invoked
|
||
* with three arguments: (value, key, object). Iteratee functions may exit
|
||
* iteration early by explicitly returning `false`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.3.0
|
||
* @category Object
|
||
* @param {Object} object The object to iterate over.
|
||
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.a = 1;
|
||
* this.b = 2;
|
||
* }
|
||
*
|
||
* Foo.prototype.c = 3;
|
||
*
|
||
* _.forIn(new Foo, function(value, key) {
|
||
* console.log(key);
|
||
* });
|
||
* // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed).
|
||
*/
|
||
function forIn(object, iteratee) {
|
||
return object == null
|
||
? object
|
||
: baseFor(object, getIteratee(iteratee), keysIn);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.forIn` except that it iterates over properties of
|
||
* `object` in the opposite order.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.0.0
|
||
* @category Object
|
||
* @param {Object} object The object to iterate over.
|
||
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.a = 1;
|
||
* this.b = 2;
|
||
* }
|
||
*
|
||
* Foo.prototype.c = 3;
|
||
*
|
||
* _.forInRight(new Foo, function(value, key) {
|
||
* console.log(key);
|
||
* });
|
||
* // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'.
|
||
*/
|
||
function forInRight(object, iteratee) {
|
||
return object == null
|
||
? object
|
||
: baseForRight(object, getIteratee(iteratee), keysIn);
|
||
}
|
||
|
||
/**
|
||
* Iterates over own enumerable string keyed properties of an object and
|
||
* invokes `iteratee` for each property. The iteratee is invoked with three
|
||
* arguments: (value, key, object). Iteratee functions may exit iteration
|
||
* early by explicitly returning `false`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.3.0
|
||
* @category Object
|
||
* @param {Object} object The object to iterate over.
|
||
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.a = 1;
|
||
* this.b = 2;
|
||
* }
|
||
*
|
||
* Foo.prototype.c = 3;
|
||
*
|
||
* _.forOwn(new Foo, function(value, key) {
|
||
* console.log(key);
|
||
* });
|
||
* // => Logs 'a' then 'b' (iteration order is not guaranteed).
|
||
*/
|
||
function forOwn(object, iteratee) {
|
||
return object && baseForOwn(object, getIteratee(iteratee));
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.forOwn` except that it iterates over properties of
|
||
* `object` in the opposite order.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.0.0
|
||
* @category Object
|
||
* @param {Object} object The object to iterate over.
|
||
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.a = 1;
|
||
* this.b = 2;
|
||
* }
|
||
*
|
||
* Foo.prototype.c = 3;
|
||
*
|
||
* _.forOwnRight(new Foo, function(value, key) {
|
||
* console.log(key);
|
||
* });
|
||
* // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'.
|
||
*/
|
||
function forOwnRight(object, iteratee) {
|
||
return object && baseForOwnRight(object, getIteratee(iteratee));
|
||
}
|
||
|
||
/**
|
||
* Creates an array of function property names from own enumerable properties
|
||
* of `object`.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Object
|
||
* @param {Object} object The object to inspect.
|
||
* @returns {Array} Returns the new array of property names.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.a = _.constant('a');
|
||
* this.b = _.constant('b');
|
||
* }
|
||
*
|
||
* Foo.prototype.c = _.constant('c');
|
||
*
|
||
* _.functions(new Foo);
|
||
* // => ['a', 'b']
|
||
*/
|
||
function functions(object) {
|
||
return object == null ? [] : baseFunctions(object, keys(object));
|
||
}
|
||
|
||
/**
|
||
* Creates an array of function property names from own and inherited
|
||
* enumerable properties of `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Object
|
||
* @param {Object} object The object to inspect.
|
||
* @returns {Array} Returns the new array of property names.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.a = _.constant('a');
|
||
* this.b = _.constant('b');
|
||
* }
|
||
*
|
||
* Foo.prototype.c = _.constant('c');
|
||
*
|
||
* _.functionsIn(new Foo);
|
||
* // => ['a', 'b', 'c']
|
||
*/
|
||
function functionsIn(object) {
|
||
return object == null ? [] : baseFunctions(object, keysIn(object));
|
||
}
|
||
|
||
/**
|
||
* Gets the value at `path` of `object`. If the resolved value is
|
||
* `undefined`, the `defaultValue` is used in its place.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.7.0
|
||
* @category Object
|
||
* @param {Object} object The object to query.
|
||
* @param {Array|string} path The path of the property to get.
|
||
* @param {*} [defaultValue] The value returned for `undefined` resolved values.
|
||
* @returns {*} Returns the resolved value.
|
||
* @example
|
||
*
|
||
* var object = { 'a': [{ 'b': { 'c': 3 } }] };
|
||
*
|
||
* _.get(object, 'a[0].b.c');
|
||
* // => 3
|
||
*
|
||
* _.get(object, ['a', '0', 'b', 'c']);
|
||
* // => 3
|
||
*
|
||
* _.get(object, 'a.b.c', 'default');
|
||
* // => 'default'
|
||
*/
|
||
function get(object, path, defaultValue) {
|
||
var result = object == null ? undefined : baseGet(object, path);
|
||
return result === undefined ? defaultValue : result;
|
||
}
|
||
|
||
/**
|
||
* Checks if `path` is a direct property of `object`.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Object
|
||
* @param {Object} object The object to query.
|
||
* @param {Array|string} path The path to check.
|
||
* @returns {boolean} Returns `true` if `path` exists, else `false`.
|
||
* @example
|
||
*
|
||
* var object = { 'a': { 'b': 2 } };
|
||
* var other = _.create({ 'a': _.create({ 'b': 2 }) });
|
||
*
|
||
* _.has(object, 'a');
|
||
* // => true
|
||
*
|
||
* _.has(object, 'a.b');
|
||
* // => true
|
||
*
|
||
* _.has(object, ['a', 'b']);
|
||
* // => true
|
||
*
|
||
* _.has(other, 'a');
|
||
* // => false
|
||
*/
|
||
function has(object, path) {
|
||
return object != null && hasPath(object, path, baseHas);
|
||
}
|
||
|
||
/**
|
||
* Checks if `path` is a direct or inherited property of `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Object
|
||
* @param {Object} object The object to query.
|
||
* @param {Array|string} path The path to check.
|
||
* @returns {boolean} Returns `true` if `path` exists, else `false`.
|
||
* @example
|
||
*
|
||
* var object = _.create({ 'a': _.create({ 'b': 2 }) });
|
||
*
|
||
* _.hasIn(object, 'a');
|
||
* // => true
|
||
*
|
||
* _.hasIn(object, 'a.b');
|
||
* // => true
|
||
*
|
||
* _.hasIn(object, ['a', 'b']);
|
||
* // => true
|
||
*
|
||
* _.hasIn(object, 'b');
|
||
* // => false
|
||
*/
|
||
function hasIn(object, path) {
|
||
return object != null && hasPath(object, path, baseHasIn);
|
||
}
|
||
|
||
/**
|
||
* Creates an object composed of the inverted keys and values of `object`.
|
||
* If `object` contains duplicate values, subsequent values overwrite
|
||
* property assignments of previous values.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.7.0
|
||
* @category Object
|
||
* @param {Object} object The object to invert.
|
||
* @returns {Object} Returns the new inverted object.
|
||
* @example
|
||
*
|
||
* var object = { 'a': 1, 'b': 2, 'c': 1 };
|
||
*
|
||
* _.invert(object);
|
||
* // => { '1': 'c', '2': 'b' }
|
||
*/
|
||
var invert = createInverter(function(result, value, key) {
|
||
result[value] = key;
|
||
}, constant(identity));
|
||
|
||
/**
|
||
* This method is like `_.invert` except that the inverted object is generated
|
||
* from the results of running each element of `object` thru `iteratee`. The
|
||
* corresponding inverted value of each inverted key is an array of keys
|
||
* responsible for generating the inverted value. The iteratee is invoked
|
||
* with one argument: (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.1.0
|
||
* @category Object
|
||
* @param {Object} object The object to invert.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee invoked per element.
|
||
* @returns {Object} Returns the new inverted object.
|
||
* @example
|
||
*
|
||
* var object = { 'a': 1, 'b': 2, 'c': 1 };
|
||
*
|
||
* _.invertBy(object);
|
||
* // => { '1': ['a', 'c'], '2': ['b'] }
|
||
*
|
||
* _.invertBy(object, function(value) {
|
||
* return 'group' + value;
|
||
* });
|
||
* // => { 'group1': ['a', 'c'], 'group2': ['b'] }
|
||
*/
|
||
var invertBy = createInverter(function(result, value, key) {
|
||
if (hasOwnProperty.call(result, value)) {
|
||
result[value].push(key);
|
||
} else {
|
||
result[value] = [key];
|
||
}
|
||
}, getIteratee);
|
||
|
||
/**
|
||
* Invokes the method at `path` of `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Object
|
||
* @param {Object} object The object to query.
|
||
* @param {Array|string} path The path of the method to invoke.
|
||
* @param {...*} [args] The arguments to invoke the method with.
|
||
* @returns {*} Returns the result of the invoked method.
|
||
* @example
|
||
*
|
||
* var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] };
|
||
*
|
||
* _.invoke(object, 'a[0].b.c.slice', 1, 3);
|
||
* // => [2, 3]
|
||
*/
|
||
var invoke = rest(baseInvoke);
|
||
|
||
/**
|
||
* Creates an array of the own enumerable property names of `object`.
|
||
*
|
||
* **Note:** Non-object values are coerced to objects. See the
|
||
* [ES spec](http://ecma-international.org/ecma-262/6.0/#sec-object.keys)
|
||
* for more details.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Object
|
||
* @param {Object} object The object to query.
|
||
* @returns {Array} Returns the array of property names.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.a = 1;
|
||
* this.b = 2;
|
||
* }
|
||
*
|
||
* Foo.prototype.c = 3;
|
||
*
|
||
* _.keys(new Foo);
|
||
* // => ['a', 'b'] (iteration order is not guaranteed)
|
||
*
|
||
* _.keys('hi');
|
||
* // => ['0', '1']
|
||
*/
|
||
function keys(object) {
|
||
var isProto = isPrototype(object);
|
||
if (!(isProto || isArrayLike(object))) {
|
||
return baseKeys(object);
|
||
}
|
||
var indexes = indexKeys(object),
|
||
skipIndexes = !!indexes,
|
||
result = indexes || [],
|
||
length = result.length;
|
||
|
||
for (var key in object) {
|
||
if (baseHas(object, key) &&
|
||
!(skipIndexes && (key == 'length' || isIndex(key, length))) &&
|
||
!(isProto && key == 'constructor')) {
|
||
result.push(key);
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Creates an array of the own and inherited enumerable property names of `object`.
|
||
*
|
||
* **Note:** Non-object values are coerced to objects.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Object
|
||
* @param {Object} object The object to query.
|
||
* @returns {Array} Returns the array of property names.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.a = 1;
|
||
* this.b = 2;
|
||
* }
|
||
*
|
||
* Foo.prototype.c = 3;
|
||
*
|
||
* _.keysIn(new Foo);
|
||
* // => ['a', 'b', 'c'] (iteration order is not guaranteed)
|
||
*/
|
||
function keysIn(object) {
|
||
var index = -1,
|
||
isProto = isPrototype(object),
|
||
props = baseKeysIn(object),
|
||
propsLength = props.length,
|
||
indexes = indexKeys(object),
|
||
skipIndexes = !!indexes,
|
||
result = indexes || [],
|
||
length = result.length;
|
||
|
||
while (++index < propsLength) {
|
||
var key = props[index];
|
||
if (!(skipIndexes && (key == 'length' || isIndex(key, length))) &&
|
||
!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) {
|
||
result.push(key);
|
||
}
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* The opposite of `_.mapValues`; this method creates an object with the
|
||
* same values as `object` and keys generated by running each own enumerable
|
||
* string keyed property of `object` thru `iteratee`. The iteratee is invoked
|
||
* with three arguments: (value, key, object).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.8.0
|
||
* @category Object
|
||
* @param {Object} object The object to iterate over.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {Object} Returns the new mapped object.
|
||
* @example
|
||
*
|
||
* _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {
|
||
* return key + value;
|
||
* });
|
||
* // => { 'a1': 1, 'b2': 2 }
|
||
*/
|
||
function mapKeys(object, iteratee) {
|
||
var result = {};
|
||
iteratee = getIteratee(iteratee, 3);
|
||
|
||
baseForOwn(object, function(value, key, object) {
|
||
result[iteratee(value, key, object)] = value;
|
||
});
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Creates an object with the same keys as `object` and values generated
|
||
* by running each own enumerable string keyed property of `object` thru
|
||
* `iteratee`. The iteratee is invoked with three arguments:
|
||
* (value, key, object).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.4.0
|
||
* @category Object
|
||
* @param {Object} object The object to iterate over.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The function invoked per iteration.
|
||
* @returns {Object} Returns the new mapped object.
|
||
* @example
|
||
*
|
||
* var users = {
|
||
* 'fred': { 'user': 'fred', 'age': 40 },
|
||
* 'pebbles': { 'user': 'pebbles', 'age': 1 }
|
||
* };
|
||
*
|
||
* _.mapValues(users, function(o) { return o.age; });
|
||
* // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.mapValues(users, 'age');
|
||
* // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
|
||
*/
|
||
function mapValues(object, iteratee) {
|
||
var result = {};
|
||
iteratee = getIteratee(iteratee, 3);
|
||
|
||
baseForOwn(object, function(value, key, object) {
|
||
result[key] = iteratee(value, key, object);
|
||
});
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.assign` except that it recursively merges own and
|
||
* inherited enumerable string keyed properties of source objects into the
|
||
* destination object. Source properties that resolve to `undefined` are
|
||
* skipped if a destination value exists. Array and plain object properties
|
||
* are merged recursively.Other objects and value types are overridden by
|
||
* assignment. Source objects are applied from left to right. Subsequent
|
||
* sources overwrite property assignments of previous sources.
|
||
*
|
||
* **Note:** This method mutates `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.5.0
|
||
* @category Object
|
||
* @param {Object} object The destination object.
|
||
* @param {...Object} [sources] The source objects.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* var users = {
|
||
* 'data': [{ 'user': 'barney' }, { 'user': 'fred' }]
|
||
* };
|
||
*
|
||
* var ages = {
|
||
* 'data': [{ 'age': 36 }, { 'age': 40 }]
|
||
* };
|
||
*
|
||
* _.merge(users, ages);
|
||
* // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] }
|
||
*/
|
||
var merge = createAssigner(function(object, source, srcIndex) {
|
||
baseMerge(object, source, srcIndex);
|
||
});
|
||
|
||
/**
|
||
* This method is like `_.merge` except that it accepts `customizer` which
|
||
* is invoked to produce the merged values of the destination and source
|
||
* properties. If `customizer` returns `undefined`, merging is handled by the
|
||
* method instead. The `customizer` is invoked with seven arguments:
|
||
* (objValue, srcValue, key, object, source, stack).
|
||
*
|
||
* **Note:** This method mutates `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Object
|
||
* @param {Object} object The destination object.
|
||
* @param {...Object} sources The source objects.
|
||
* @param {Function} customizer The function to customize assigned values.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* function customizer(objValue, srcValue) {
|
||
* if (_.isArray(objValue)) {
|
||
* return objValue.concat(srcValue);
|
||
* }
|
||
* }
|
||
*
|
||
* var object = {
|
||
* 'fruits': ['apple'],
|
||
* 'vegetables': ['beet']
|
||
* };
|
||
*
|
||
* var other = {
|
||
* 'fruits': ['banana'],
|
||
* 'vegetables': ['carrot']
|
||
* };
|
||
*
|
||
* _.mergeWith(object, other, customizer);
|
||
* // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }
|
||
*/
|
||
var mergeWith = createAssigner(function(object, source, srcIndex, customizer) {
|
||
baseMerge(object, source, srcIndex, customizer);
|
||
});
|
||
|
||
/**
|
||
* The opposite of `_.pick`; this method creates an object composed of the
|
||
* own and inherited enumerable string keyed properties of `object` that are
|
||
* not omitted.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Object
|
||
* @param {Object} object The source object.
|
||
* @param {...(string|string[])} [props] The property identifiers to omit.
|
||
* @returns {Object} Returns the new object.
|
||
* @example
|
||
*
|
||
* var object = { 'a': 1, 'b': '2', 'c': 3 };
|
||
*
|
||
* _.omit(object, ['a', 'c']);
|
||
* // => { 'b': '2' }
|
||
*/
|
||
var omit = rest(function(object, props) {
|
||
if (object == null) {
|
||
return {};
|
||
}
|
||
props = arrayMap(baseFlatten(props, 1), toKey);
|
||
return basePick(object, baseDifference(getAllKeysIn(object), props));
|
||
});
|
||
|
||
/**
|
||
* The opposite of `_.pickBy`; this method creates an object composed of
|
||
* the own and inherited enumerable string keyed properties of `object` that
|
||
* `predicate` doesn't return truthy for. The predicate is invoked with two
|
||
* arguments: (value, key).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Object
|
||
* @param {Object} object The source object.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per property.
|
||
* @returns {Object} Returns the new object.
|
||
* @example
|
||
*
|
||
* var object = { 'a': 1, 'b': '2', 'c': 3 };
|
||
*
|
||
* _.omitBy(object, _.isNumber);
|
||
* // => { 'b': '2' }
|
||
*/
|
||
function omitBy(object, predicate) {
|
||
predicate = getIteratee(predicate);
|
||
return basePickBy(object, function(value, key) {
|
||
return !predicate(value, key);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Creates an object composed of the picked `object` properties.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Object
|
||
* @param {Object} object The source object.
|
||
* @param {...(string|string[])} [props] The property identifiers to pick.
|
||
* @returns {Object} Returns the new object.
|
||
* @example
|
||
*
|
||
* var object = { 'a': 1, 'b': '2', 'c': 3 };
|
||
*
|
||
* _.pick(object, ['a', 'c']);
|
||
* // => { 'a': 1, 'c': 3 }
|
||
*/
|
||
var pick = rest(function(object, props) {
|
||
return object == null ? {} : basePick(object, baseFlatten(props, 1));
|
||
});
|
||
|
||
/**
|
||
* Creates an object composed of the `object` properties `predicate` returns
|
||
* truthy for. The predicate is invoked with two arguments: (value, key).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Object
|
||
* @param {Object} object The source object.
|
||
* @param {Array|Function|Object|string} [predicate=_.identity]
|
||
* The function invoked per property.
|
||
* @returns {Object} Returns the new object.
|
||
* @example
|
||
*
|
||
* var object = { 'a': 1, 'b': '2', 'c': 3 };
|
||
*
|
||
* _.pickBy(object, _.isNumber);
|
||
* // => { 'a': 1, 'c': 3 }
|
||
*/
|
||
function pickBy(object, predicate) {
|
||
return object == null ? {} : basePickBy(object, getIteratee(predicate));
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.get` except that if the resolved value is a
|
||
* function it's invoked with the `this` binding of its parent object and
|
||
* its result is returned.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Object
|
||
* @param {Object} object The object to query.
|
||
* @param {Array|string} path The path of the property to resolve.
|
||
* @param {*} [defaultValue] The value returned for `undefined` resolved values.
|
||
* @returns {*} Returns the resolved value.
|
||
* @example
|
||
*
|
||
* var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };
|
||
*
|
||
* _.result(object, 'a[0].b.c1');
|
||
* // => 3
|
||
*
|
||
* _.result(object, 'a[0].b.c2');
|
||
* // => 4
|
||
*
|
||
* _.result(object, 'a[0].b.c3', 'default');
|
||
* // => 'default'
|
||
*
|
||
* _.result(object, 'a[0].b.c3', _.constant('default'));
|
||
* // => 'default'
|
||
*/
|
||
function result(object, path, defaultValue) {
|
||
path = isKey(path, object) ? [path] : castPath(path);
|
||
|
||
var index = -1,
|
||
length = path.length;
|
||
|
||
// Ensure the loop is entered when path is empty.
|
||
if (!length) {
|
||
object = undefined;
|
||
length = 1;
|
||
}
|
||
while (++index < length) {
|
||
var value = object == null ? undefined : object[path[index]];
|
||
if (value === undefined) {
|
||
index = length;
|
||
value = defaultValue;
|
||
}
|
||
object = isFunction(value) ? value.call(object) : value;
|
||
}
|
||
return object;
|
||
}
|
||
|
||
/**
|
||
* Sets the value at `path` of `object`. If a portion of `path` doesn't exist,
|
||
* it's created. Arrays are created for missing index properties while objects
|
||
* are created for all other missing properties. Use `_.setWith` to customize
|
||
* `path` creation.
|
||
*
|
||
* **Note:** This method mutates `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.7.0
|
||
* @category Object
|
||
* @param {Object} object The object to modify.
|
||
* @param {Array|string} path The path of the property to set.
|
||
* @param {*} value The value to set.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* var object = { 'a': [{ 'b': { 'c': 3 } }] };
|
||
*
|
||
* _.set(object, 'a[0].b.c', 4);
|
||
* console.log(object.a[0].b.c);
|
||
* // => 4
|
||
*
|
||
* _.set(object, ['x', '0', 'y', 'z'], 5);
|
||
* console.log(object.x[0].y.z);
|
||
* // => 5
|
||
*/
|
||
function set(object, path, value) {
|
||
return object == null ? object : baseSet(object, path, value);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.set` except that it accepts `customizer` which is
|
||
* invoked to produce the objects of `path`. If `customizer` returns `undefined`
|
||
* path creation is handled by the method instead. The `customizer` is invoked
|
||
* with three arguments: (nsValue, key, nsObject).
|
||
*
|
||
* **Note:** This method mutates `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Object
|
||
* @param {Object} object The object to modify.
|
||
* @param {Array|string} path The path of the property to set.
|
||
* @param {*} value The value to set.
|
||
* @param {Function} [customizer] The function to customize assigned values.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* var object = {};
|
||
*
|
||
* _.setWith(object, '[0][1]', 'a', Object);
|
||
* // => { '0': { '1': 'a' } }
|
||
*/
|
||
function setWith(object, path, value, customizer) {
|
||
customizer = typeof customizer == 'function' ? customizer : undefined;
|
||
return object == null ? object : baseSet(object, path, value, customizer);
|
||
}
|
||
|
||
/**
|
||
* Creates an array of own enumerable string keyed-value pairs for `object`
|
||
* which can be consumed by `_.fromPairs`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @alias entries
|
||
* @category Object
|
||
* @param {Object} object The object to query.
|
||
* @returns {Array} Returns the new array of key-value pairs.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.a = 1;
|
||
* this.b = 2;
|
||
* }
|
||
*
|
||
* Foo.prototype.c = 3;
|
||
*
|
||
* _.toPairs(new Foo);
|
||
* // => [['a', 1], ['b', 2]] (iteration order is not guaranteed)
|
||
*/
|
||
function toPairs(object) {
|
||
return baseToPairs(object, keys(object));
|
||
}
|
||
|
||
/**
|
||
* Creates an array of own and inherited enumerable string keyed-value pairs
|
||
* for `object` which can be consumed by `_.fromPairs`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @alias entriesIn
|
||
* @category Object
|
||
* @param {Object} object The object to query.
|
||
* @returns {Array} Returns the new array of key-value pairs.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.a = 1;
|
||
* this.b = 2;
|
||
* }
|
||
*
|
||
* Foo.prototype.c = 3;
|
||
*
|
||
* _.toPairsIn(new Foo);
|
||
* // => [['a', 1], ['b', 2], ['c', 1]] (iteration order is not guaranteed)
|
||
*/
|
||
function toPairsIn(object) {
|
||
return baseToPairs(object, keysIn(object));
|
||
}
|
||
|
||
/**
|
||
* An alternative to `_.reduce`; this method transforms `object` to a new
|
||
* `accumulator` object which is the result of running each of its own
|
||
* enumerable string keyed properties thru `iteratee`, with each invocation
|
||
* potentially mutating the `accumulator` object. The iteratee is invoked
|
||
* with four arguments: (accumulator, value, key, object). Iteratee functions
|
||
* may exit iteration early by explicitly returning `false`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 1.3.0
|
||
* @category Object
|
||
* @param {Array|Object} object The object to iterate over.
|
||
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
|
||
* @param {*} [accumulator] The custom accumulator value.
|
||
* @returns {*} Returns the accumulated value.
|
||
* @example
|
||
*
|
||
* _.transform([2, 3, 4], function(result, n) {
|
||
* result.push(n *= n);
|
||
* return n % 2 == 0;
|
||
* }, []);
|
||
* // => [4, 9]
|
||
*
|
||
* _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {
|
||
* (result[value] || (result[value] = [])).push(key);
|
||
* }, {});
|
||
* // => { '1': ['a', 'c'], '2': ['b'] }
|
||
*/
|
||
function transform(object, iteratee, accumulator) {
|
||
var isArr = isArray(object) || isTypedArray(object);
|
||
iteratee = getIteratee(iteratee, 4);
|
||
|
||
if (accumulator == null) {
|
||
if (isArr || isObject(object)) {
|
||
var Ctor = object.constructor;
|
||
if (isArr) {
|
||
accumulator = isArray(object) ? new Ctor : [];
|
||
} else {
|
||
accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {};
|
||
}
|
||
} else {
|
||
accumulator = {};
|
||
}
|
||
}
|
||
(isArr ? arrayEach : baseForOwn)(object, function(value, index, object) {
|
||
return iteratee(accumulator, value, index, object);
|
||
});
|
||
return accumulator;
|
||
}
|
||
|
||
/**
|
||
* Removes the property at `path` of `object`.
|
||
*
|
||
* **Note:** This method mutates `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Object
|
||
* @param {Object} object The object to modify.
|
||
* @param {Array|string} path The path of the property to unset.
|
||
* @returns {boolean} Returns `true` if the property is deleted, else `false`.
|
||
* @example
|
||
*
|
||
* var object = { 'a': [{ 'b': { 'c': 7 } }] };
|
||
* _.unset(object, 'a[0].b.c');
|
||
* // => true
|
||
*
|
||
* console.log(object);
|
||
* // => { 'a': [{ 'b': {} }] };
|
||
*
|
||
* _.unset(object, ['a', '0', 'b', 'c']);
|
||
* // => true
|
||
*
|
||
* console.log(object);
|
||
* // => { 'a': [{ 'b': {} }] };
|
||
*/
|
||
function unset(object, path) {
|
||
return object == null ? true : baseUnset(object, path);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.set` except that accepts `updater` to produce the
|
||
* value to set. Use `_.updateWith` to customize `path` creation. The `updater`
|
||
* is invoked with one argument: (value).
|
||
*
|
||
* **Note:** This method mutates `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.6.0
|
||
* @category Object
|
||
* @param {Object} object The object to modify.
|
||
* @param {Array|string} path The path of the property to set.
|
||
* @param {Function} updater The function to produce the updated value.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* var object = { 'a': [{ 'b': { 'c': 3 } }] };
|
||
*
|
||
* _.update(object, 'a[0].b.c', function(n) { return n * n; });
|
||
* console.log(object.a[0].b.c);
|
||
* // => 9
|
||
*
|
||
* _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; });
|
||
* console.log(object.x[0].y.z);
|
||
* // => 0
|
||
*/
|
||
function update(object, path, updater) {
|
||
return object == null ? object : baseUpdate(object, path, castFunction(updater));
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.update` except that it accepts `customizer` which is
|
||
* invoked to produce the objects of `path`. If `customizer` returns `undefined`
|
||
* path creation is handled by the method instead. The `customizer` is invoked
|
||
* with three arguments: (nsValue, key, nsObject).
|
||
*
|
||
* **Note:** This method mutates `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.6.0
|
||
* @category Object
|
||
* @param {Object} object The object to modify.
|
||
* @param {Array|string} path The path of the property to set.
|
||
* @param {Function} updater The function to produce the updated value.
|
||
* @param {Function} [customizer] The function to customize assigned values.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* var object = {};
|
||
*
|
||
* _.updateWith(object, '[0][1]', _.constant('a'), Object);
|
||
* // => { '0': { '1': 'a' } }
|
||
*/
|
||
function updateWith(object, path, updater, customizer) {
|
||
customizer = typeof customizer == 'function' ? customizer : undefined;
|
||
return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer);
|
||
}
|
||
|
||
/**
|
||
* Creates an array of the own enumerable string keyed property values of `object`.
|
||
*
|
||
* **Note:** Non-object values are coerced to objects.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Object
|
||
* @param {Object} object The object to query.
|
||
* @returns {Array} Returns the array of property values.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.a = 1;
|
||
* this.b = 2;
|
||
* }
|
||
*
|
||
* Foo.prototype.c = 3;
|
||
*
|
||
* _.values(new Foo);
|
||
* // => [1, 2] (iteration order is not guaranteed)
|
||
*
|
||
* _.values('hi');
|
||
* // => ['h', 'i']
|
||
*/
|
||
function values(object) {
|
||
return object ? baseValues(object, keys(object)) : [];
|
||
}
|
||
|
||
/**
|
||
* Creates an array of the own and inherited enumerable string keyed property
|
||
* values of `object`.
|
||
*
|
||
* **Note:** Non-object values are coerced to objects.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Object
|
||
* @param {Object} object The object to query.
|
||
* @returns {Array} Returns the array of property values.
|
||
* @example
|
||
*
|
||
* function Foo() {
|
||
* this.a = 1;
|
||
* this.b = 2;
|
||
* }
|
||
*
|
||
* Foo.prototype.c = 3;
|
||
*
|
||
* _.valuesIn(new Foo);
|
||
* // => [1, 2, 3] (iteration order is not guaranteed)
|
||
*/
|
||
function valuesIn(object) {
|
||
return object == null ? [] : baseValues(object, keysIn(object));
|
||
}
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Clamps `number` within the inclusive `lower` and `upper` bounds.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Number
|
||
* @param {number} number The number to clamp.
|
||
* @param {number} [lower] The lower bound.
|
||
* @param {number} upper The upper bound.
|
||
* @returns {number} Returns the clamped number.
|
||
* @example
|
||
*
|
||
* _.clamp(-10, -5, 5);
|
||
* // => -5
|
||
*
|
||
* _.clamp(10, -5, 5);
|
||
* // => 5
|
||
*/
|
||
function clamp(number, lower, upper) {
|
||
if (upper === undefined) {
|
||
upper = lower;
|
||
lower = undefined;
|
||
}
|
||
if (upper !== undefined) {
|
||
upper = toNumber(upper);
|
||
upper = upper === upper ? upper : 0;
|
||
}
|
||
if (lower !== undefined) {
|
||
lower = toNumber(lower);
|
||
lower = lower === lower ? lower : 0;
|
||
}
|
||
return baseClamp(toNumber(number), lower, upper);
|
||
}
|
||
|
||
/**
|
||
* Checks if `n` is between `start` and up to but not including, `end`. If
|
||
* `end` is not specified, it's set to `start` with `start` then set to `0`.
|
||
* If `start` is greater than `end` the params are swapped to support
|
||
* negative ranges.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.3.0
|
||
* @category Number
|
||
* @param {number} number The number to check.
|
||
* @param {number} [start=0] The start of the range.
|
||
* @param {number} end The end of the range.
|
||
* @returns {boolean} Returns `true` if `number` is in the range, else `false`.
|
||
* @example
|
||
*
|
||
* _.inRange(3, 2, 4);
|
||
* // => true
|
||
*
|
||
* _.inRange(4, 8);
|
||
* // => true
|
||
*
|
||
* _.inRange(4, 2);
|
||
* // => false
|
||
*
|
||
* _.inRange(2, 2);
|
||
* // => false
|
||
*
|
||
* _.inRange(1.2, 2);
|
||
* // => true
|
||
*
|
||
* _.inRange(5.2, 4);
|
||
* // => false
|
||
*
|
||
* _.inRange(-3, -2, -6);
|
||
* // => true
|
||
*/
|
||
function inRange(number, start, end) {
|
||
start = toNumber(start) || 0;
|
||
if (end === undefined) {
|
||
end = start;
|
||
start = 0;
|
||
} else {
|
||
end = toNumber(end) || 0;
|
||
}
|
||
number = toNumber(number);
|
||
return baseInRange(number, start, end);
|
||
}
|
||
|
||
/**
|
||
* Produces a random number between the inclusive `lower` and `upper` bounds.
|
||
* If only one argument is provided a number between `0` and the given number
|
||
* is returned. If `floating` is `true`, or either `lower` or `upper` are
|
||
* floats, a floating-point number is returned instead of an integer.
|
||
*
|
||
* **Note:** JavaScript follows the IEEE-754 standard for resolving
|
||
* floating-point values which can produce unexpected results.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.7.0
|
||
* @category Number
|
||
* @param {number} [lower=0] The lower bound.
|
||
* @param {number} [upper=1] The upper bound.
|
||
* @param {boolean} [floating] Specify returning a floating-point number.
|
||
* @returns {number} Returns the random number.
|
||
* @example
|
||
*
|
||
* _.random(0, 5);
|
||
* // => an integer between 0 and 5
|
||
*
|
||
* _.random(5);
|
||
* // => also an integer between 0 and 5
|
||
*
|
||
* _.random(5, true);
|
||
* // => a floating-point number between 0 and 5
|
||
*
|
||
* _.random(1.2, 5.2);
|
||
* // => a floating-point number between 1.2 and 5.2
|
||
*/
|
||
function random(lower, upper, floating) {
|
||
if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) {
|
||
upper = floating = undefined;
|
||
}
|
||
if (floating === undefined) {
|
||
if (typeof upper == 'boolean') {
|
||
floating = upper;
|
||
upper = undefined;
|
||
}
|
||
else if (typeof lower == 'boolean') {
|
||
floating = lower;
|
||
lower = undefined;
|
||
}
|
||
}
|
||
if (lower === undefined && upper === undefined) {
|
||
lower = 0;
|
||
upper = 1;
|
||
}
|
||
else {
|
||
lower = toNumber(lower) || 0;
|
||
if (upper === undefined) {
|
||
upper = lower;
|
||
lower = 0;
|
||
} else {
|
||
upper = toNumber(upper) || 0;
|
||
}
|
||
}
|
||
if (lower > upper) {
|
||
var temp = lower;
|
||
lower = upper;
|
||
upper = temp;
|
||
}
|
||
if (floating || lower % 1 || upper % 1) {
|
||
var rand = nativeRandom();
|
||
return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper);
|
||
}
|
||
return baseRandom(lower, upper);
|
||
}
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to convert.
|
||
* @returns {string} Returns the camel cased string.
|
||
* @example
|
||
*
|
||
* _.camelCase('Foo Bar');
|
||
* // => 'fooBar'
|
||
*
|
||
* _.camelCase('--foo-bar--');
|
||
* // => 'fooBar'
|
||
*
|
||
* _.camelCase('__FOO_BAR__');
|
||
* // => 'fooBar'
|
||
*/
|
||
var camelCase = createCompounder(function(result, word, index) {
|
||
word = word.toLowerCase();
|
||
return result + (index ? capitalize(word) : word);
|
||
});
|
||
|
||
/**
|
||
* Converts the first character of `string` to upper case and the remaining
|
||
* to lower case.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to capitalize.
|
||
* @returns {string} Returns the capitalized string.
|
||
* @example
|
||
*
|
||
* _.capitalize('FRED');
|
||
* // => 'Fred'
|
||
*/
|
||
function capitalize(string) {
|
||
return upperFirst(toString(string).toLowerCase());
|
||
}
|
||
|
||
/**
|
||
* Deburrs `string` by converting
|
||
* [latin-1 supplementary letters](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)
|
||
* to basic latin letters and removing
|
||
* [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to deburr.
|
||
* @returns {string} Returns the deburred string.
|
||
* @example
|
||
*
|
||
* _.deburr('déjà vu');
|
||
* // => 'deja vu'
|
||
*/
|
||
function deburr(string) {
|
||
string = toString(string);
|
||
return string && string.replace(reLatin1, deburrLetter).replace(reComboMark, '');
|
||
}
|
||
|
||
/**
|
||
* Checks if `string` ends with the given target string.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to search.
|
||
* @param {string} [target] The string to search for.
|
||
* @param {number} [position=string.length] The position to search from.
|
||
* @returns {boolean} Returns `true` if `string` ends with `target`,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.endsWith('abc', 'c');
|
||
* // => true
|
||
*
|
||
* _.endsWith('abc', 'b');
|
||
* // => false
|
||
*
|
||
* _.endsWith('abc', 'b', 2);
|
||
* // => true
|
||
*/
|
||
function endsWith(string, target, position) {
|
||
string = toString(string);
|
||
target = typeof target == 'string' ? target : (target + '');
|
||
|
||
var length = string.length;
|
||
position = position === undefined
|
||
? length
|
||
: baseClamp(toInteger(position), 0, length);
|
||
|
||
position -= target.length;
|
||
return position >= 0 && string.indexOf(target, position) == position;
|
||
}
|
||
|
||
/**
|
||
* Converts the characters "&", "<", ">", '"', "'", and "\`" in `string` to
|
||
* their corresponding HTML entities.
|
||
*
|
||
* **Note:** No other characters are escaped. To escape additional
|
||
* characters use a third-party library like [_he_](https://mths.be/he).
|
||
*
|
||
* Though the ">" character is escaped for symmetry, characters like
|
||
* ">" and "/" don't need escaping in HTML and have no special meaning
|
||
* unless they're part of a tag or unquoted attribute value. See
|
||
* [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands)
|
||
* (under "semi-related fun fact") for more details.
|
||
*
|
||
* Backticks are escaped because in IE < 9, they can break out of
|
||
* attribute values or HTML comments. See [#59](https://html5sec.org/#59),
|
||
* [#102](https://html5sec.org/#102), [#108](https://html5sec.org/#108), and
|
||
* [#133](https://html5sec.org/#133) of the
|
||
* [HTML5 Security Cheatsheet](https://html5sec.org/) for more details.
|
||
*
|
||
* When working with HTML you should always
|
||
* [quote attribute values](http://wonko.com/post/html-escaping) to reduce
|
||
* XSS vectors.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category String
|
||
* @param {string} [string=''] The string to escape.
|
||
* @returns {string} Returns the escaped string.
|
||
* @example
|
||
*
|
||
* _.escape('fred, barney, & pebbles');
|
||
* // => 'fred, barney, & pebbles'
|
||
*/
|
||
function escape(string) {
|
||
string = toString(string);
|
||
return (string && reHasUnescapedHtml.test(string))
|
||
? string.replace(reUnescapedHtml, escapeHtmlChar)
|
||
: string;
|
||
}
|
||
|
||
/**
|
||
* Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+",
|
||
* "?", "(", ")", "[", "]", "{", "}", and "|" in `string`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to escape.
|
||
* @returns {string} Returns the escaped string.
|
||
* @example
|
||
*
|
||
* _.escapeRegExp('[lodash](https://lodash.com/)');
|
||
* // => '\[lodash\]\(https://lodash\.com/\)'
|
||
*/
|
||
function escapeRegExp(string) {
|
||
string = toString(string);
|
||
return (string && reHasRegExpChar.test(string))
|
||
? string.replace(reRegExpChar, '\\$&')
|
||
: string;
|
||
}
|
||
|
||
/**
|
||
* Converts `string` to
|
||
* [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to convert.
|
||
* @returns {string} Returns the kebab cased string.
|
||
* @example
|
||
*
|
||
* _.kebabCase('Foo Bar');
|
||
* // => 'foo-bar'
|
||
*
|
||
* _.kebabCase('fooBar');
|
||
* // => 'foo-bar'
|
||
*
|
||
* _.kebabCase('__FOO_BAR__');
|
||
* // => 'foo-bar'
|
||
*/
|
||
var kebabCase = createCompounder(function(result, word, index) {
|
||
return result + (index ? '-' : '') + word.toLowerCase();
|
||
});
|
||
|
||
/**
|
||
* Converts `string`, as space separated words, to lower case.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to convert.
|
||
* @returns {string} Returns the lower cased string.
|
||
* @example
|
||
*
|
||
* _.lowerCase('--Foo-Bar--');
|
||
* // => 'foo bar'
|
||
*
|
||
* _.lowerCase('fooBar');
|
||
* // => 'foo bar'
|
||
*
|
||
* _.lowerCase('__FOO_BAR__');
|
||
* // => 'foo bar'
|
||
*/
|
||
var lowerCase = createCompounder(function(result, word, index) {
|
||
return result + (index ? ' ' : '') + word.toLowerCase();
|
||
});
|
||
|
||
/**
|
||
* Converts the first character of `string` to lower case.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to convert.
|
||
* @returns {string} Returns the converted string.
|
||
* @example
|
||
*
|
||
* _.lowerFirst('Fred');
|
||
* // => 'fred'
|
||
*
|
||
* _.lowerFirst('FRED');
|
||
* // => 'fRED'
|
||
*/
|
||
var lowerFirst = createCaseFirst('toLowerCase');
|
||
|
||
/**
|
||
* Pads `string` on the left and right sides if it's shorter than `length`.
|
||
* Padding characters are truncated if they can't be evenly divided by `length`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to pad.
|
||
* @param {number} [length=0] The padding length.
|
||
* @param {string} [chars=' '] The string used as padding.
|
||
* @returns {string} Returns the padded string.
|
||
* @example
|
||
*
|
||
* _.pad('abc', 8);
|
||
* // => ' abc '
|
||
*
|
||
* _.pad('abc', 8, '_-');
|
||
* // => '_-abc_-_'
|
||
*
|
||
* _.pad('abc', 3);
|
||
* // => 'abc'
|
||
*/
|
||
function pad(string, length, chars) {
|
||
string = toString(string);
|
||
length = toInteger(length);
|
||
|
||
var strLength = length ? stringSize(string) : 0;
|
||
if (!length || strLength >= length) {
|
||
return string;
|
||
}
|
||
var mid = (length - strLength) / 2;
|
||
return (
|
||
createPadding(nativeFloor(mid), chars) +
|
||
string +
|
||
createPadding(nativeCeil(mid), chars)
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Pads `string` on the right side if it's shorter than `length`. Padding
|
||
* characters are truncated if they exceed `length`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to pad.
|
||
* @param {number} [length=0] The padding length.
|
||
* @param {string} [chars=' '] The string used as padding.
|
||
* @returns {string} Returns the padded string.
|
||
* @example
|
||
*
|
||
* _.padEnd('abc', 6);
|
||
* // => 'abc '
|
||
*
|
||
* _.padEnd('abc', 6, '_-');
|
||
* // => 'abc_-_'
|
||
*
|
||
* _.padEnd('abc', 3);
|
||
* // => 'abc'
|
||
*/
|
||
function padEnd(string, length, chars) {
|
||
string = toString(string);
|
||
length = toInteger(length);
|
||
|
||
var strLength = length ? stringSize(string) : 0;
|
||
return (length && strLength < length)
|
||
? (string + createPadding(length - strLength, chars))
|
||
: string;
|
||
}
|
||
|
||
/**
|
||
* Pads `string` on the left side if it's shorter than `length`. Padding
|
||
* characters are truncated if they exceed `length`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to pad.
|
||
* @param {number} [length=0] The padding length.
|
||
* @param {string} [chars=' '] The string used as padding.
|
||
* @returns {string} Returns the padded string.
|
||
* @example
|
||
*
|
||
* _.padStart('abc', 6);
|
||
* // => ' abc'
|
||
*
|
||
* _.padStart('abc', 6, '_-');
|
||
* // => '_-_abc'
|
||
*
|
||
* _.padStart('abc', 3);
|
||
* // => 'abc'
|
||
*/
|
||
function padStart(string, length, chars) {
|
||
string = toString(string);
|
||
length = toInteger(length);
|
||
|
||
var strLength = length ? stringSize(string) : 0;
|
||
return (length && strLength < length)
|
||
? (createPadding(length - strLength, chars) + string)
|
||
: string;
|
||
}
|
||
|
||
/**
|
||
* Converts `string` to an integer of the specified radix. If `radix` is
|
||
* `undefined` or `0`, a `radix` of `10` is used unless `value` is a
|
||
* hexadecimal, in which case a `radix` of `16` is used.
|
||
*
|
||
* **Note:** This method aligns with the
|
||
* [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 1.1.0
|
||
* @category String
|
||
* @param {string} string The string to convert.
|
||
* @param {number} [radix=10] The radix to interpret `value` by.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {number} Returns the converted integer.
|
||
* @example
|
||
*
|
||
* _.parseInt('08');
|
||
* // => 8
|
||
*
|
||
* _.map(['6', '08', '10'], _.parseInt);
|
||
* // => [6, 8, 10]
|
||
*/
|
||
function parseInt(string, radix, guard) {
|
||
// Chrome fails to trim leading <BOM> whitespace characters.
|
||
// See https://bugs.chromium.org/p/v8/issues/detail?id=3109 for more details.
|
||
if (guard || radix == null) {
|
||
radix = 0;
|
||
} else if (radix) {
|
||
radix = +radix;
|
||
}
|
||
string = toString(string).replace(reTrim, '');
|
||
return nativeParseInt(string, radix || (reHasHexPrefix.test(string) ? 16 : 10));
|
||
}
|
||
|
||
/**
|
||
* Repeats the given string `n` times.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to repeat.
|
||
* @param {number} [n=1] The number of times to repeat the string.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {string} Returns the repeated string.
|
||
* @example
|
||
*
|
||
* _.repeat('*', 3);
|
||
* // => '***'
|
||
*
|
||
* _.repeat('abc', 2);
|
||
* // => 'abcabc'
|
||
*
|
||
* _.repeat('abc', 0);
|
||
* // => ''
|
||
*/
|
||
function repeat(string, n, guard) {
|
||
if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) {
|
||
n = 1;
|
||
} else {
|
||
n = toInteger(n);
|
||
}
|
||
return baseRepeat(toString(string), n);
|
||
}
|
||
|
||
/**
|
||
* Replaces matches for `pattern` in `string` with `replacement`.
|
||
*
|
||
* **Note:** This method is based on
|
||
* [`String#replace`](https://mdn.io/String/replace).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to modify.
|
||
* @param {RegExp|string} pattern The pattern to replace.
|
||
* @param {Function|string} replacement The match replacement.
|
||
* @returns {string} Returns the modified string.
|
||
* @example
|
||
*
|
||
* _.replace('Hi Fred', 'Fred', 'Barney');
|
||
* // => 'Hi Barney'
|
||
*/
|
||
function replace() {
|
||
var args = arguments,
|
||
string = toString(args[0]);
|
||
|
||
return args.length < 3 ? string : nativeReplace.call(string, args[1], args[2]);
|
||
}
|
||
|
||
/**
|
||
* Converts `string` to
|
||
* [snake case](https://en.wikipedia.org/wiki/Snake_case).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to convert.
|
||
* @returns {string} Returns the snake cased string.
|
||
* @example
|
||
*
|
||
* _.snakeCase('Foo Bar');
|
||
* // => 'foo_bar'
|
||
*
|
||
* _.snakeCase('fooBar');
|
||
* // => 'foo_bar'
|
||
*
|
||
* _.snakeCase('--FOO-BAR--');
|
||
* // => 'foo_bar'
|
||
*/
|
||
var snakeCase = createCompounder(function(result, word, index) {
|
||
return result + (index ? '_' : '') + word.toLowerCase();
|
||
});
|
||
|
||
/**
|
||
* Splits `string` by `separator`.
|
||
*
|
||
* **Note:** This method is based on
|
||
* [`String#split`](https://mdn.io/String/split).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to split.
|
||
* @param {RegExp|string} separator The separator pattern to split by.
|
||
* @param {number} [limit] The length to truncate results to.
|
||
* @returns {Array} Returns the new array of string segments.
|
||
* @example
|
||
*
|
||
* _.split('a-b-c', '-', 2);
|
||
* // => ['a', 'b']
|
||
*/
|
||
function split(string, separator, limit) {
|
||
if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) {
|
||
separator = limit = undefined;
|
||
}
|
||
limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0;
|
||
if (!limit) {
|
||
return [];
|
||
}
|
||
string = toString(string);
|
||
if (string && (
|
||
typeof separator == 'string' ||
|
||
(separator != null && !isRegExp(separator))
|
||
)) {
|
||
separator += '';
|
||
if (separator == '' && reHasComplexSymbol.test(string)) {
|
||
return castSlice(stringToArray(string), 0, limit);
|
||
}
|
||
}
|
||
return nativeSplit.call(string, separator, limit);
|
||
}
|
||
|
||
/**
|
||
* Converts `string` to
|
||
* [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.1.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to convert.
|
||
* @returns {string} Returns the start cased string.
|
||
* @example
|
||
*
|
||
* _.startCase('--foo-bar--');
|
||
* // => 'Foo Bar'
|
||
*
|
||
* _.startCase('fooBar');
|
||
* // => 'Foo Bar'
|
||
*
|
||
* _.startCase('__FOO_BAR__');
|
||
* // => 'FOO BAR'
|
||
*/
|
||
var startCase = createCompounder(function(result, word, index) {
|
||
return result + (index ? ' ' : '') + upperFirst(word);
|
||
});
|
||
|
||
/**
|
||
* Checks if `string` starts with the given target string.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to search.
|
||
* @param {string} [target] The string to search for.
|
||
* @param {number} [position=0] The position to search from.
|
||
* @returns {boolean} Returns `true` if `string` starts with `target`,
|
||
* else `false`.
|
||
* @example
|
||
*
|
||
* _.startsWith('abc', 'a');
|
||
* // => true
|
||
*
|
||
* _.startsWith('abc', 'b');
|
||
* // => false
|
||
*
|
||
* _.startsWith('abc', 'b', 1);
|
||
* // => true
|
||
*/
|
||
function startsWith(string, target, position) {
|
||
string = toString(string);
|
||
position = baseClamp(toInteger(position), 0, string.length);
|
||
return string.lastIndexOf(target, position) == position;
|
||
}
|
||
|
||
/**
|
||
* Creates a compiled template function that can interpolate data properties
|
||
* in "interpolate" delimiters, HTML-escape interpolated data properties in
|
||
* "escape" delimiters, and execute JavaScript in "evaluate" delimiters. Data
|
||
* properties may be accessed as free variables in the template. If a setting
|
||
* object is given, it takes precedence over `_.templateSettings` values.
|
||
*
|
||
* **Note:** In the development build `_.template` utilizes
|
||
* [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)
|
||
* for easier debugging.
|
||
*
|
||
* For more information on precompiling templates see
|
||
* [lodash's custom builds documentation](https://lodash.com/custom-builds).
|
||
*
|
||
* For more information on Chrome extension sandboxes see
|
||
* [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category String
|
||
* @param {string} [string=''] The template string.
|
||
* @param {Object} [options={}] The options object.
|
||
* @param {RegExp} [options.escape=_.templateSettings.escape]
|
||
* The HTML "escape" delimiter.
|
||
* @param {RegExp} [options.evaluate=_.templateSettings.evaluate]
|
||
* The "evaluate" delimiter.
|
||
* @param {Object} [options.imports=_.templateSettings.imports]
|
||
* An object to import into the template as free variables.
|
||
* @param {RegExp} [options.interpolate=_.templateSettings.interpolate]
|
||
* The "interpolate" delimiter.
|
||
* @param {string} [options.sourceURL='lodash.templateSources[n]']
|
||
* The sourceURL of the compiled template.
|
||
* @param {string} [options.variable='obj']
|
||
* The data object variable name.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {Function} Returns the compiled template function.
|
||
* @example
|
||
*
|
||
* // Use the "interpolate" delimiter to create a compiled template.
|
||
* var compiled = _.template('hello <%= user %>!');
|
||
* compiled({ 'user': 'fred' });
|
||
* // => 'hello fred!'
|
||
*
|
||
* // Use the HTML "escape" delimiter to escape data property values.
|
||
* var compiled = _.template('<b><%- value %></b>');
|
||
* compiled({ 'value': '<script>' });
|
||
* // => '<b><script></b>'
|
||
*
|
||
* // Use the "evaluate" delimiter to execute JavaScript and generate HTML.
|
||
* var compiled = _.template('<% _.forEach(users, function(user) { %><li><%- user %></li><% }); %>');
|
||
* compiled({ 'users': ['fred', 'barney'] });
|
||
* // => '<li>fred</li><li>barney</li>'
|
||
*
|
||
* // Use the internal `print` function in "evaluate" delimiters.
|
||
* var compiled = _.template('<% print("hello " + user); %>!');
|
||
* compiled({ 'user': 'barney' });
|
||
* // => 'hello barney!'
|
||
*
|
||
* // Use the ES delimiter as an alternative to the default "interpolate" delimiter.
|
||
* var compiled = _.template('hello ${ user }!');
|
||
* compiled({ 'user': 'pebbles' });
|
||
* // => 'hello pebbles!'
|
||
*
|
||
* // Use custom template delimiters.
|
||
* _.templateSettings.interpolate = /{{([\s\S]+?)}}/g;
|
||
* var compiled = _.template('hello {{ user }}!');
|
||
* compiled({ 'user': 'mustache' });
|
||
* // => 'hello mustache!'
|
||
*
|
||
* // Use backslashes to treat delimiters as plain text.
|
||
* var compiled = _.template('<%= "\\<%- value %\\>" %>');
|
||
* compiled({ 'value': 'ignored' });
|
||
* // => '<%- value %>'
|
||
*
|
||
* // Use the `imports` option to import `jQuery` as `jq`.
|
||
* var text = '<% jq.each(users, function(user) { %><li><%- user %></li><% }); %>';
|
||
* var compiled = _.template(text, { 'imports': { 'jq': jQuery } });
|
||
* compiled({ 'users': ['fred', 'barney'] });
|
||
* // => '<li>fred</li><li>barney</li>'
|
||
*
|
||
* // Use the `sourceURL` option to specify a custom sourceURL for the template.
|
||
* var compiled = _.template('hello <%= user %>!', { 'sourceURL': '/basic/greeting.jst' });
|
||
* compiled(data);
|
||
* // => Find the source of "greeting.jst" under the Sources tab or Resources panel of the web inspector.
|
||
*
|
||
* // Use the `variable` option to ensure a with-statement isn't used in the compiled template.
|
||
* var compiled = _.template('hi <%= data.user %>!', { 'variable': 'data' });
|
||
* compiled.source;
|
||
* // => function(data) {
|
||
* // var __t, __p = '';
|
||
* // __p += 'hi ' + ((__t = ( data.user )) == null ? '' : __t) + '!';
|
||
* // return __p;
|
||
* // }
|
||
*
|
||
* // Use the `source` property to inline compiled templates for meaningful
|
||
* // line numbers in error messages and stack traces.
|
||
* fs.writeFileSync(path.join(cwd, 'jst.js'), '\
|
||
* var JST = {\
|
||
* "main": ' + _.template(mainText).source + '\
|
||
* };\
|
||
* ');
|
||
*/
|
||
function template(string, options, guard) {
|
||
// 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;
|
||
|
||
if (guard && isIterateeCall(string, options, guard)) {
|
||
options = undefined;
|
||
}
|
||
string = toString(string);
|
||
options = assignInWith({}, options, settings, assignInDefaults);
|
||
|
||
var imports = assignInWith({}, options.imports, settings.imports, assignInDefaults),
|
||
importsKeys = keys(imports),
|
||
importsValues = baseValues(imports, importsKeys);
|
||
|
||
var isEscaping,
|
||
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');
|
||
|
||
// Use a sourceURL for easier debugging.
|
||
var sourceURL = '//# sourceURL=' +
|
||
('sourceURL' in options
|
||
? options.sourceURL
|
||
: ('lodash.templateSources[' + (++templateCounter) + ']')
|
||
) + '\n';
|
||
|
||
string.replace(reDelimiters, function(match, escapeValue, interpolateValue, esTemplateValue, evaluateValue, offset) {
|
||
interpolateValue || (interpolateValue = esTemplateValue);
|
||
|
||
// Escape characters that can't be included in string literals.
|
||
source += string.slice(index, offset).replace(reUnescapedString, escapeStringChar);
|
||
|
||
// Replace delimiters with snippets.
|
||
if (escapeValue) {
|
||
isEscaping = true;
|
||
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 needs `match` returned 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;
|
||
if (!variable) {
|
||
source = 'with (obj) {\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 || 'obj') + ') {\n' +
|
||
(variable
|
||
? ''
|
||
: 'obj || (obj = {});\n'
|
||
) +
|
||
"var __t, __p = ''" +
|
||
(isEscaping
|
||
? ', __e = _.escape'
|
||
: ''
|
||
) +
|
||
(isEvaluating
|
||
? ', __j = Array.prototype.join;\n' +
|
||
"function print() { __p += __j.call(arguments, '') }\n"
|
||
: ';\n'
|
||
) +
|
||
source +
|
||
'return __p\n}';
|
||
|
||
var result = attempt(function() {
|
||
return Function(importsKeys, sourceURL + 'return ' + source)
|
||
.apply(undefined, importsValues);
|
||
});
|
||
|
||
// Provide the compiled function's source by its `toString` method or
|
||
// the `source` property as a convenience for inlining compiled templates.
|
||
result.source = source;
|
||
if (isError(result)) {
|
||
throw result;
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Converts `string`, as a whole, to lower case just like
|
||
* [String#toLowerCase](https://mdn.io/toLowerCase).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to convert.
|
||
* @returns {string} Returns the lower cased string.
|
||
* @example
|
||
*
|
||
* _.toLower('--Foo-Bar--');
|
||
* // => '--foo-bar--'
|
||
*
|
||
* _.toLower('fooBar');
|
||
* // => 'foobar'
|
||
*
|
||
* _.toLower('__FOO_BAR__');
|
||
* // => '__foo_bar__'
|
||
*/
|
||
function toLower(value) {
|
||
return toString(value).toLowerCase();
|
||
}
|
||
|
||
/**
|
||
* Converts `string`, as a whole, to upper case just like
|
||
* [String#toUpperCase](https://mdn.io/toUpperCase).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to convert.
|
||
* @returns {string} Returns the upper cased string.
|
||
* @example
|
||
*
|
||
* _.toUpper('--foo-bar--');
|
||
* // => '--FOO-BAR--'
|
||
*
|
||
* _.toUpper('fooBar');
|
||
* // => 'FOOBAR'
|
||
*
|
||
* _.toUpper('__foo_bar__');
|
||
* // => '__FOO_BAR__'
|
||
*/
|
||
function toUpper(value) {
|
||
return toString(value).toUpperCase();
|
||
}
|
||
|
||
/**
|
||
* Removes leading and trailing whitespace or specified characters from `string`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to trim.
|
||
* @param {string} [chars=whitespace] The characters to trim.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {string} Returns the trimmed string.
|
||
* @example
|
||
*
|
||
* _.trim(' abc ');
|
||
* // => 'abc'
|
||
*
|
||
* _.trim('-_-abc-_-', '_-');
|
||
* // => 'abc'
|
||
*
|
||
* _.map([' foo ', ' bar '], _.trim);
|
||
* // => ['foo', 'bar']
|
||
*/
|
||
function trim(string, chars, guard) {
|
||
string = toString(string);
|
||
if (!string) {
|
||
return string;
|
||
}
|
||
if (guard || chars === undefined) {
|
||
return string.replace(reTrim, '');
|
||
}
|
||
if (!(chars += '')) {
|
||
return string;
|
||
}
|
||
var strSymbols = stringToArray(string),
|
||
chrSymbols = stringToArray(chars),
|
||
start = charsStartIndex(strSymbols, chrSymbols),
|
||
end = charsEndIndex(strSymbols, chrSymbols) + 1;
|
||
|
||
return castSlice(strSymbols, start, end).join('');
|
||
}
|
||
|
||
/**
|
||
* Removes trailing whitespace or specified characters from `string`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to trim.
|
||
* @param {string} [chars=whitespace] The characters to trim.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {string} Returns the trimmed string.
|
||
* @example
|
||
*
|
||
* _.trimEnd(' abc ');
|
||
* // => ' abc'
|
||
*
|
||
* _.trimEnd('-_-abc-_-', '_-');
|
||
* // => '-_-abc'
|
||
*/
|
||
function trimEnd(string, chars, guard) {
|
||
string = toString(string);
|
||
if (!string) {
|
||
return string;
|
||
}
|
||
if (guard || chars === undefined) {
|
||
return string.replace(reTrimEnd, '');
|
||
}
|
||
if (!(chars += '')) {
|
||
return string;
|
||
}
|
||
var strSymbols = stringToArray(string),
|
||
end = charsEndIndex(strSymbols, stringToArray(chars)) + 1;
|
||
|
||
return castSlice(strSymbols, 0, end).join('');
|
||
}
|
||
|
||
/**
|
||
* Removes leading whitespace or specified characters from `string`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to trim.
|
||
* @param {string} [chars=whitespace] The characters to trim.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {string} Returns the trimmed string.
|
||
* @example
|
||
*
|
||
* _.trimStart(' abc ');
|
||
* // => 'abc '
|
||
*
|
||
* _.trimStart('-_-abc-_-', '_-');
|
||
* // => 'abc-_-'
|
||
*/
|
||
function trimStart(string, chars, guard) {
|
||
string = toString(string);
|
||
if (!string) {
|
||
return string;
|
||
}
|
||
if (guard || chars === undefined) {
|
||
return string.replace(reTrimStart, '');
|
||
}
|
||
if (!(chars += '')) {
|
||
return string;
|
||
}
|
||
var strSymbols = stringToArray(string),
|
||
start = charsStartIndex(strSymbols, stringToArray(chars));
|
||
|
||
return castSlice(strSymbols, start).join('');
|
||
}
|
||
|
||
/**
|
||
* Truncates `string` if it's longer than the given maximum string length.
|
||
* The last characters of the truncated string are replaced with the omission
|
||
* string which defaults to "...".
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to truncate.
|
||
* @param {Object} [options={}] The options object.
|
||
* @param {number} [options.length=30] The maximum string length.
|
||
* @param {string} [options.omission='...'] The string to indicate text is omitted.
|
||
* @param {RegExp|string} [options.separator] The separator pattern to truncate to.
|
||
* @returns {string} Returns the truncated string.
|
||
* @example
|
||
*
|
||
* _.truncate('hi-diddly-ho there, neighborino');
|
||
* // => 'hi-diddly-ho there, neighbo...'
|
||
*
|
||
* _.truncate('hi-diddly-ho there, neighborino', {
|
||
* 'length': 24,
|
||
* 'separator': ' '
|
||
* });
|
||
* // => 'hi-diddly-ho there,...'
|
||
*
|
||
* _.truncate('hi-diddly-ho there, neighborino', {
|
||
* 'length': 24,
|
||
* 'separator': /,? +/
|
||
* });
|
||
* // => 'hi-diddly-ho there...'
|
||
*
|
||
* _.truncate('hi-diddly-ho there, neighborino', {
|
||
* 'omission': ' [...]'
|
||
* });
|
||
* // => 'hi-diddly-ho there, neig [...]'
|
||
*/
|
||
function truncate(string, options) {
|
||
var length = DEFAULT_TRUNC_LENGTH,
|
||
omission = DEFAULT_TRUNC_OMISSION;
|
||
|
||
if (isObject(options)) {
|
||
var separator = 'separator' in options ? options.separator : separator;
|
||
length = 'length' in options ? toInteger(options.length) : length;
|
||
omission = 'omission' in options ? toString(options.omission) : omission;
|
||
}
|
||
string = toString(string);
|
||
|
||
var strLength = string.length;
|
||
if (reHasComplexSymbol.test(string)) {
|
||
var strSymbols = stringToArray(string);
|
||
strLength = strSymbols.length;
|
||
}
|
||
if (length >= strLength) {
|
||
return string;
|
||
}
|
||
var end = length - stringSize(omission);
|
||
if (end < 1) {
|
||
return omission;
|
||
}
|
||
var result = strSymbols
|
||
? castSlice(strSymbols, 0, end).join('')
|
||
: string.slice(0, end);
|
||
|
||
if (separator === undefined) {
|
||
return result + omission;
|
||
}
|
||
if (strSymbols) {
|
||
end += (result.length - end);
|
||
}
|
||
if (isRegExp(separator)) {
|
||
if (string.slice(end).search(separator)) {
|
||
var match,
|
||
substring = result;
|
||
|
||
if (!separator.global) {
|
||
separator = RegExp(separator.source, toString(reFlags.exec(separator)) + 'g');
|
||
}
|
||
separator.lastIndex = 0;
|
||
while ((match = separator.exec(substring))) {
|
||
var newEnd = match.index;
|
||
}
|
||
result = result.slice(0, newEnd === undefined ? end : newEnd);
|
||
}
|
||
} else if (string.indexOf(separator, end) != end) {
|
||
var index = result.lastIndexOf(separator);
|
||
if (index > -1) {
|
||
result = result.slice(0, index);
|
||
}
|
||
}
|
||
return result + omission;
|
||
}
|
||
|
||
/**
|
||
* The inverse of `_.escape`; this method converts the HTML entities
|
||
* `&`, `<`, `>`, `"`, `'`, and ``` in `string` to
|
||
* their corresponding characters.
|
||
*
|
||
* **Note:** No other HTML entities are unescaped. To unescape additional
|
||
* HTML entities use a third-party library like [_he_](https://mths.be/he).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 0.6.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to unescape.
|
||
* @returns {string} Returns the unescaped string.
|
||
* @example
|
||
*
|
||
* _.unescape('fred, barney, & pebbles');
|
||
* // => 'fred, barney, & pebbles'
|
||
*/
|
||
function unescape(string) {
|
||
string = toString(string);
|
||
return (string && reHasEscapedHtml.test(string))
|
||
? string.replace(reEscapedHtml, unescapeHtmlChar)
|
||
: string;
|
||
}
|
||
|
||
/**
|
||
* Converts `string`, as space separated words, to upper case.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to convert.
|
||
* @returns {string} Returns the upper cased string.
|
||
* @example
|
||
*
|
||
* _.upperCase('--foo-bar');
|
||
* // => 'FOO BAR'
|
||
*
|
||
* _.upperCase('fooBar');
|
||
* // => 'FOO BAR'
|
||
*
|
||
* _.upperCase('__foo_bar__');
|
||
* // => 'FOO BAR'
|
||
*/
|
||
var upperCase = createCompounder(function(result, word, index) {
|
||
return result + (index ? ' ' : '') + word.toUpperCase();
|
||
});
|
||
|
||
/**
|
||
* Converts the first character of `string` to upper case.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to convert.
|
||
* @returns {string} Returns the converted string.
|
||
* @example
|
||
*
|
||
* _.upperFirst('fred');
|
||
* // => 'Fred'
|
||
*
|
||
* _.upperFirst('FRED');
|
||
* // => 'FRED'
|
||
*/
|
||
var upperFirst = createCaseFirst('toUpperCase');
|
||
|
||
/**
|
||
* Splits `string` into an array of its words.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category String
|
||
* @param {string} [string=''] The string to inspect.
|
||
* @param {RegExp|string} [pattern] The pattern to match words.
|
||
* @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.
|
||
* @returns {Array} Returns the words of `string`.
|
||
* @example
|
||
*
|
||
* _.words('fred, barney, & pebbles');
|
||
* // => ['fred', 'barney', 'pebbles']
|
||
*
|
||
* _.words('fred, barney, & pebbles', /[^, ]+/g);
|
||
* // => ['fred', 'barney', '&', 'pebbles']
|
||
*/
|
||
function words(string, pattern, guard) {
|
||
string = toString(string);
|
||
pattern = guard ? undefined : pattern;
|
||
|
||
if (pattern === undefined) {
|
||
pattern = reHasComplexWord.test(string) ? reComplexWord : reBasicWord;
|
||
}
|
||
return string.match(pattern) || [];
|
||
}
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Attempts to invoke `func`, returning either the result or the caught error
|
||
* object. Any additional arguments are provided to `func` when it's invoked.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Util
|
||
* @param {Function} func The function to attempt.
|
||
* @param {...*} [args] The arguments to invoke `func` with.
|
||
* @returns {*} Returns the `func` result or error object.
|
||
* @example
|
||
*
|
||
* // Avoid throwing errors for invalid selectors.
|
||
* var elements = _.attempt(function(selector) {
|
||
* return document.querySelectorAll(selector);
|
||
* }, '>_>');
|
||
*
|
||
* if (_.isError(elements)) {
|
||
* elements = [];
|
||
* }
|
||
*/
|
||
var attempt = rest(function(func, args) {
|
||
try {
|
||
return apply(func, undefined, args);
|
||
} catch (e) {
|
||
return isError(e) ? e : new Error(e);
|
||
}
|
||
});
|
||
|
||
/**
|
||
* Binds methods of an object to the object itself, overwriting the existing
|
||
* method.
|
||
*
|
||
* **Note:** This method doesn't set the "length" property of bound functions.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Util
|
||
* @param {Object} object The object to bind and assign the bound methods to.
|
||
* @param {...(string|string[])} methodNames The object method names to bind.
|
||
* @returns {Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* var view = {
|
||
* 'label': 'docs',
|
||
* 'onClick': function() {
|
||
* console.log('clicked ' + this.label);
|
||
* }
|
||
* };
|
||
*
|
||
* _.bindAll(view, 'onClick');
|
||
* jQuery(element).on('click', view.onClick);
|
||
* // => Logs 'clicked docs' when clicked.
|
||
*/
|
||
var bindAll = rest(function(object, methodNames) {
|
||
arrayEach(baseFlatten(methodNames, 1), function(key) {
|
||
object[key] = bind(object[key], object);
|
||
});
|
||
return object;
|
||
});
|
||
|
||
/**
|
||
* Creates a function that iterates over `pairs` and invokes the corresponding
|
||
* function of the first predicate to return truthy. The predicate-function
|
||
* pairs are invoked with the `this` binding and arguments of the created
|
||
* function.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Util
|
||
* @param {Array} pairs The predicate-function pairs.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var func = _.cond([
|
||
* [_.matches({ 'a': 1 }), _.constant('matches A')],
|
||
* [_.conforms({ 'b': _.isNumber }), _.constant('matches B')],
|
||
* [_.constant(true), _.constant('no match')]
|
||
* ]);
|
||
*
|
||
* func({ 'a': 1, 'b': 2 });
|
||
* // => 'matches A'
|
||
*
|
||
* func({ 'a': 0, 'b': 1 });
|
||
* // => 'matches B'
|
||
*
|
||
* func({ 'a': '1', 'b': '2' });
|
||
* // => 'no match'
|
||
*/
|
||
function cond(pairs) {
|
||
var length = pairs ? pairs.length : 0,
|
||
toIteratee = getIteratee();
|
||
|
||
pairs = !length ? [] : arrayMap(pairs, function(pair) {
|
||
if (typeof pair[1] != 'function') {
|
||
throw new TypeError(FUNC_ERROR_TEXT);
|
||
}
|
||
return [toIteratee(pair[0]), pair[1]];
|
||
});
|
||
|
||
return rest(function(args) {
|
||
var index = -1;
|
||
while (++index < length) {
|
||
var pair = pairs[index];
|
||
if (apply(pair[0], this, args)) {
|
||
return apply(pair[1], this, args);
|
||
}
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Creates a function that invokes the predicate properties of `source` with
|
||
* the corresponding property values of a given object, returning `true` if
|
||
* all predicates return truthy, else `false`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Util
|
||
* @param {Object} source The object of property predicates to conform to.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'age': 36 },
|
||
* { 'user': 'fred', 'age': 40 }
|
||
* ];
|
||
*
|
||
* _.filter(users, _.conforms({ 'age': _.partial(_.gt, _, 38) }));
|
||
* // => [{ 'user': 'fred', 'age': 40 }]
|
||
*/
|
||
function conforms(source) {
|
||
return baseConforms(baseClone(source, true));
|
||
}
|
||
|
||
/**
|
||
* Creates a function that returns `value`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.4.0
|
||
* @category Util
|
||
* @param {*} value The value to return from the new function.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var object = { 'user': 'fred' };
|
||
* var getter = _.constant(object);
|
||
*
|
||
* getter() === object;
|
||
* // => true
|
||
*/
|
||
function constant(value) {
|
||
return function() {
|
||
return value;
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates a function that returns the result of invoking the given functions
|
||
* with the `this` binding of the created function, where each successive
|
||
* invocation is supplied the return value of the previous.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Util
|
||
* @param {...(Function|Function[])} [funcs] Functions to invoke.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* function square(n) {
|
||
* return n * n;
|
||
* }
|
||
*
|
||
* var addSquare = _.flow(_.add, square);
|
||
* addSquare(1, 2);
|
||
* // => 9
|
||
*/
|
||
var flow = createFlow();
|
||
|
||
/**
|
||
* This method is like `_.flow` except that it creates a function that
|
||
* invokes the given functions from right to left.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Util
|
||
* @param {...(Function|Function[])} [funcs] Functions to invoke.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* function square(n) {
|
||
* return n * n;
|
||
* }
|
||
*
|
||
* var addSquare = _.flowRight(square, _.add);
|
||
* addSquare(1, 2);
|
||
* // => 9
|
||
*/
|
||
var flowRight = createFlow(true);
|
||
|
||
/**
|
||
* This method returns the first argument given to it.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Util
|
||
* @param {*} value Any value.
|
||
* @returns {*} Returns `value`.
|
||
* @example
|
||
*
|
||
* var object = { 'user': 'fred' };
|
||
*
|
||
* _.identity(object) === object;
|
||
* // => true
|
||
*/
|
||
function identity(value) {
|
||
return value;
|
||
}
|
||
|
||
/**
|
||
* Creates a function that invokes `func` with the arguments of the created
|
||
* function. If `func` is a property name, the created function returns the
|
||
* property value for a given element. If `func` is an array or object, the
|
||
* created function returns `true` for elements that contain the equivalent
|
||
* source properties, otherwise it returns `false`.
|
||
*
|
||
* @static
|
||
* @since 4.0.0
|
||
* @memberOf _
|
||
* @category Util
|
||
* @param {*} [func=_.identity] The value to convert to a callback.
|
||
* @returns {Function} Returns the callback.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'age': 36, 'active': true },
|
||
* { 'user': 'fred', 'age': 40, 'active': false }
|
||
* ];
|
||
*
|
||
* // The `_.matches` iteratee shorthand.
|
||
* _.filter(users, _.iteratee({ 'user': 'barney', 'active': true }));
|
||
* // => [{ 'user': 'barney', 'age': 36, 'active': true }]
|
||
*
|
||
* // The `_.matchesProperty` iteratee shorthand.
|
||
* _.filter(users, _.iteratee(['user', 'fred']));
|
||
* // => [{ 'user': 'fred', 'age': 40 }]
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.map(users, _.iteratee('user'));
|
||
* // => ['barney', 'fred']
|
||
*
|
||
* // Create custom iteratee shorthands.
|
||
* _.iteratee = _.wrap(_.iteratee, function(iteratee, func) {
|
||
* return !_.isRegExp(func) ? iteratee(func) : function(string) {
|
||
* return func.test(string);
|
||
* };
|
||
* });
|
||
*
|
||
* _.filter(['abc', 'def'], /ef/);
|
||
* // => ['def']
|
||
*/
|
||
function iteratee(func) {
|
||
return baseIteratee(typeof func == 'function' ? func : baseClone(func, true));
|
||
}
|
||
|
||
/**
|
||
* Creates a function that performs a partial deep comparison between a given
|
||
* object and `source`, returning `true` if the given object has equivalent
|
||
* property values, else `false`. The created function is equivalent to
|
||
* `_.isMatch` with a `source` partially applied.
|
||
*
|
||
* **Note:** This method supports comparing the same values as `_.isEqual`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Util
|
||
* @param {Object} source The object of property values to match.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney', 'age': 36, 'active': true },
|
||
* { 'user': 'fred', 'age': 40, 'active': false }
|
||
* ];
|
||
*
|
||
* _.filter(users, _.matches({ 'age': 40, 'active': false }));
|
||
* // => [{ 'user': 'fred', 'age': 40, 'active': false }]
|
||
*/
|
||
function matches(source) {
|
||
return baseMatches(baseClone(source, true));
|
||
}
|
||
|
||
/**
|
||
* Creates a function that performs a partial deep comparison between the
|
||
* value at `path` of a given object to `srcValue`, returning `true` if the
|
||
* object value is equivalent, else `false`.
|
||
*
|
||
* **Note:** This method supports comparing the same values as `_.isEqual`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.2.0
|
||
* @category Util
|
||
* @param {Array|string} path The path of the property to get.
|
||
* @param {*} srcValue The value to match.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var users = [
|
||
* { 'user': 'barney' },
|
||
* { 'user': 'fred' }
|
||
* ];
|
||
*
|
||
* _.find(users, _.matchesProperty('user', 'fred'));
|
||
* // => { 'user': 'fred' }
|
||
*/
|
||
function matchesProperty(path, srcValue) {
|
||
return baseMatchesProperty(path, baseClone(srcValue, true));
|
||
}
|
||
|
||
/**
|
||
* Creates a function that invokes the method at `path` of a given object.
|
||
* Any additional arguments are provided to the invoked method.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.7.0
|
||
* @category Util
|
||
* @param {Array|string} path The path of the method to invoke.
|
||
* @param {...*} [args] The arguments to invoke the method with.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var objects = [
|
||
* { 'a': { 'b': _.constant(2) } },
|
||
* { 'a': { 'b': _.constant(1) } }
|
||
* ];
|
||
*
|
||
* _.map(objects, _.method('a.b'));
|
||
* // => [2, 1]
|
||
*
|
||
* _.map(objects, _.method(['a', 'b']));
|
||
* // => [2, 1]
|
||
*/
|
||
var method = rest(function(path, args) {
|
||
return function(object) {
|
||
return baseInvoke(object, path, args);
|
||
};
|
||
});
|
||
|
||
/**
|
||
* The opposite of `_.method`; this method creates a function that invokes
|
||
* the method at a given path of `object`. Any additional arguments are
|
||
* provided to the invoked method.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.7.0
|
||
* @category Util
|
||
* @param {Object} object The object to query.
|
||
* @param {...*} [args] The arguments to invoke the method with.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var array = _.times(3, _.constant),
|
||
* object = { 'a': array, 'b': array, 'c': array };
|
||
*
|
||
* _.map(['a[2]', 'c[0]'], _.methodOf(object));
|
||
* // => [2, 0]
|
||
*
|
||
* _.map([['a', '2'], ['c', '0']], _.methodOf(object));
|
||
* // => [2, 0]
|
||
*/
|
||
var methodOf = rest(function(object, args) {
|
||
return function(path) {
|
||
return baseInvoke(object, path, args);
|
||
};
|
||
});
|
||
|
||
/**
|
||
* Adds all own enumerable string keyed function properties of a source
|
||
* object to the destination object. If `object` is a function, then methods
|
||
* are added to its prototype as well.
|
||
*
|
||
* **Note:** Use `_.runInContext` to create a pristine `lodash` function to
|
||
* avoid conflicts caused by modifying the original.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Util
|
||
* @param {Function|Object} [object=lodash] The destination object.
|
||
* @param {Object} source The object of functions to add.
|
||
* @param {Object} [options={}] The options object.
|
||
* @param {boolean} [options.chain=true] Specify whether mixins are chainable.
|
||
* @returns {Function|Object} Returns `object`.
|
||
* @example
|
||
*
|
||
* function vowels(string) {
|
||
* return _.filter(string, function(v) {
|
||
* return /[aeiou]/i.test(v);
|
||
* });
|
||
* }
|
||
*
|
||
* _.mixin({ 'vowels': vowels });
|
||
* _.vowels('fred');
|
||
* // => ['e']
|
||
*
|
||
* _('fred').vowels().value();
|
||
* // => ['e']
|
||
*
|
||
* _.mixin({ 'vowels': vowels }, { 'chain': false });
|
||
* _('fred').vowels();
|
||
* // => ['e']
|
||
*/
|
||
function mixin(object, source, options) {
|
||
var props = keys(source),
|
||
methodNames = baseFunctions(source, props);
|
||
|
||
if (options == null &&
|
||
!(isObject(source) && (methodNames.length || !props.length))) {
|
||
options = source;
|
||
source = object;
|
||
object = this;
|
||
methodNames = baseFunctions(source, keys(source));
|
||
}
|
||
var chain = !(isObject(options) && 'chain' in options) || !!options.chain,
|
||
isFunc = isFunction(object);
|
||
|
||
arrayEach(methodNames, function(methodName) {
|
||
var func = source[methodName];
|
||
object[methodName] = func;
|
||
if (isFunc) {
|
||
object.prototype[methodName] = function() {
|
||
var chainAll = this.__chain__;
|
||
if (chain || chainAll) {
|
||
var result = object(this.__wrapped__),
|
||
actions = result.__actions__ = copyArray(this.__actions__);
|
||
|
||
actions.push({ 'func': func, 'args': arguments, 'thisArg': object });
|
||
result.__chain__ = chainAll;
|
||
return result;
|
||
}
|
||
return func.apply(object, arrayPush([this.value()], arguments));
|
||
};
|
||
}
|
||
});
|
||
|
||
return object;
|
||
}
|
||
|
||
/**
|
||
* Reverts the `_` variable to its previous value and returns a reference to
|
||
* the `lodash` function.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Util
|
||
* @returns {Function} Returns the `lodash` function.
|
||
* @example
|
||
*
|
||
* var lodash = _.noConflict();
|
||
*/
|
||
function noConflict() {
|
||
if (root._ === this) {
|
||
root._ = oldDash;
|
||
}
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* A no-operation function that returns `undefined` regardless of the
|
||
* arguments it receives.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.3.0
|
||
* @category Util
|
||
* @example
|
||
*
|
||
* var object = { 'user': 'fred' };
|
||
*
|
||
* _.noop(object) === undefined;
|
||
* // => true
|
||
*/
|
||
function noop() {
|
||
// No operation performed.
|
||
}
|
||
|
||
/**
|
||
* Creates a function that returns its nth argument. If `n` is negative,
|
||
* the nth argument from the end is returned.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Util
|
||
* @param {number} [n=0] The index of the argument to return.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var func = _.nthArg(1);
|
||
* func('a', 'b', 'c', 'd');
|
||
* // => 'b'
|
||
*
|
||
* var func = _.nthArg(-2);
|
||
* func('a', 'b', 'c', 'd');
|
||
* // => 'c'
|
||
*/
|
||
function nthArg(n) {
|
||
n = toInteger(n);
|
||
return rest(function(args) {
|
||
return baseNth(args, n);
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Creates a function that invokes `iteratees` with the arguments it receives
|
||
* and returns their results.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Util
|
||
* @param {...(Array|Array[]|Function|Function[]|Object|Object[]|string|string[])}
|
||
* [iteratees=[_.identity]] The iteratees to invoke.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var func = _.over(Math.max, Math.min);
|
||
*
|
||
* func(1, 2, 3, 4);
|
||
* // => [4, 1]
|
||
*/
|
||
var over = createOver(arrayMap);
|
||
|
||
/**
|
||
* Creates a function that checks if **all** of the `predicates` return
|
||
* truthy when invoked with the arguments it receives.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Util
|
||
* @param {...(Array|Array[]|Function|Function[]|Object|Object[]|string|string[])}
|
||
* [predicates=[_.identity]] The predicates to check.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var func = _.overEvery(Boolean, isFinite);
|
||
*
|
||
* func('1');
|
||
* // => true
|
||
*
|
||
* func(null);
|
||
* // => false
|
||
*
|
||
* func(NaN);
|
||
* // => false
|
||
*/
|
||
var overEvery = createOver(arrayEvery);
|
||
|
||
/**
|
||
* Creates a function that checks if **any** of the `predicates` return
|
||
* truthy when invoked with the arguments it receives.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Util
|
||
* @param {...(Array|Array[]|Function|Function[]|Object|Object[]|string|string[])}
|
||
* [predicates=[_.identity]] The predicates to check.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var func = _.overSome(Boolean, isFinite);
|
||
*
|
||
* func('1');
|
||
* // => true
|
||
*
|
||
* func(null);
|
||
* // => true
|
||
*
|
||
* func(NaN);
|
||
* // => false
|
||
*/
|
||
var overSome = createOver(arraySome);
|
||
|
||
/**
|
||
* Creates a function that returns the value at `path` of a given object.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 2.4.0
|
||
* @category Util
|
||
* @param {Array|string} path The path of the property to get.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var objects = [
|
||
* { 'a': { 'b': 2 } },
|
||
* { 'a': { 'b': 1 } }
|
||
* ];
|
||
*
|
||
* _.map(objects, _.property('a.b'));
|
||
* // => [2, 1]
|
||
*
|
||
* _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b');
|
||
* // => [1, 2]
|
||
*/
|
||
function property(path) {
|
||
return isKey(path) ? baseProperty(path) : basePropertyDeep(path);
|
||
}
|
||
|
||
/**
|
||
* The opposite of `_.property`; this method creates a function that returns
|
||
* the value at a given path of `object`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.0.0
|
||
* @category Util
|
||
* @param {Object} object The object to query.
|
||
* @returns {Function} Returns the new function.
|
||
* @example
|
||
*
|
||
* var array = [0, 1, 2],
|
||
* object = { 'a': array, 'b': array, 'c': array };
|
||
*
|
||
* _.map(['a[2]', 'c[0]'], _.propertyOf(object));
|
||
* // => [2, 0]
|
||
*
|
||
* _.map([['a', '2'], ['c', '0']], _.propertyOf(object));
|
||
* // => [2, 0]
|
||
*/
|
||
function propertyOf(object) {
|
||
return function(path) {
|
||
return object == null ? undefined : baseGet(object, path);
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Creates an array of numbers (positive and/or negative) progressing from
|
||
* `start` up to, but not including, `end`. A step of `-1` is used if a negative
|
||
* `start` is specified without an `end` or `step`. If `end` is not specified,
|
||
* it's set to `start` with `start` then set to `0`.
|
||
*
|
||
* **Note:** JavaScript follows the IEEE-754 standard for resolving
|
||
* floating-point values which can produce unexpected results.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Util
|
||
* @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 the new array of numbers.
|
||
* @example
|
||
*
|
||
* _.range(4);
|
||
* // => [0, 1, 2, 3]
|
||
*
|
||
* _.range(-4);
|
||
* // => [0, -1, -2, -3]
|
||
*
|
||
* _.range(1, 5);
|
||
* // => [1, 2, 3, 4]
|
||
*
|
||
* _.range(0, 20, 5);
|
||
* // => [0, 5, 10, 15]
|
||
*
|
||
* _.range(0, -4, -1);
|
||
* // => [0, -1, -2, -3]
|
||
*
|
||
* _.range(1, 4, 0);
|
||
* // => [1, 1, 1]
|
||
*
|
||
* _.range(0);
|
||
* // => []
|
||
*/
|
||
var range = createRange();
|
||
|
||
/**
|
||
* This method is like `_.range` except that it populates values in
|
||
* descending order.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Util
|
||
* @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 the new array of numbers.
|
||
* @example
|
||
*
|
||
* _.rangeRight(4);
|
||
* // => [3, 2, 1, 0]
|
||
*
|
||
* _.rangeRight(-4);
|
||
* // => [-3, -2, -1, 0]
|
||
*
|
||
* _.rangeRight(1, 5);
|
||
* // => [4, 3, 2, 1]
|
||
*
|
||
* _.rangeRight(0, 20, 5);
|
||
* // => [15, 10, 5, 0]
|
||
*
|
||
* _.rangeRight(0, -4, -1);
|
||
* // => [-3, -2, -1, 0]
|
||
*
|
||
* _.rangeRight(1, 4, 0);
|
||
* // => [1, 1, 1]
|
||
*
|
||
* _.rangeRight(0);
|
||
* // => []
|
||
*/
|
||
var rangeRight = createRange(true);
|
||
|
||
/**
|
||
* Invokes the iteratee `n` times, returning an array of the results of
|
||
* each invocation. The iteratee is invoked with one argument; (index).
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Util
|
||
* @param {number} n The number of times to invoke `iteratee`.
|
||
* @param {Function} [iteratee=_.identity] The function invoked per iteration.
|
||
* @returns {Array} Returns the array of results.
|
||
* @example
|
||
*
|
||
* _.times(3, String);
|
||
* // => ['0', '1', '2']
|
||
*
|
||
* _.times(4, _.constant(true));
|
||
* // => [true, true, true, true]
|
||
*/
|
||
function times(n, iteratee) {
|
||
n = toInteger(n);
|
||
if (n < 1 || n > MAX_SAFE_INTEGER) {
|
||
return [];
|
||
}
|
||
var index = MAX_ARRAY_LENGTH,
|
||
length = nativeMin(n, MAX_ARRAY_LENGTH);
|
||
|
||
iteratee = getIteratee(iteratee);
|
||
n -= MAX_ARRAY_LENGTH;
|
||
|
||
var result = baseTimes(length, iteratee);
|
||
while (++index < n) {
|
||
iteratee(index);
|
||
}
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Converts `value` to a property path array.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Util
|
||
* @param {*} value The value to convert.
|
||
* @returns {Array} Returns the new property path array.
|
||
* @example
|
||
*
|
||
* _.toPath('a.b.c');
|
||
* // => ['a', 'b', 'c']
|
||
*
|
||
* _.toPath('a[0].b.c');
|
||
* // => ['a', '0', 'b', 'c']
|
||
*
|
||
* var path = ['a', 'b', 'c'],
|
||
* newPath = _.toPath(path);
|
||
*
|
||
* console.log(newPath);
|
||
* // => ['a', 'b', 'c']
|
||
*
|
||
* console.log(path === newPath);
|
||
* // => false
|
||
*/
|
||
function toPath(value) {
|
||
if (isArray(value)) {
|
||
return arrayMap(value, toKey);
|
||
}
|
||
return isSymbol(value) ? [value] : copyArray(stringToPath(value));
|
||
}
|
||
|
||
/**
|
||
* Generates a unique ID. If `prefix` is given, the ID is appended to it.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Util
|
||
* @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 toString(prefix) + id;
|
||
}
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* Adds two numbers.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.4.0
|
||
* @category Math
|
||
* @param {number} augend The first number in an addition.
|
||
* @param {number} addend The second number in an addition.
|
||
* @returns {number} Returns the total.
|
||
* @example
|
||
*
|
||
* _.add(6, 4);
|
||
* // => 10
|
||
*/
|
||
var add = createMathOperation(function(augend, addend) {
|
||
return augend + addend;
|
||
});
|
||
|
||
/**
|
||
* Computes `number` rounded up to `precision`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.10.0
|
||
* @category Math
|
||
* @param {number} number The number to round up.
|
||
* @param {number} [precision=0] The precision to round up to.
|
||
* @returns {number} Returns the rounded up number.
|
||
* @example
|
||
*
|
||
* _.ceil(4.006);
|
||
* // => 5
|
||
*
|
||
* _.ceil(6.004, 2);
|
||
* // => 6.01
|
||
*
|
||
* _.ceil(6040, -2);
|
||
* // => 6100
|
||
*/
|
||
var ceil = createRound('ceil');
|
||
|
||
/**
|
||
* Divide two numbers.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.7.0
|
||
* @category Math
|
||
* @param {number} dividend The first number in a division.
|
||
* @param {number} divisor The second number in a division.
|
||
* @returns {number} Returns the quotient.
|
||
* @example
|
||
*
|
||
* _.divide(6, 4);
|
||
* // => 1.5
|
||
*/
|
||
var divide = createMathOperation(function(dividend, divisor) {
|
||
return dividend / divisor;
|
||
});
|
||
|
||
/**
|
||
* Computes `number` rounded down to `precision`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.10.0
|
||
* @category Math
|
||
* @param {number} number The number to round down.
|
||
* @param {number} [precision=0] The precision to round down to.
|
||
* @returns {number} Returns the rounded down number.
|
||
* @example
|
||
*
|
||
* _.floor(4.006);
|
||
* // => 4
|
||
*
|
||
* _.floor(0.046, 2);
|
||
* // => 0.04
|
||
*
|
||
* _.floor(4060, -2);
|
||
* // => 4000
|
||
*/
|
||
var floor = createRound('floor');
|
||
|
||
/**
|
||
* Computes the maximum value of `array`. If `array` is empty or falsey,
|
||
* `undefined` is returned.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Math
|
||
* @param {Array} array The array to iterate over.
|
||
* @returns {*} Returns the maximum value.
|
||
* @example
|
||
*
|
||
* _.max([4, 2, 8, 6]);
|
||
* // => 8
|
||
*
|
||
* _.max([]);
|
||
* // => undefined
|
||
*/
|
||
function max(array) {
|
||
return (array && array.length)
|
||
? baseExtremum(array, identity, gt)
|
||
: undefined;
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.max` except that it accepts `iteratee` which is
|
||
* invoked for each element in `array` to generate the criterion by which
|
||
* the value is ranked. The iteratee is invoked with one argument: (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Math
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee invoked per element.
|
||
* @returns {*} Returns the maximum value.
|
||
* @example
|
||
*
|
||
* var objects = [{ 'n': 1 }, { 'n': 2 }];
|
||
*
|
||
* _.maxBy(objects, function(o) { return o.n; });
|
||
* // => { 'n': 2 }
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.maxBy(objects, 'n');
|
||
* // => { 'n': 2 }
|
||
*/
|
||
function maxBy(array, iteratee) {
|
||
return (array && array.length)
|
||
? baseExtremum(array, getIteratee(iteratee), gt)
|
||
: undefined;
|
||
}
|
||
|
||
/**
|
||
* Computes the mean of the values in `array`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Math
|
||
* @param {Array} array The array to iterate over.
|
||
* @returns {number} Returns the mean.
|
||
* @example
|
||
*
|
||
* _.mean([4, 2, 8, 6]);
|
||
* // => 5
|
||
*/
|
||
function mean(array) {
|
||
return baseMean(array, identity);
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.mean` except that it accepts `iteratee` which is
|
||
* invoked for each element in `array` to generate the value to be averaged.
|
||
* The iteratee is invoked with one argument: (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.7.0
|
||
* @category Math
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee invoked per element.
|
||
* @returns {number} Returns the mean.
|
||
* @example
|
||
*
|
||
* var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
|
||
*
|
||
* _.meanBy(objects, function(o) { return o.n; });
|
||
* // => 5
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.meanBy(objects, 'n');
|
||
* // => 5
|
||
*/
|
||
function meanBy(array, iteratee) {
|
||
return baseMean(array, getIteratee(iteratee));
|
||
}
|
||
|
||
/**
|
||
* Computes the minimum value of `array`. If `array` is empty or falsey,
|
||
* `undefined` is returned.
|
||
*
|
||
* @static
|
||
* @since 0.1.0
|
||
* @memberOf _
|
||
* @category Math
|
||
* @param {Array} array The array to iterate over.
|
||
* @returns {*} Returns the minimum value.
|
||
* @example
|
||
*
|
||
* _.min([4, 2, 8, 6]);
|
||
* // => 2
|
||
*
|
||
* _.min([]);
|
||
* // => undefined
|
||
*/
|
||
function min(array) {
|
||
return (array && array.length)
|
||
? baseExtremum(array, identity, lt)
|
||
: undefined;
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.min` except that it accepts `iteratee` which is
|
||
* invoked for each element in `array` to generate the criterion by which
|
||
* the value is ranked. The iteratee is invoked with one argument: (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Math
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee invoked per element.
|
||
* @returns {*} Returns the minimum value.
|
||
* @example
|
||
*
|
||
* var objects = [{ 'n': 1 }, { 'n': 2 }];
|
||
*
|
||
* _.minBy(objects, function(o) { return o.n; });
|
||
* // => { 'n': 1 }
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.minBy(objects, 'n');
|
||
* // => { 'n': 1 }
|
||
*/
|
||
function minBy(array, iteratee) {
|
||
return (array && array.length)
|
||
? baseExtremum(array, getIteratee(iteratee), lt)
|
||
: undefined;
|
||
}
|
||
|
||
/**
|
||
* Multiply two numbers.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.7.0
|
||
* @category Math
|
||
* @param {number} multiplier The first number in a multiplication.
|
||
* @param {number} multiplicand The second number in a multiplication.
|
||
* @returns {number} Returns the product.
|
||
* @example
|
||
*
|
||
* _.multiply(6, 4);
|
||
* // => 24
|
||
*/
|
||
var multiply = createMathOperation(function(multiplier, multiplicand) {
|
||
return multiplier * multiplicand;
|
||
});
|
||
|
||
/**
|
||
* Computes `number` rounded to `precision`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.10.0
|
||
* @category Math
|
||
* @param {number} number The number to round.
|
||
* @param {number} [precision=0] The precision to round to.
|
||
* @returns {number} Returns the rounded number.
|
||
* @example
|
||
*
|
||
* _.round(4.006);
|
||
* // => 4
|
||
*
|
||
* _.round(4.006, 2);
|
||
* // => 4.01
|
||
*
|
||
* _.round(4060, -2);
|
||
* // => 4100
|
||
*/
|
||
var round = createRound('round');
|
||
|
||
/**
|
||
* Subtract two numbers.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Math
|
||
* @param {number} minuend The first number in a subtraction.
|
||
* @param {number} subtrahend The second number in a subtraction.
|
||
* @returns {number} Returns the difference.
|
||
* @example
|
||
*
|
||
* _.subtract(6, 4);
|
||
* // => 2
|
||
*/
|
||
var subtract = createMathOperation(function(minuend, subtrahend) {
|
||
return minuend - subtrahend;
|
||
});
|
||
|
||
/**
|
||
* Computes the sum of the values in `array`.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 3.4.0
|
||
* @category Math
|
||
* @param {Array} array The array to iterate over.
|
||
* @returns {number} Returns the sum.
|
||
* @example
|
||
*
|
||
* _.sum([4, 2, 8, 6]);
|
||
* // => 20
|
||
*/
|
||
function sum(array) {
|
||
return (array && array.length)
|
||
? baseSum(array, identity)
|
||
: 0;
|
||
}
|
||
|
||
/**
|
||
* This method is like `_.sum` except that it accepts `iteratee` which is
|
||
* invoked for each element in `array` to generate the value to be summed.
|
||
* The iteratee is invoked with one argument: (value).
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @since 4.0.0
|
||
* @category Math
|
||
* @param {Array} array The array to iterate over.
|
||
* @param {Array|Function|Object|string} [iteratee=_.identity]
|
||
* The iteratee invoked per element.
|
||
* @returns {number} Returns the sum.
|
||
* @example
|
||
*
|
||
* var objects = [{ 'n': 4 }, { 'n': 2 }, { 'n': 8 }, { 'n': 6 }];
|
||
*
|
||
* _.sumBy(objects, function(o) { return o.n; });
|
||
* // => 20
|
||
*
|
||
* // The `_.property` iteratee shorthand.
|
||
* _.sumBy(objects, 'n');
|
||
* // => 20
|
||
*/
|
||
function sumBy(array, iteratee) {
|
||
return (array && array.length)
|
||
? baseSum(array, getIteratee(iteratee))
|
||
: 0;
|
||
}
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
// Add methods that return wrapped values in chain sequences.
|
||
lodash.after = after;
|
||
lodash.ary = ary;
|
||
lodash.assign = assign;
|
||
lodash.assignIn = assignIn;
|
||
lodash.assignInWith = assignInWith;
|
||
lodash.assignWith = assignWith;
|
||
lodash.at = at;
|
||
lodash.before = before;
|
||
lodash.bind = bind;
|
||
lodash.bindAll = bindAll;
|
||
lodash.bindKey = bindKey;
|
||
lodash.castArray = castArray;
|
||
lodash.chain = chain;
|
||
lodash.chunk = chunk;
|
||
lodash.compact = compact;
|
||
lodash.concat = concat;
|
||
lodash.cond = cond;
|
||
lodash.conforms = conforms;
|
||
lodash.constant = constant;
|
||
lodash.countBy = countBy;
|
||
lodash.create = create;
|
||
lodash.curry = curry;
|
||
lodash.curryRight = curryRight;
|
||
lodash.debounce = debounce;
|
||
lodash.defaults = defaults;
|
||
lodash.defaultsDeep = defaultsDeep;
|
||
lodash.defer = defer;
|
||
lodash.delay = delay;
|
||
lodash.difference = difference;
|
||
lodash.differenceBy = differenceBy;
|
||
lodash.differenceWith = differenceWith;
|
||
lodash.drop = drop;
|
||
lodash.dropRight = dropRight;
|
||
lodash.dropRightWhile = dropRightWhile;
|
||
lodash.dropWhile = dropWhile;
|
||
lodash.fill = fill;
|
||
lodash.filter = filter;
|
||
lodash.flatMap = flatMap;
|
||
lodash.flatMapDeep = flatMapDeep;
|
||
lodash.flatMapDepth = flatMapDepth;
|
||
lodash.flatten = flatten;
|
||
lodash.flattenDeep = flattenDeep;
|
||
lodash.flattenDepth = flattenDepth;
|
||
lodash.flip = flip;
|
||
lodash.flow = flow;
|
||
lodash.flowRight = flowRight;
|
||
lodash.fromPairs = fromPairs;
|
||
lodash.functions = functions;
|
||
lodash.functionsIn = functionsIn;
|
||
lodash.groupBy = groupBy;
|
||
lodash.initial = initial;
|
||
lodash.intersection = intersection;
|
||
lodash.intersectionBy = intersectionBy;
|
||
lodash.intersectionWith = intersectionWith;
|
||
lodash.invert = invert;
|
||
lodash.invertBy = invertBy;
|
||
lodash.invokeMap = invokeMap;
|
||
lodash.iteratee = iteratee;
|
||
lodash.keyBy = keyBy;
|
||
lodash.keys = keys;
|
||
lodash.keysIn = keysIn;
|
||
lodash.map = map;
|
||
lodash.mapKeys = mapKeys;
|
||
lodash.mapValues = mapValues;
|
||
lodash.matches = matches;
|
||
lodash.matchesProperty = matchesProperty;
|
||
lodash.memoize = memoize;
|
||
lodash.merge = merge;
|
||
lodash.mergeWith = mergeWith;
|
||
lodash.method = method;
|
||
lodash.methodOf = methodOf;
|
||
lodash.mixin = mixin;
|
||
lodash.negate = negate;
|
||
lodash.nthArg = nthArg;
|
||
lodash.omit = omit;
|
||
lodash.omitBy = omitBy;
|
||
lodash.once = once;
|
||
lodash.orderBy = orderBy;
|
||
lodash.over = over;
|
||
lodash.overArgs = overArgs;
|
||
lodash.overEvery = overEvery;
|
||
lodash.overSome = overSome;
|
||
lodash.partial = partial;
|
||
lodash.partialRight = partialRight;
|
||
lodash.partition = partition;
|
||
lodash.pick = pick;
|
||
lodash.pickBy = pickBy;
|
||
lodash.property = property;
|
||
lodash.propertyOf = propertyOf;
|
||
lodash.pull = pull;
|
||
lodash.pullAll = pullAll;
|
||
lodash.pullAllBy = pullAllBy;
|
||
lodash.pullAllWith = pullAllWith;
|
||
lodash.pullAt = pullAt;
|
||
lodash.range = range;
|
||
lodash.rangeRight = rangeRight;
|
||
lodash.rearg = rearg;
|
||
lodash.reject = reject;
|
||
lodash.remove = remove;
|
||
lodash.rest = rest;
|
||
lodash.reverse = reverse;
|
||
lodash.sampleSize = sampleSize;
|
||
lodash.set = set;
|
||
lodash.setWith = setWith;
|
||
lodash.shuffle = shuffle;
|
||
lodash.slice = slice;
|
||
lodash.sortBy = sortBy;
|
||
lodash.sortedUniq = sortedUniq;
|
||
lodash.sortedUniqBy = sortedUniqBy;
|
||
lodash.split = split;
|
||
lodash.spread = spread;
|
||
lodash.tail = tail;
|
||
lodash.take = take;
|
||
lodash.takeRight = takeRight;
|
||
lodash.takeRightWhile = takeRightWhile;
|
||
lodash.takeWhile = takeWhile;
|
||
lodash.tap = tap;
|
||
lodash.throttle = throttle;
|
||
lodash.thru = thru;
|
||
lodash.toArray = toArray;
|
||
lodash.toPairs = toPairs;
|
||
lodash.toPairsIn = toPairsIn;
|
||
lodash.toPath = toPath;
|
||
lodash.toPlainObject = toPlainObject;
|
||
lodash.transform = transform;
|
||
lodash.unary = unary;
|
||
lodash.union = union;
|
||
lodash.unionBy = unionBy;
|
||
lodash.unionWith = unionWith;
|
||
lodash.uniq = uniq;
|
||
lodash.uniqBy = uniqBy;
|
||
lodash.uniqWith = uniqWith;
|
||
lodash.unset = unset;
|
||
lodash.unzip = unzip;
|
||
lodash.unzipWith = unzipWith;
|
||
lodash.update = update;
|
||
lodash.updateWith = updateWith;
|
||
lodash.values = values;
|
||
lodash.valuesIn = valuesIn;
|
||
lodash.without = without;
|
||
lodash.words = words;
|
||
lodash.wrap = wrap;
|
||
lodash.xor = xor;
|
||
lodash.xorBy = xorBy;
|
||
lodash.xorWith = xorWith;
|
||
lodash.zip = zip;
|
||
lodash.zipObject = zipObject;
|
||
lodash.zipObjectDeep = zipObjectDeep;
|
||
lodash.zipWith = zipWith;
|
||
|
||
// Add aliases.
|
||
lodash.entries = toPairs;
|
||
lodash.entriesIn = toPairsIn;
|
||
lodash.extend = assignIn;
|
||
lodash.extendWith = assignInWith;
|
||
|
||
// Add methods to `lodash.prototype`.
|
||
mixin(lodash, lodash);
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
// Add methods that return unwrapped values in chain sequences.
|
||
lodash.add = add;
|
||
lodash.attempt = attempt;
|
||
lodash.camelCase = camelCase;
|
||
lodash.capitalize = capitalize;
|
||
lodash.ceil = ceil;
|
||
lodash.clamp = clamp;
|
||
lodash.clone = clone;
|
||
lodash.cloneDeep = cloneDeep;
|
||
lodash.cloneDeepWith = cloneDeepWith;
|
||
lodash.cloneWith = cloneWith;
|
||
lodash.deburr = deburr;
|
||
lodash.divide = divide;
|
||
lodash.endsWith = endsWith;
|
||
lodash.eq = eq;
|
||
lodash.escape = escape;
|
||
lodash.escapeRegExp = escapeRegExp;
|
||
lodash.every = every;
|
||
lodash.find = find;
|
||
lodash.findIndex = findIndex;
|
||
lodash.findKey = findKey;
|
||
lodash.findLast = findLast;
|
||
lodash.findLastIndex = findLastIndex;
|
||
lodash.findLastKey = findLastKey;
|
||
lodash.floor = floor;
|
||
lodash.forEach = forEach;
|
||
lodash.forEachRight = forEachRight;
|
||
lodash.forIn = forIn;
|
||
lodash.forInRight = forInRight;
|
||
lodash.forOwn = forOwn;
|
||
lodash.forOwnRight = forOwnRight;
|
||
lodash.get = get;
|
||
lodash.gt = gt;
|
||
lodash.gte = gte;
|
||
lodash.has = has;
|
||
lodash.hasIn = hasIn;
|
||
lodash.head = head;
|
||
lodash.identity = identity;
|
||
lodash.includes = includes;
|
||
lodash.indexOf = indexOf;
|
||
lodash.inRange = inRange;
|
||
lodash.invoke = invoke;
|
||
lodash.isArguments = isArguments;
|
||
lodash.isArray = isArray;
|
||
lodash.isArrayBuffer = isArrayBuffer;
|
||
lodash.isArrayLike = isArrayLike;
|
||
lodash.isArrayLikeObject = isArrayLikeObject;
|
||
lodash.isBoolean = isBoolean;
|
||
lodash.isBuffer = isBuffer;
|
||
lodash.isDate = isDate;
|
||
lodash.isElement = isElement;
|
||
lodash.isEmpty = isEmpty;
|
||
lodash.isEqual = isEqual;
|
||
lodash.isEqualWith = isEqualWith;
|
||
lodash.isError = isError;
|
||
lodash.isFinite = isFinite;
|
||
lodash.isFunction = isFunction;
|
||
lodash.isInteger = isInteger;
|
||
lodash.isLength = isLength;
|
||
lodash.isMap = isMap;
|
||
lodash.isMatch = isMatch;
|
||
lodash.isMatchWith = isMatchWith;
|
||
lodash.isNaN = isNaN;
|
||
lodash.isNative = isNative;
|
||
lodash.isNil = isNil;
|
||
lodash.isNull = isNull;
|
||
lodash.isNumber = isNumber;
|
||
lodash.isObject = isObject;
|
||
lodash.isObjectLike = isObjectLike;
|
||
lodash.isPlainObject = isPlainObject;
|
||
lodash.isRegExp = isRegExp;
|
||
lodash.isSafeInteger = isSafeInteger;
|
||
lodash.isSet = isSet;
|
||
lodash.isString = isString;
|
||
lodash.isSymbol = isSymbol;
|
||
lodash.isTypedArray = isTypedArray;
|
||
lodash.isUndefined = isUndefined;
|
||
lodash.isWeakMap = isWeakMap;
|
||
lodash.isWeakSet = isWeakSet;
|
||
lodash.join = join;
|
||
lodash.kebabCase = kebabCase;
|
||
lodash.last = last;
|
||
lodash.lastIndexOf = lastIndexOf;
|
||
lodash.lowerCase = lowerCase;
|
||
lodash.lowerFirst = lowerFirst;
|
||
lodash.lt = lt;
|
||
lodash.lte = lte;
|
||
lodash.max = max;
|
||
lodash.maxBy = maxBy;
|
||
lodash.mean = mean;
|
||
lodash.meanBy = meanBy;
|
||
lodash.min = min;
|
||
lodash.minBy = minBy;
|
||
lodash.multiply = multiply;
|
||
lodash.nth = nth;
|
||
lodash.noConflict = noConflict;
|
||
lodash.noop = noop;
|
||
lodash.now = now;
|
||
lodash.pad = pad;
|
||
lodash.padEnd = padEnd;
|
||
lodash.padStart = padStart;
|
||
lodash.parseInt = parseInt;
|
||
lodash.random = random;
|
||
lodash.reduce = reduce;
|
||
lodash.reduceRight = reduceRight;
|
||
lodash.repeat = repeat;
|
||
lodash.replace = replace;
|
||
lodash.result = result;
|
||
lodash.round = round;
|
||
lodash.runInContext = runInContext;
|
||
lodash.sample = sample;
|
||
lodash.size = size;
|
||
lodash.snakeCase = snakeCase;
|
||
lodash.some = some;
|
||
lodash.sortedIndex = sortedIndex;
|
||
lodash.sortedIndexBy = sortedIndexBy;
|
||
lodash.sortedIndexOf = sortedIndexOf;
|
||
lodash.sortedLastIndex = sortedLastIndex;
|
||
lodash.sortedLastIndexBy = sortedLastIndexBy;
|
||
lodash.sortedLastIndexOf = sortedLastIndexOf;
|
||
lodash.startCase = startCase;
|
||
lodash.startsWith = startsWith;
|
||
lodash.subtract = subtract;
|
||
lodash.sum = sum;
|
||
lodash.sumBy = sumBy;
|
||
lodash.template = template;
|
||
lodash.times = times;
|
||
lodash.toInteger = toInteger;
|
||
lodash.toLength = toLength;
|
||
lodash.toLower = toLower;
|
||
lodash.toNumber = toNumber;
|
||
lodash.toSafeInteger = toSafeInteger;
|
||
lodash.toString = toString;
|
||
lodash.toUpper = toUpper;
|
||
lodash.trim = trim;
|
||
lodash.trimEnd = trimEnd;
|
||
lodash.trimStart = trimStart;
|
||
lodash.truncate = truncate;
|
||
lodash.unescape = unescape;
|
||
lodash.uniqueId = uniqueId;
|
||
lodash.upperCase = upperCase;
|
||
lodash.upperFirst = upperFirst;
|
||
|
||
// Add aliases.
|
||
lodash.each = forEach;
|
||
lodash.eachRight = forEachRight;
|
||
lodash.first = head;
|
||
|
||
mixin(lodash, (function() {
|
||
var source = {};
|
||
baseForOwn(lodash, function(func, methodName) {
|
||
if (!hasOwnProperty.call(lodash.prototype, methodName)) {
|
||
source[methodName] = func;
|
||
}
|
||
});
|
||
return source;
|
||
}()), { 'chain': false });
|
||
|
||
/*------------------------------------------------------------------------*/
|
||
|
||
/**
|
||
* The semantic version number.
|
||
*
|
||
* @static
|
||
* @memberOf _
|
||
* @type {string}
|
||
*/
|
||
lodash.VERSION = VERSION;
|
||
|
||
// Assign default placeholders.
|
||
arrayEach(['bind', 'bindKey', 'curry', 'curryRight', 'partial', 'partialRight'], function(methodName) {
|
||
lodash[methodName].placeholder = lodash;
|
||
});
|
||
|
||
// Add `LazyWrapper` methods for `_.drop` and `_.take` variants.
|
||
arrayEach(['drop', 'take'], function(methodName, index) {
|
||
LazyWrapper.prototype[methodName] = function(n) {
|
||
var filtered = this.__filtered__;
|
||
if (filtered && !index) {
|
||
return new LazyWrapper(this);
|
||
}
|
||
n = n === undefined ? 1 : nativeMax(toInteger(n), 0);
|
||
|
||
var result = this.clone();
|
||
if (filtered) {
|
||
result.__takeCount__ = nativeMin(n, result.__takeCount__);
|
||
} else {
|
||
result.__views__.push({
|
||
'size': nativeMin(n, MAX_ARRAY_LENGTH),
|
||
'type': methodName + (result.__dir__ < 0 ? 'Right' : '')
|
||
});
|
||
}
|
||
return result;
|
||
};
|
||
|
||
LazyWrapper.prototype[methodName + 'Right'] = function(n) {
|
||
return this.reverse()[methodName](n).reverse();
|
||
};
|
||
});
|
||
|
||
// Add `LazyWrapper` methods that accept an `iteratee` value.
|
||
arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) {
|
||
var type = index + 1,
|
||
isFilter = type == LAZY_FILTER_FLAG || type == LAZY_WHILE_FLAG;
|
||
|
||
LazyWrapper.prototype[methodName] = function(iteratee) {
|
||
var result = this.clone();
|
||
result.__iteratees__.push({
|
||
'iteratee': getIteratee(iteratee, 3),
|
||
'type': type
|
||
});
|
||
result.__filtered__ = result.__filtered__ || isFilter;
|
||
return result;
|
||
};
|
||
});
|
||
|
||
// Add `LazyWrapper` methods for `_.head` and `_.last`.
|
||
arrayEach(['head', 'last'], function(methodName, index) {
|
||
var takeName = 'take' + (index ? 'Right' : '');
|
||
|
||
LazyWrapper.prototype[methodName] = function() {
|
||
return this[takeName](1).value()[0];
|
||
};
|
||
});
|
||
|
||
// Add `LazyWrapper` methods for `_.initial` and `_.tail`.
|
||
arrayEach(['initial', 'tail'], function(methodName, index) {
|
||
var dropName = 'drop' + (index ? '' : 'Right');
|
||
|
||
LazyWrapper.prototype[methodName] = function() {
|
||
return this.__filtered__ ? new LazyWrapper(this) : this[dropName](1);
|
||
};
|
||
});
|
||
|
||
LazyWrapper.prototype.compact = function() {
|
||
return this.filter(identity);
|
||
};
|
||
|
||
LazyWrapper.prototype.find = function(predicate) {
|
||
return this.filter(predicate).head();
|
||
};
|
||
|
||
LazyWrapper.prototype.findLast = function(predicate) {
|
||
return this.reverse().find(predicate);
|
||
};
|
||
|
||
LazyWrapper.prototype.invokeMap = rest(function(path, args) {
|
||
if (typeof path == 'function') {
|
||
return new LazyWrapper(this);
|
||
}
|
||
return this.map(function(value) {
|
||
return baseInvoke(value, path, args);
|
||
});
|
||
});
|
||
|
||
LazyWrapper.prototype.reject = function(predicate) {
|
||
predicate = getIteratee(predicate, 3);
|
||
return this.filter(function(value) {
|
||
return !predicate(value);
|
||
});
|
||
};
|
||
|
||
LazyWrapper.prototype.slice = function(start, end) {
|
||
start = toInteger(start);
|
||
|
||
var result = this;
|
||
if (result.__filtered__ && (start > 0 || end < 0)) {
|
||
return new LazyWrapper(result);
|
||
}
|
||
if (start < 0) {
|
||
result = result.takeRight(-start);
|
||
} else if (start) {
|
||
result = result.drop(start);
|
||
}
|
||
if (end !== undefined) {
|
||
end = toInteger(end);
|
||
result = end < 0 ? result.dropRight(-end) : result.take(end - start);
|
||
}
|
||
return result;
|
||
};
|
||
|
||
LazyWrapper.prototype.takeRightWhile = function(predicate) {
|
||
return this.reverse().takeWhile(predicate).reverse();
|
||
};
|
||
|
||
LazyWrapper.prototype.toArray = function() {
|
||
return this.take(MAX_ARRAY_LENGTH);
|
||
};
|
||
|
||
// Add `LazyWrapper` methods to `lodash.prototype`.
|
||
baseForOwn(LazyWrapper.prototype, function(func, methodName) {
|
||
var checkIteratee = /^(?:filter|find|map|reject)|While$/.test(methodName),
|
||
isTaker = /^(?:head|last)$/.test(methodName),
|
||
lodashFunc = lodash[isTaker ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName],
|
||
retUnwrapped = isTaker || /^find/.test(methodName);
|
||
|
||
if (!lodashFunc) {
|
||
return;
|
||
}
|
||
lodash.prototype[methodName] = function() {
|
||
var value = this.__wrapped__,
|
||
args = isTaker ? [1] : arguments,
|
||
isLazy = value instanceof LazyWrapper,
|
||
iteratee = args[0],
|
||
useLazy = isLazy || isArray(value);
|
||
|
||
var interceptor = function(value) {
|
||
var result = lodashFunc.apply(lodash, arrayPush([value], args));
|
||
return (isTaker && chainAll) ? result[0] : result;
|
||
};
|
||
|
||
if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) {
|
||
// Avoid lazy use if the iteratee has a "length" value other than `1`.
|
||
isLazy = useLazy = false;
|
||
}
|
||
var chainAll = this.__chain__,
|
||
isHybrid = !!this.__actions__.length,
|
||
isUnwrapped = retUnwrapped && !chainAll,
|
||
onlyLazy = isLazy && !isHybrid;
|
||
|
||
if (!retUnwrapped && useLazy) {
|
||
value = onlyLazy ? value : new LazyWrapper(this);
|
||
var result = func.apply(value, args);
|
||
result.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined });
|
||
return new LodashWrapper(result, chainAll);
|
||
}
|
||
if (isUnwrapped && onlyLazy) {
|
||
return func.apply(this, args);
|
||
}
|
||
result = this.thru(interceptor);
|
||
return isUnwrapped ? (isTaker ? result.value()[0] : result.value()) : result;
|
||
};
|
||
});
|
||
|
||
// Add `Array` methods to `lodash.prototype`.
|
||
arrayEach(['pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) {
|
||
var func = arrayProto[methodName],
|
||
chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru',
|
||
retUnwrapped = /^(?:pop|shift)$/.test(methodName);
|
||
|
||
lodash.prototype[methodName] = function() {
|
||
var args = arguments;
|
||
if (retUnwrapped && !this.__chain__) {
|
||
var value = this.value();
|
||
return func.apply(isArray(value) ? value : [], args);
|
||
}
|
||
return this[chainName](function(value) {
|
||
return func.apply(isArray(value) ? value : [], args);
|
||
});
|
||
};
|
||
});
|
||
|
||
// Map minified method names to their real names.
|
||
baseForOwn(LazyWrapper.prototype, function(func, methodName) {
|
||
var lodashFunc = lodash[methodName];
|
||
if (lodashFunc) {
|
||
var key = (lodashFunc.name + ''),
|
||
names = realNames[key] || (realNames[key] = []);
|
||
|
||
names.push({ 'name': methodName, 'func': lodashFunc });
|
||
}
|
||
});
|
||
|
||
realNames[createHybridWrapper(undefined, BIND_KEY_FLAG).name] = [{
|
||
'name': 'wrapper',
|
||
'func': undefined
|
||
}];
|
||
|
||
// Add methods to `LazyWrapper`.
|
||
LazyWrapper.prototype.clone = lazyClone;
|
||
LazyWrapper.prototype.reverse = lazyReverse;
|
||
LazyWrapper.prototype.value = lazyValue;
|
||
|
||
// Add chain sequence methods to the `lodash` wrapper.
|
||
lodash.prototype.at = wrapperAt;
|
||
lodash.prototype.chain = wrapperChain;
|
||
lodash.prototype.commit = wrapperCommit;
|
||
lodash.prototype.next = wrapperNext;
|
||
lodash.prototype.plant = wrapperPlant;
|
||
lodash.prototype.reverse = wrapperReverse;
|
||
lodash.prototype.toJSON = lodash.prototype.valueOf = lodash.prototype.value = wrapperValue;
|
||
|
||
if (iteratorSymbol) {
|
||
lodash.prototype[iteratorSymbol] = wrapperToIterator;
|
||
}
|
||
return lodash;
|
||
}
|
||
|
||
/*--------------------------------------------------------------------------*/
|
||
|
||
// Export lodash.
|
||
var _ = runInContext();
|
||
|
||
// Expose lodash on the free variable `window` or `self` when available. This
|
||
// prevents errors in cases where lodash is loaded by a script tag in the presence
|
||
// of an AMD loader. See http://requirejs.org/docs/errors.html#mismatch for more details.
|
||
(freeWindow || freeSelf || {})._ = _;
|
||
|
||
// Some AMD build optimizers like r.js check for condition patterns like the following:
|
||
if (true) {
|
||
// Define as an anonymous module so, through path mapping, it can be
|
||
// referenced as the "underscore" module.
|
||
!(__WEBPACK_AMD_DEFINE_RESULT__ = function() {
|
||
return _;
|
||
}.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
|
||
}
|
||
// Check for `exports` after `define` in case a build optimizer adds an `exports` object.
|
||
else if (freeExports && freeModule) {
|
||
// Export for Node.js.
|
||
if (moduleExports) {
|
||
(freeModule.exports = _)._ = _;
|
||
}
|
||
// Export for CommonJS support.
|
||
freeExports._ = _;
|
||
}
|
||
else {
|
||
// Export to the global object.
|
||
root._ = _;
|
||
}
|
||
}.call(this));
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(76)(module), (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 151 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(setImmediate, clearImmediate) {/*
|
||
* @name Lazy.js
|
||
*
|
||
* @fileOverview
|
||
* Lazy.js is a lazy evaluation library for JavaScript.
|
||
*
|
||
* This has been done before. For examples see:
|
||
*
|
||
* - [wu.js](http://fitzgen.github.io/wu.js/)
|
||
* - [Linq.js](http://linqjs.codeplex.com/)
|
||
* - [from.js](https://github.com/suckgamoni/fromjs/)
|
||
* - [IxJS](http://rx.codeplex.com/)
|
||
* - [sloth.js](http://rfw.name/sloth.js/)
|
||
*
|
||
* However, at least at present, Lazy.js is faster (on average) than any of
|
||
* those libraries. It is also more complete, with nearly all of the
|
||
* functionality of [Underscore](http://underscorejs.org/) and
|
||
* [Lo-Dash](http://lodash.com/).
|
||
*
|
||
* Finding your way around the code
|
||
* --------------------------------
|
||
*
|
||
* At the heart of Lazy.js is the {@link Sequence} object. You create an initial
|
||
* sequence using {@link Lazy}, which can accept an array, object, or string.
|
||
* You can then "chain" together methods from this sequence, creating a new
|
||
* sequence with each call.
|
||
*
|
||
* Here's an example:
|
||
*
|
||
* var data = getReallyBigArray();
|
||
*
|
||
* var statistics = Lazy(data)
|
||
* .map(transform)
|
||
* .filter(validate)
|
||
* .reduce(aggregate);
|
||
*
|
||
* {@link Sequence} is the foundation of other, more specific sequence types.
|
||
*
|
||
* An {@link ArrayLikeSequence} provides indexed access to its elements.
|
||
*
|
||
* An {@link ObjectLikeSequence} consists of key/value pairs.
|
||
*
|
||
* A {@link StringLikeSequence} is like a string (duh): actually, it is an
|
||
* {@link ArrayLikeSequence} whose elements happen to be characters.
|
||
*
|
||
* An {@link AsyncSequence} is special: it iterates over its elements
|
||
* asynchronously (so calling `each` generally begins an asynchronous loop and
|
||
* returns immediately).
|
||
*
|
||
* For more information
|
||
* --------------------
|
||
*
|
||
* I wrote a blog post that explains a little bit more about Lazy.js, which you
|
||
* can read [here](http://philosopherdeveloper.com/posts/introducing-lazy-js.html).
|
||
*
|
||
* You can also [create an issue on GitHub](https://github.com/dtao/lazy.js/issues)
|
||
* if you have any issues with the library. I work through them eventually.
|
||
*
|
||
* [@dtao](https://github.com/dtao)
|
||
*/
|
||
|
||
(function(root, factory) {
|
||
if (true) {
|
||
!(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
|
||
} else if (typeof exports === 'object') {
|
||
module.exports = factory();
|
||
} else {
|
||
root.Lazy = factory();
|
||
}
|
||
})(this, function(context) {
|
||
/**
|
||
* Wraps an object and returns a {@link Sequence}. For `null` or `undefined`,
|
||
* simply returns an empty sequence (see {@link Lazy.strict} for a stricter
|
||
* implementation).
|
||
*
|
||
* - For **arrays**, Lazy will create a sequence comprising the elements in
|
||
* the array (an {@link ArrayLikeSequence}).
|
||
* - For **objects**, Lazy will create a sequence of key/value pairs
|
||
* (an {@link ObjectLikeSequence}).
|
||
* - For **strings**, Lazy will create a sequence of characters (a
|
||
* {@link StringLikeSequence}).
|
||
*
|
||
* @public
|
||
* @param {Array|Object|string} source An array, object, or string to wrap.
|
||
* @returns {Sequence} The wrapped lazy object.
|
||
*
|
||
* @exampleHelpers
|
||
* // Utility functions to provide to all examples
|
||
* function increment(x) { return x + 1; }
|
||
* function isEven(x) { return x % 2 === 0; }
|
||
* function isPositive(x) { return x > 0; }
|
||
* function isNegative(x) { return x < 0; }
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 4]) // instanceof Lazy.ArrayLikeSequence
|
||
* Lazy({ foo: "bar" }) // instanceof Lazy.ObjectLikeSequence
|
||
* Lazy("hello, world!") // instanceof Lazy.StringLikeSequence
|
||
* Lazy() // sequence: []
|
||
* Lazy(null) // sequence: []
|
||
*/
|
||
function Lazy(source) {
|
||
if (source instanceof Array) {
|
||
return new ArrayWrapper(source);
|
||
|
||
} else if (typeof source === "string") {
|
||
return new StringWrapper(source);
|
||
|
||
} else if (source instanceof Sequence) {
|
||
return source;
|
||
}
|
||
|
||
if (Lazy.extensions) {
|
||
var extensions = Lazy.extensions, length = extensions.length, result;
|
||
while (!result && length--) {
|
||
result = extensions[length](source);
|
||
}
|
||
if (result) {
|
||
return result;
|
||
}
|
||
}
|
||
|
||
return new ObjectWrapper(source);
|
||
}
|
||
|
||
Lazy.VERSION = '0.4.2';
|
||
|
||
/*** Utility methods of questionable value ***/
|
||
|
||
Lazy.noop = function noop() {};
|
||
Lazy.identity = function identity(x) { return x; };
|
||
|
||
/**
|
||
* Provides a stricter version of {@link Lazy} which throws an error when
|
||
* attempting to wrap `null`, `undefined`, or numeric or boolean values as a
|
||
* sequence.
|
||
*
|
||
* @public
|
||
* @returns {Function} A stricter version of the {@link Lazy} helper function.
|
||
*
|
||
* @examples
|
||
* var Strict = Lazy.strict();
|
||
*
|
||
* Strict() // throws
|
||
* Strict(null) // throws
|
||
* Strict(true) // throws
|
||
* Strict(5) // throws
|
||
* Strict([1, 2, 3]) // instanceof Lazy.ArrayLikeSequence
|
||
* Strict({ foo: "bar" }) // instanceof Lazy.ObjectLikeSequence
|
||
* Strict("hello, world!") // instanceof Lazy.StringLikeSequence
|
||
*
|
||
* // Let's also ensure the static functions are still there.
|
||
* Strict.range(3) // sequence: [0, 1, 2]
|
||
* Strict.generate(Date.now) // instanceof Lazy.GeneratedSequence
|
||
*/
|
||
Lazy.strict = function strict() {
|
||
function StrictLazy(source) {
|
||
if (source == null) {
|
||
throw new Error("You cannot wrap null or undefined using Lazy.");
|
||
}
|
||
|
||
if (typeof source === "number" || typeof source === "boolean") {
|
||
throw new Error("You cannot wrap primitive values using Lazy.");
|
||
}
|
||
|
||
return Lazy(source);
|
||
};
|
||
|
||
Lazy(Lazy).each(function(property, name) {
|
||
StrictLazy[name] = property;
|
||
});
|
||
|
||
return StrictLazy;
|
||
};
|
||
|
||
/**
|
||
* The `Sequence` object provides a unified API encapsulating the notion of
|
||
* zero or more consecutive elements in a collection, stream, etc.
|
||
*
|
||
* Lazy evaluation
|
||
* ---------------
|
||
*
|
||
* Generally speaking, creating a sequence should not be an expensive operation,
|
||
* and should not iterate over an underlying source or trigger any side effects.
|
||
* This means that chaining together methods that return sequences incurs only
|
||
* the cost of creating the `Sequence` objects themselves and not the cost of
|
||
* iterating an underlying data source multiple times.
|
||
*
|
||
* The following code, for example, creates 4 sequences and does nothing with
|
||
* `source`:
|
||
*
|
||
* var seq = Lazy(source) // 1st sequence
|
||
* .map(func) // 2nd
|
||
* .filter(pred) // 3rd
|
||
* .reverse(); // 4th
|
||
*
|
||
* Lazy's convention is to hold off on iterating or otherwise *doing* anything
|
||
* (aside from creating `Sequence` objects) until you call `each`:
|
||
*
|
||
* seq.each(function(x) { console.log(x); });
|
||
*
|
||
* Defining custom sequences
|
||
* -------------------------
|
||
*
|
||
* Defining your own type of sequence is relatively simple:
|
||
*
|
||
* 1. Pass a *method name* and an object containing *function overrides* to
|
||
* {@link Sequence.define}. If the object includes a function called `init`,
|
||
* this function will be called upon initialization.
|
||
* 2. The object should include at least either a `getIterator` method or an
|
||
* `each` method. The former supports both asynchronous and synchronous
|
||
* iteration, but is slightly more cumbersome to implement. The latter
|
||
* supports synchronous iteration and can be automatically implemented in
|
||
* terms of the former. You can also implement both if you want, e.g. to
|
||
* optimize performance. For more info, see {@link Iterator} and
|
||
* {@link AsyncSequence}.
|
||
*
|
||
* As a trivial example, the following code defines a new method, `sample`,
|
||
* which randomly may or may not include each element from its parent.
|
||
*
|
||
* Lazy.Sequence.define("sample", {
|
||
* each: function(fn) {
|
||
* return this.parent.each(function(e) {
|
||
* // 50/50 chance of including this element.
|
||
* if (Math.random() > 0.5) {
|
||
* return fn(e);
|
||
* }
|
||
* });
|
||
* }
|
||
* });
|
||
*
|
||
* (Of course, the above could also easily have been implemented using
|
||
* {@link #filter} instead of creating a custom sequence. But I *did* say this
|
||
* was a trivial example, to be fair.)
|
||
*
|
||
* Now it will be possible to create this type of sequence from any parent
|
||
* sequence by calling the method name you specified. In other words, you can
|
||
* now do this:
|
||
*
|
||
* Lazy(arr).sample();
|
||
* Lazy(arr).map(func).sample();
|
||
* Lazy(arr).map(func).filter(pred).sample();
|
||
*
|
||
* Etc., etc.
|
||
*
|
||
* @public
|
||
* @constructor
|
||
*/
|
||
function Sequence() {}
|
||
|
||
/**
|
||
* Create a new constructor function for a type inheriting from `Sequence`.
|
||
*
|
||
* @public
|
||
* @param {string|Array.<string>} methodName The name(s) of the method(s) to be
|
||
* used for constructing the new sequence. The method will be attached to
|
||
* the `Sequence` prototype so that it can be chained with any other
|
||
* sequence methods, like {@link #map}, {@link #filter}, etc.
|
||
* @param {Object} overrides An object containing function overrides for this
|
||
* new sequence type. **Must** include either `getIterator` or `each` (or
|
||
* both). *May* include an `init` method as well. For these overrides,
|
||
* `this` will be the new sequence, and `this.parent` will be the base
|
||
* sequence from which the new sequence was constructed.
|
||
* @returns {Function} A constructor for a new type inheriting from `Sequence`.
|
||
*
|
||
* @examples
|
||
* // This sequence type logs every element to the specified logger as it
|
||
* // iterates over it.
|
||
* Lazy.Sequence.define("verbose", {
|
||
* init: function(logger) {
|
||
* this.logger = logger;
|
||
* },
|
||
*
|
||
* each: function(fn) {
|
||
* var logger = this.logger;
|
||
* return this.parent.each(function(e, i) {
|
||
* logger(e);
|
||
* return fn(e, i);
|
||
* });
|
||
* }
|
||
* });
|
||
*
|
||
* Lazy([1, 2, 3]).verbose(logger).each(Lazy.noop) // calls logger 3 times
|
||
*/
|
||
Sequence.define = function define(methodName, overrides) {
|
||
if (!overrides || (!overrides.getIterator && !overrides.each)) {
|
||
throw new Error("A custom sequence must implement *at least* getIterator or each!");
|
||
}
|
||
|
||
return defineSequenceType(Sequence, methodName, overrides);
|
||
};
|
||
|
||
/**
|
||
* Gets the number of elements in the sequence. In some cases, this may
|
||
* require eagerly evaluating the sequence.
|
||
*
|
||
* @public
|
||
* @returns {number} The number of elements in the sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3]).size(); // => 3
|
||
* Lazy([1, 2]).map(Lazy.identity).size(); // => 2
|
||
* Lazy([1, 2, 3]).reject(isEven).size(); // => 2
|
||
* Lazy([1, 2, 3]).take(1).size(); // => 1
|
||
* Lazy({ foo: 1, bar: 2 }).size(); // => 2
|
||
* Lazy('hello').size(); // => 5
|
||
*/
|
||
Sequence.prototype.size = function size() {
|
||
return this.getIndex().length();
|
||
};
|
||
|
||
/**
|
||
* Creates an {@link Iterator} object with two methods, `moveNext` -- returning
|
||
* true or false -- and `current` -- returning the current value.
|
||
*
|
||
* This method is used when asynchronously iterating over sequences. Any type
|
||
* inheriting from `Sequence` must implement this method or it can't support
|
||
* asynchronous iteration.
|
||
*
|
||
* Note that **this method is not intended to be used directly by application
|
||
* code.** Rather, it is intended as a means for implementors to potentially
|
||
* define custom sequence types that support either synchronous or
|
||
* asynchronous iteration.
|
||
*
|
||
* @public
|
||
* @returns {Iterator} An iterator object.
|
||
*
|
||
* @examples
|
||
* var iterator = Lazy([1, 2]).getIterator();
|
||
*
|
||
* iterator.moveNext(); // => true
|
||
* iterator.current(); // => 1
|
||
* iterator.moveNext(); // => true
|
||
* iterator.current(); // => 2
|
||
* iterator.moveNext(); // => false
|
||
*/
|
||
Sequence.prototype.getIterator = function getIterator() {
|
||
return new Iterator(this);
|
||
};
|
||
|
||
/**
|
||
* Gets the root sequence underlying the current chain of sequences.
|
||
*/
|
||
Sequence.prototype.root = function root() {
|
||
return this.parent.root();
|
||
};
|
||
|
||
/**
|
||
* Whether or not the current sequence is an asynchronous one. This is more
|
||
* accurate than checking `instanceof {@link AsyncSequence}` because, for
|
||
* example, `Lazy([1, 2, 3]).async().map(Lazy.identity)` returns a sequence
|
||
* that iterates asynchronously even though it's not an instance of
|
||
* `AsyncSequence`.
|
||
*
|
||
* @returns {boolean} Whether or not the current sequence is an asynchronous one.
|
||
*/
|
||
Sequence.prototype.isAsync = function isAsync() {
|
||
return this.parent ? this.parent.isAsync() : false;
|
||
};
|
||
|
||
/**
|
||
* Evaluates the sequence and produces the appropriate value (an array in most
|
||
* cases, an object for {@link ObjectLikeSequence}s or a string for
|
||
* {@link StringLikeSequence}s).
|
||
*
|
||
* @returns {Array|string|Object} The value resulting from fully evaluating
|
||
* the sequence.
|
||
*/
|
||
Sequence.prototype.value = function value() {
|
||
return this.toArray();
|
||
};
|
||
|
||
/**
|
||
* Applies the current transformation chain to a given source, returning the
|
||
* resulting value.
|
||
*
|
||
* @examples
|
||
* var sequence = Lazy([])
|
||
* .map(function(x) { return x * -1; })
|
||
* .filter(function(x) { return x % 2 === 0; });
|
||
*
|
||
* sequence.apply([1, 2, 3, 4]); // => [-2, -4]
|
||
*/
|
||
Sequence.prototype.apply = function apply(source) {
|
||
var root = this.root(),
|
||
previousSource = root.source,
|
||
result;
|
||
|
||
try {
|
||
root.source = source;
|
||
result = this.value();
|
||
} finally {
|
||
root.source = previousSource;
|
||
}
|
||
|
||
return result;
|
||
};
|
||
|
||
/**
|
||
* The Iterator object provides an API for iterating over a sequence.
|
||
*
|
||
* The purpose of the `Iterator` type is mainly to offer an agnostic way of
|
||
* iterating over a sequence -- either synchronous (i.e. with a `while` loop)
|
||
* or asynchronously (with recursive calls to either `setTimeout` or --- if
|
||
* available --- `setImmediate`). It is not intended to be used directly by
|
||
* application code.
|
||
*
|
||
* @public
|
||
* @constructor
|
||
* @param {Sequence} sequence The sequence to iterate over.
|
||
*/
|
||
function Iterator(sequence) {
|
||
this.sequence = sequence;
|
||
this.index = -1;
|
||
}
|
||
|
||
/**
|
||
* Gets the current item this iterator is pointing to.
|
||
*
|
||
* @public
|
||
* @returns {*} The current item.
|
||
*/
|
||
Iterator.prototype.current = function current() {
|
||
return this.cachedIndex && this.cachedIndex.get(this.index);
|
||
};
|
||
|
||
/**
|
||
* Moves the iterator to the next item in a sequence, if possible.
|
||
*
|
||
* @public
|
||
* @returns {boolean} True if the iterator is able to move to a new item, or else
|
||
* false.
|
||
*/
|
||
Iterator.prototype.moveNext = function moveNext() {
|
||
var cachedIndex = this.cachedIndex;
|
||
|
||
if (!cachedIndex) {
|
||
cachedIndex = this.cachedIndex = this.sequence.getIndex();
|
||
}
|
||
|
||
if (this.index >= cachedIndex.length() - 1) {
|
||
return false;
|
||
}
|
||
|
||
++this.index;
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* Creates an array snapshot of a sequence.
|
||
*
|
||
* Note that for indefinite sequences, this method may raise an exception or
|
||
* (worse) cause the environment to hang.
|
||
*
|
||
* @public
|
||
* @returns {Array} An array containing the current contents of the sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3]).toArray() // => [1, 2, 3]
|
||
*/
|
||
Sequence.prototype.toArray = function toArray() {
|
||
return this.reduce(function(arr, element) {
|
||
arr.push(element);
|
||
return arr;
|
||
}, []);
|
||
};
|
||
|
||
/**
|
||
* Provides an indexed view into the sequence.
|
||
*
|
||
* For sequences that are already indexed, this will simply return the
|
||
* sequence. For non-indexed sequences, this will eagerly evaluate the
|
||
* sequence.
|
||
*
|
||
* @returns {ArrayLikeSequence} A sequence containing the current contents of
|
||
* the sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3]).filter(isEven) // instanceof Lazy.Sequence
|
||
* Lazy([1, 2, 3]).filter(isEven).getIndex() // instanceof Lazy.ArrayLikeSequence
|
||
*/
|
||
Sequence.prototype.getIndex = function getIndex() {
|
||
return new ArrayWrapper(this.toArray());
|
||
};
|
||
|
||
/**
|
||
* Returns the element at the specified index. Note that, for sequences that
|
||
* are not {@link ArrayLikeSequence}s, this may require partially evaluating
|
||
* the sequence, iterating to reach the result. (In other words for such
|
||
* sequences this method is not O(1).)
|
||
*
|
||
* @public
|
||
* @param {number} i The index to access.
|
||
* @returns {*} The element.
|
||
*
|
||
*/
|
||
Sequence.prototype.get = function get(i) {
|
||
var element;
|
||
this.each(function(e, index) {
|
||
if (index === i) {
|
||
element = e;
|
||
return false;
|
||
}
|
||
});
|
||
return element;
|
||
};
|
||
|
||
/**
|
||
* Provides an indexed, memoized view into the sequence. This will cache the
|
||
* result whenever the sequence is first iterated, so that subsequent
|
||
* iterations will access the same element objects.
|
||
*
|
||
* @public
|
||
* @returns {ArrayLikeSequence} An indexed, memoized sequence containing this
|
||
* sequence's elements, cached after the first iteration.
|
||
*
|
||
* @example
|
||
* function createObject() { return new Object(); }
|
||
*
|
||
* var plain = Lazy.generate(createObject, 10),
|
||
* memoized = Lazy.generate(createObject, 10).memoize();
|
||
*
|
||
* plain.toArray()[0] === plain.toArray()[0]; // => false
|
||
* memoized.toArray()[0] === memoized.toArray()[0]; // => true
|
||
*/
|
||
Sequence.prototype.memoize = function memoize() {
|
||
return new MemoizedSequence(this);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function MemoizedSequence(parent) {
|
||
this.parent = parent;
|
||
}
|
||
|
||
// MemoizedSequence needs to have its prototype set up after ArrayLikeSequence
|
||
|
||
/**
|
||
* Creates an object from a sequence of key/value pairs.
|
||
*
|
||
* @public
|
||
* @returns {Object} An object with keys and values corresponding to the pairs
|
||
* of elements in the sequence.
|
||
*
|
||
* @examples
|
||
* var details = [
|
||
* ["first", "Dan"],
|
||
* ["last", "Tao"],
|
||
* ["age", 29]
|
||
* ];
|
||
*
|
||
* Lazy(details).toObject() // => { first: "Dan", last: "Tao", age: 29 }
|
||
*/
|
||
Sequence.prototype.toObject = function toObject() {
|
||
return this.reduce(function(object, pair) {
|
||
object[pair[0]] = pair[1];
|
||
return object;
|
||
}, {});
|
||
};
|
||
|
||
/**
|
||
* Iterates over this sequence and executes a function for every element.
|
||
*
|
||
* @public
|
||
* @aka forEach
|
||
* @param {Function} fn The function to call on each element in the sequence.
|
||
* Return false from the function to end the iteration.
|
||
* @returns {boolean} `true` if the iteration evaluated the entire sequence,
|
||
* or `false` if iteration was ended early.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3, 4]).each(fn) // calls fn 4 times
|
||
*/
|
||
Sequence.prototype.each = function each(fn) {
|
||
var iterator = this.getIterator(),
|
||
i = -1;
|
||
|
||
while (iterator.moveNext()) {
|
||
if (fn(iterator.current(), ++i) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
Sequence.prototype.forEach = function forEach(fn) {
|
||
return this.each(fn);
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence whose values are calculated by passing this sequence's
|
||
* elements through some mapping function.
|
||
*
|
||
* @public
|
||
* @aka collect
|
||
* @param {Function} mapFn The mapping function used to project this sequence's
|
||
* elements onto a new sequence. This function takes up to two arguments:
|
||
* the element, and the current index.
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* function addIndexToValue(e, i) { return e + i; }
|
||
*
|
||
* Lazy([]).map(increment) // sequence: []
|
||
* Lazy([1, 2, 3]).map(increment) // sequence: [2, 3, 4]
|
||
* Lazy([1, 2, 3]).map(addIndexToValue) // sequence: [1, 3, 5]
|
||
*
|
||
* @benchmarks
|
||
* function increment(x) { return x + 1; }
|
||
*
|
||
* var smArr = Lazy.range(10).toArray(),
|
||
* lgArr = Lazy.range(100).toArray();
|
||
*
|
||
* Lazy(smArr).map(increment).each(Lazy.noop) // lazy - 10 elements
|
||
* Lazy(lgArr).map(increment).each(Lazy.noop) // lazy - 100 elements
|
||
* _.each(_.map(smArr, increment), _.noop) // lodash - 10 elements
|
||
* _.each(_.map(lgArr, increment), _.noop) // lodash - 100 elements
|
||
*/
|
||
Sequence.prototype.map = function map(mapFn) {
|
||
return new MappedSequence(this, createCallback(mapFn));
|
||
};
|
||
|
||
Sequence.prototype.collect = function collect(mapFn) {
|
||
return this.map(mapFn);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function MappedSequence(parent, mapFn) {
|
||
this.parent = parent;
|
||
this.mapFn = mapFn;
|
||
}
|
||
|
||
MappedSequence.prototype = new Sequence();
|
||
|
||
MappedSequence.prototype.getIterator = function getIterator() {
|
||
return new MappingIterator(this.parent, this.mapFn);
|
||
};
|
||
|
||
MappedSequence.prototype.each = function each(fn) {
|
||
var mapFn = this.mapFn;
|
||
return this.parent.each(function(e, i) {
|
||
return fn(mapFn(e, i), i);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function MappingIterator(sequence, mapFn) {
|
||
this.iterator = sequence.getIterator();
|
||
this.mapFn = mapFn;
|
||
this.index = -1;
|
||
}
|
||
|
||
MappingIterator.prototype.current = function current() {
|
||
return this.mapFn(this.iterator.current(), this.index);
|
||
};
|
||
|
||
MappingIterator.prototype.moveNext = function moveNext() {
|
||
if (this.iterator.moveNext()) {
|
||
++this.index;
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence whose values are calculated by accessing the specified
|
||
* property from each element in this sequence.
|
||
*
|
||
* @public
|
||
* @param {string} propertyName The name of the property to access for every
|
||
* element in this sequence.
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* var people = [
|
||
* { first: "Dan", last: "Tao" },
|
||
* { first: "Bob", last: "Smith" }
|
||
* ];
|
||
*
|
||
* Lazy(people).pluck("last") // sequence: ["Tao", "Smith"]
|
||
*/
|
||
Sequence.prototype.pluck = function pluck(property) {
|
||
return this.map(property);
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence whose values are calculated by invoking the specified
|
||
* function on each element in this sequence.
|
||
*
|
||
* @public
|
||
* @param {string} methodName The name of the method to invoke for every element
|
||
* in this sequence.
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* function Person(first, last) {
|
||
* this.fullName = function fullName() {
|
||
* return first + " " + last;
|
||
* };
|
||
* }
|
||
*
|
||
* var people = [
|
||
* new Person("Dan", "Tao"),
|
||
* new Person("Bob", "Smith")
|
||
* ];
|
||
*
|
||
* Lazy(people).invoke("fullName") // sequence: ["Dan Tao", "Bob Smith"]
|
||
*/
|
||
Sequence.prototype.invoke = function invoke(methodName) {
|
||
return this.map(function(e) {
|
||
return e[methodName]();
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence whose values are the elements of this sequence which
|
||
* satisfy the specified predicate.
|
||
*
|
||
* @public
|
||
* @aka select
|
||
* @param {Function} filterFn The predicate to call on each element in this
|
||
* sequence, which returns true if the element should be included.
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* var numbers = [1, 2, 3, 4, 5, 6];
|
||
*
|
||
* Lazy(numbers).filter(isEven) // sequence: [2, 4, 6]
|
||
*
|
||
* @benchmarks
|
||
* function isEven(x) { return x % 2 === 0; }
|
||
*
|
||
* var smArr = Lazy.range(10).toArray(),
|
||
* lgArr = Lazy.range(100).toArray();
|
||
*
|
||
* Lazy(smArr).filter(isEven).each(Lazy.noop) // lazy - 10 elements
|
||
* Lazy(lgArr).filter(isEven).each(Lazy.noop) // lazy - 100 elements
|
||
* _.each(_.filter(smArr, isEven), _.noop) // lodash - 10 elements
|
||
* _.each(_.filter(lgArr, isEven), _.noop) // lodash - 100 elements
|
||
*/
|
||
Sequence.prototype.filter = function filter(filterFn) {
|
||
return new FilteredSequence(this, createCallback(filterFn));
|
||
};
|
||
|
||
Sequence.prototype.select = function select(filterFn) {
|
||
return this.filter(filterFn);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function FilteredSequence(parent, filterFn) {
|
||
this.parent = parent;
|
||
this.filterFn = filterFn;
|
||
}
|
||
|
||
FilteredSequence.prototype = new Sequence();
|
||
|
||
FilteredSequence.prototype.getIterator = function getIterator() {
|
||
return new FilteringIterator(this.parent, this.filterFn);
|
||
};
|
||
|
||
FilteredSequence.prototype.each = function each(fn) {
|
||
var filterFn = this.filterFn,
|
||
j = 0;
|
||
|
||
return this.parent.each(function(e, i) {
|
||
if (filterFn(e, i)) {
|
||
return fn(e, j++);
|
||
}
|
||
});
|
||
};
|
||
|
||
FilteredSequence.prototype.reverse = function reverse() {
|
||
return this.parent.reverse().filter(this.filterFn);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function FilteringIterator(sequence, filterFn) {
|
||
this.iterator = sequence.getIterator();
|
||
this.filterFn = filterFn;
|
||
this.index = 0;
|
||
}
|
||
|
||
FilteringIterator.prototype.current = function current() {
|
||
return this.value;
|
||
};
|
||
|
||
FilteringIterator.prototype.moveNext = function moveNext() {
|
||
var iterator = this.iterator,
|
||
filterFn = this.filterFn,
|
||
value;
|
||
|
||
while (iterator.moveNext()) {
|
||
value = iterator.current();
|
||
if (filterFn(value, this.index++)) {
|
||
this.value = value;
|
||
return true;
|
||
}
|
||
}
|
||
|
||
this.value = undefined;
|
||
return false;
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence whose values exclude the elements of this sequence
|
||
* identified by the specified predicate.
|
||
*
|
||
* @public
|
||
* @param {Function} rejectFn The predicate to call on each element in this
|
||
* sequence, which returns true if the element should be omitted.
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3, 4, 5]).reject(isEven) // sequence: [1, 3, 5]
|
||
* Lazy([{ foo: 1 }, { bar: 2 }]).reject('foo') // sequence: [{ bar: 2 }]
|
||
* Lazy([{ foo: 1 }, { foo: 2 }]).reject({ foo: 2 }) // sequence: [{ foo: 1 }]
|
||
*/
|
||
Sequence.prototype.reject = function reject(rejectFn) {
|
||
rejectFn = createCallback(rejectFn);
|
||
return this.filter(function(e) { return !rejectFn(e); });
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence whose values have the specified type, as determined
|
||
* by the `typeof` operator.
|
||
*
|
||
* @public
|
||
* @param {string} type The type of elements to include from the underlying
|
||
* sequence, i.e. where `typeof [element] === [type]`.
|
||
* @returns {Sequence} The new sequence, comprising elements of the specified
|
||
* type.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 'foo', 'bar']).ofType('number') // sequence: [1, 2]
|
||
* Lazy([1, 2, 'foo', 'bar']).ofType('string') // sequence: ['foo', 'bar']
|
||
* Lazy([1, 2, 'foo', 'bar']).ofType('boolean') // sequence: []
|
||
*/
|
||
Sequence.prototype.ofType = function ofType(type) {
|
||
return this.filter(function(e) { return typeof e === type; });
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence whose values are the elements of this sequence with
|
||
* property names and values matching those of the specified object.
|
||
*
|
||
* @public
|
||
* @param {Object} properties The properties that should be found on every
|
||
* element that is to be included in this sequence.
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* var people = [
|
||
* { first: "Dan", last: "Tao" },
|
||
* { first: "Bob", last: "Smith" }
|
||
* ];
|
||
*
|
||
* Lazy(people).where({ first: "Dan" }) // sequence: [{ first: "Dan", last: "Tao" }]
|
||
*
|
||
* @benchmarks
|
||
* var animals = ["dog", "cat", "mouse", "horse", "pig", "snake"];
|
||
*
|
||
* Lazy(animals).where({ length: 3 }).each(Lazy.noop) // lazy
|
||
* _.each(_.where(animals, { length: 3 }), _.noop) // lodash
|
||
*/
|
||
Sequence.prototype.where = function where(properties) {
|
||
return this.filter(properties);
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence with the same elements as this one, but to be iterated
|
||
* in the opposite order.
|
||
*
|
||
* Note that in some (but not all) cases, the only way to create such a sequence
|
||
* may require iterating the entire underlying source when `each` is called.
|
||
*
|
||
* @public
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3]).reverse() // sequence: [3, 2, 1]
|
||
* Lazy([]).reverse() // sequence: []
|
||
*/
|
||
Sequence.prototype.reverse = function reverse() {
|
||
return new ReversedSequence(this);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function ReversedSequence(parent) {
|
||
this.parent = parent;
|
||
}
|
||
|
||
ReversedSequence.prototype = new Sequence();
|
||
|
||
ReversedSequence.prototype.getIterator = function getIterator() {
|
||
return new ReversedIterator(this.parent);
|
||
};
|
||
|
||
/**
|
||
* @constuctor
|
||
*/
|
||
function ReversedIterator(sequence) {
|
||
this.sequence = sequence;
|
||
}
|
||
|
||
ReversedIterator.prototype.current = function current() {
|
||
return this.getIndex().get(this.index);
|
||
};
|
||
|
||
ReversedIterator.prototype.moveNext = function moveNext() {
|
||
var index = this.getIndex(),
|
||
length = index.length();
|
||
|
||
if (typeof this.index === "undefined") {
|
||
this.index = length;
|
||
}
|
||
|
||
return (--this.index >= 0);
|
||
};
|
||
|
||
ReversedIterator.prototype.getIndex = function getIndex() {
|
||
if (!this.cachedIndex) {
|
||
this.cachedIndex = this.sequence.getIndex();
|
||
}
|
||
|
||
return this.cachedIndex;
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence with all of the elements of this one, plus those of
|
||
* the given array(s).
|
||
*
|
||
* @public
|
||
* @param {...*} var_args One or more values (or arrays of values) to use for
|
||
* additional items after this sequence.
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* var left = [1, 2, 3];
|
||
* var right = [4, 5, 6];
|
||
*
|
||
* Lazy(left).concat(right) // sequence: [1, 2, 3, 4, 5, 6]
|
||
* Lazy(left).concat(Lazy(right)) // sequence: [1, 2, 3, 4, 5, 6]
|
||
* Lazy(left).concat(right, [7, 8]) // sequence: [1, 2, 3, 4, 5, 6, 7, 8]
|
||
*/
|
||
Sequence.prototype.concat = function concat(var_args) {
|
||
return new ConcatenatedSequence(this, arraySlice.call(arguments, 0));
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function ConcatenatedSequence(parent, arrays) {
|
||
this.parent = parent;
|
||
this.arrays = arrays;
|
||
}
|
||
|
||
ConcatenatedSequence.prototype = new Sequence();
|
||
|
||
ConcatenatedSequence.prototype.each = function each(fn) {
|
||
var done = false,
|
||
i = 0;
|
||
|
||
this.parent.each(function(e) {
|
||
if (fn(e, i++) === false) {
|
||
done = true;
|
||
return false;
|
||
}
|
||
});
|
||
|
||
if (!done) {
|
||
Lazy(this.arrays).flatten().each(function(e) {
|
||
if (fn(e, i++) === false) {
|
||
return false;
|
||
}
|
||
});
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence comprising the first N elements from this sequence, OR
|
||
* (if N is `undefined`) simply returns the first element of this sequence.
|
||
*
|
||
* @public
|
||
* @aka head, take
|
||
* @param {number=} count The number of elements to take from this sequence. If
|
||
* this value exceeds the length of the sequence, the resulting sequence
|
||
* will be essentially the same as this one.
|
||
* @returns {*} The new sequence (or the first element from this sequence if
|
||
* no count was given).
|
||
*
|
||
* @examples
|
||
* function powerOfTwo(exp) {
|
||
* return Math.pow(2, exp);
|
||
* }
|
||
*
|
||
* Lazy.generate(powerOfTwo).first() // => 1
|
||
* Lazy.generate(powerOfTwo).first(5) // sequence: [1, 2, 4, 8, 16]
|
||
* Lazy.generate(powerOfTwo).skip(2).first() // => 4
|
||
* Lazy.generate(powerOfTwo).skip(2).first(2) // sequence: [4, 8]
|
||
*/
|
||
Sequence.prototype.first = function first(count) {
|
||
if (typeof count === "undefined") {
|
||
return getFirst(this);
|
||
}
|
||
return new TakeSequence(this, count);
|
||
};
|
||
|
||
Sequence.prototype.head =
|
||
Sequence.prototype.take = function (count) {
|
||
return this.first(count);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function TakeSequence(parent, count) {
|
||
this.parent = parent;
|
||
this.count = count;
|
||
}
|
||
|
||
TakeSequence.prototype = new Sequence();
|
||
|
||
TakeSequence.prototype.getIterator = function getIterator() {
|
||
return new TakeIterator(this.parent, this.count);
|
||
};
|
||
|
||
TakeSequence.prototype.each = function each(fn) {
|
||
var count = this.count,
|
||
i = 0;
|
||
|
||
var result;
|
||
var handle = this.parent.each(function(e) {
|
||
if (i < count) { result = fn(e, i++); }
|
||
if (i >= count) { return false; }
|
||
return result;
|
||
});
|
||
|
||
if (handle instanceof AsyncHandle) {
|
||
return handle;
|
||
}
|
||
|
||
return i === count && result !== false;
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function TakeIterator(sequence, count) {
|
||
this.iterator = sequence.getIterator();
|
||
this.count = count;
|
||
}
|
||
|
||
TakeIterator.prototype.current = function current() {
|
||
return this.iterator.current();
|
||
};
|
||
|
||
TakeIterator.prototype.moveNext = function moveNext() {
|
||
return ((--this.count >= 0) && this.iterator.moveNext());
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence comprising the elements from the head of this sequence
|
||
* that satisfy some predicate. Once an element is encountered that doesn't
|
||
* satisfy the predicate, iteration will stop.
|
||
*
|
||
* @public
|
||
* @param {Function} predicate
|
||
* @returns {Sequence} The new sequence
|
||
*
|
||
* @examples
|
||
* function lessThan(x) {
|
||
* return function(y) {
|
||
* return y < x;
|
||
* };
|
||
* }
|
||
*
|
||
* Lazy([1, 2, 3, 4]).takeWhile(lessThan(3)) // sequence: [1, 2]
|
||
* Lazy([1, 2, 3, 4]).takeWhile(lessThan(0)) // sequence: []
|
||
*/
|
||
Sequence.prototype.takeWhile = function takeWhile(predicate) {
|
||
return new TakeWhileSequence(this, predicate);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function TakeWhileSequence(parent, predicate) {
|
||
this.parent = parent;
|
||
this.predicate = predicate;
|
||
}
|
||
|
||
TakeWhileSequence.prototype = new Sequence();
|
||
|
||
TakeWhileSequence.prototype.each = function each(fn) {
|
||
var predicate = this.predicate,
|
||
finished = false,
|
||
j = 0;
|
||
|
||
var result = this.parent.each(function(e, i) {
|
||
if (!predicate(e, i)) {
|
||
finished = true;
|
||
return false;
|
||
}
|
||
|
||
return fn(e, j++);
|
||
});
|
||
|
||
if (result instanceof AsyncHandle) {
|
||
return result;
|
||
}
|
||
|
||
return finished;
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence comprising all but the last N elements of this
|
||
* sequence.
|
||
*
|
||
* @public
|
||
* @param {number=} count The number of items to omit from the end of the
|
||
* sequence (defaults to 1).
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3, 4]).initial() // sequence: [1, 2, 3]
|
||
* Lazy([1, 2, 3, 4]).initial(2) // sequence: [1, 2]
|
||
* Lazy([1, 2, 3]).filter(Lazy.identity).initial() // sequence: [1, 2]
|
||
*/
|
||
Sequence.prototype.initial = function initial(count) {
|
||
return new InitialSequence(this, count);
|
||
};
|
||
|
||
function InitialSequence(parent, count) {
|
||
this.parent = parent;
|
||
this.count = typeof count === "number" ? count : 1;
|
||
}
|
||
|
||
InitialSequence.prototype = new Sequence();
|
||
|
||
InitialSequence.prototype.each = function each(fn) {
|
||
var index = this.parent.getIndex();
|
||
return index.take(index.length() - this.count).each(fn);
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence comprising the last N elements of this sequence, OR
|
||
* (if N is `undefined`) simply returns the last element of this sequence.
|
||
*
|
||
* @public
|
||
* @param {number=} count The number of items to take from the end of the
|
||
* sequence.
|
||
* @returns {*} The new sequence (or the last element from this sequence
|
||
* if no count was given).
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3]).last() // => 3
|
||
* Lazy([1, 2, 3]).last(2) // sequence: [2, 3]
|
||
* Lazy([1, 2, 3]).filter(isEven).last(2) // sequence: [2]
|
||
*/
|
||
Sequence.prototype.last = function last(count) {
|
||
if (typeof count === "undefined") {
|
||
return this.reverse().first();
|
||
}
|
||
return this.reverse().take(count).reverse();
|
||
};
|
||
|
||
/**
|
||
* Returns the first element in this sequence with property names and values
|
||
* matching those of the specified object.
|
||
*
|
||
* @public
|
||
* @param {Object} properties The properties that should be found on some
|
||
* element in this sequence.
|
||
* @returns {*} The found element, or `undefined` if none exists in this
|
||
* sequence.
|
||
*
|
||
* @examples
|
||
* var words = ["foo", "bar"];
|
||
*
|
||
* Lazy(words).findWhere({ 0: "f" }); // => "foo"
|
||
* Lazy(words).findWhere({ 0: "z" }); // => undefined
|
||
*/
|
||
Sequence.prototype.findWhere = function findWhere(properties) {
|
||
return this.where(properties).first();
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence comprising all but the first N elements of this
|
||
* sequence.
|
||
*
|
||
* @public
|
||
* @aka skip, tail, rest
|
||
* @param {number=} count The number of items to omit from the beginning of the
|
||
* sequence (defaults to 1).
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3, 4]).rest() // sequence: [2, 3, 4]
|
||
* Lazy([1, 2, 3, 4]).rest(0) // sequence: [1, 2, 3, 4]
|
||
* Lazy([1, 2, 3, 4]).rest(2) // sequence: [3, 4]
|
||
* Lazy([1, 2, 3, 4]).rest(5) // sequence: []
|
||
*/
|
||
Sequence.prototype.rest = function rest(count) {
|
||
return new DropSequence(this, count);
|
||
};
|
||
|
||
Sequence.prototype.skip =
|
||
Sequence.prototype.tail =
|
||
Sequence.prototype.drop = function drop(count) {
|
||
return this.rest(count);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function DropSequence(parent, count) {
|
||
this.parent = parent;
|
||
this.count = typeof count === "number" ? count : 1;
|
||
}
|
||
|
||
DropSequence.prototype = new Sequence();
|
||
|
||
DropSequence.prototype.each = function each(fn) {
|
||
var count = this.count,
|
||
dropped = 0,
|
||
i = 0;
|
||
|
||
return this.parent.each(function(e) {
|
||
if (dropped++ < count) { return; }
|
||
return fn(e, i++);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence comprising the elements from this sequence *after*
|
||
* those that satisfy some predicate. The sequence starts with the first
|
||
* element that does not match the predicate.
|
||
*
|
||
* @public
|
||
* @aka skipWhile
|
||
* @param {Function} predicate
|
||
* @returns {Sequence} The new sequence
|
||
*/
|
||
Sequence.prototype.dropWhile = function dropWhile(predicate) {
|
||
return new DropWhileSequence(this, predicate);
|
||
};
|
||
|
||
Sequence.prototype.skipWhile = function skipWhile(predicate) {
|
||
return this.dropWhile(predicate);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function DropWhileSequence(parent, predicate) {
|
||
this.parent = parent;
|
||
this.predicate = predicate;
|
||
}
|
||
|
||
DropWhileSequence.prototype = new Sequence();
|
||
|
||
DropWhileSequence.prototype.each = function each(fn) {
|
||
var predicate = this.predicate,
|
||
done = false;
|
||
|
||
return this.parent.each(function(e) {
|
||
if (!done) {
|
||
if (predicate(e)) {
|
||
return;
|
||
}
|
||
|
||
done = true;
|
||
}
|
||
|
||
return fn(e);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence with the same elements as this one, but ordered
|
||
* using the specified comparison function.
|
||
*
|
||
* This has essentially the same behavior as calling
|
||
* [`Array#sort`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort),
|
||
* but obviously instead of modifying the collection it returns a new
|
||
* {@link Sequence} object.
|
||
*
|
||
* @public
|
||
* @param {Function=} sortFn The function used to compare elements in the
|
||
* sequence. The function will be passed two elements and should return:
|
||
* - 1 if the first is greater
|
||
* - -1 if the second is greater
|
||
* - 0 if the two values are the same
|
||
* @param {boolean} descending Whether or not the resulting sequence should be
|
||
* in descending order (defaults to `false`).
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([5, 10, 1]).sort() // sequence: [1, 5, 10]
|
||
* Lazy(['foo', 'bar']).sort() // sequence: ['bar', 'foo']
|
||
* Lazy(['b', 'c', 'a']).sort(null, true) // sequence: ['c', 'b', 'a']
|
||
* Lazy([5, 10, 1]).sort(null, true) // sequence: [10, 5, 1]
|
||
*
|
||
* // Sorting w/ custom comparison function
|
||
* Lazy(['a', 'ab', 'aa', 'ba', 'b', 'abc']).sort(function compare(x, y) {
|
||
* if (x.length && (x.length !== y.length)) { return compare(x.length, y.length); }
|
||
* if (x === y) { return 0; }
|
||
* return x > y ? 1 : -1;
|
||
* });
|
||
* // => sequence: ['a', 'b', 'aa', 'ab', 'ba', 'abc']
|
||
*/
|
||
Sequence.prototype.sort = function sort(sortFn, descending) {
|
||
sortFn || (sortFn = compare);
|
||
if (descending) { sortFn = reverseArguments(sortFn); }
|
||
return new SortedSequence(this, sortFn);
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence with the same elements as this one, but ordered by
|
||
* the results of the given function.
|
||
*
|
||
* You can pass:
|
||
*
|
||
* - a *string*, to sort by the named property
|
||
* - a function, to sort by the result of calling the function on each element
|
||
*
|
||
* @public
|
||
* @param {Function} sortFn The function to call on the elements in this
|
||
* sequence, in order to sort them.
|
||
* @param {boolean} descending Whether or not the resulting sequence should be
|
||
* in descending order (defaults to `false`).
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* function population(country) {
|
||
* return country.pop;
|
||
* }
|
||
*
|
||
* function area(country) {
|
||
* return country.sqkm;
|
||
* }
|
||
*
|
||
* var countries = [
|
||
* { name: "USA", pop: 320000000, sqkm: 9600000 },
|
||
* { name: "Brazil", pop: 194000000, sqkm: 8500000 },
|
||
* { name: "Nigeria", pop: 174000000, sqkm: 924000 },
|
||
* { name: "China", pop: 1350000000, sqkm: 9700000 },
|
||
* { name: "Russia", pop: 143000000, sqkm: 17000000 },
|
||
* { name: "Australia", pop: 23000000, sqkm: 7700000 }
|
||
* ];
|
||
*
|
||
* Lazy(countries).sortBy(population).last(3).pluck('name') // sequence: ["Brazil", "USA", "China"]
|
||
* Lazy(countries).sortBy(area).last(3).pluck('name') // sequence: ["USA", "China", "Russia"]
|
||
* Lazy(countries).sortBy(area, true).first(3).pluck('name') // sequence: ["Russia", "China", "USA"]
|
||
*
|
||
* @benchmarks
|
||
* var randoms = Lazy.generate(Math.random).take(100).toArray();
|
||
*
|
||
* Lazy(randoms).sortBy(Lazy.identity).each(Lazy.noop) // lazy
|
||
* _.each(_.sortBy(randoms, Lazy.identity), _.noop) // lodash
|
||
*/
|
||
Sequence.prototype.sortBy = function sortBy(sortFn, descending) {
|
||
sortFn = createComparator(sortFn);
|
||
if (descending) { sortFn = reverseArguments(sortFn); }
|
||
return new SortedSequence(this, sortFn);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function SortedSequence(parent, sortFn) {
|
||
this.parent = parent;
|
||
this.sortFn = sortFn;
|
||
}
|
||
|
||
SortedSequence.prototype = new Sequence();
|
||
|
||
SortedSequence.prototype.each = function each(fn) {
|
||
var sortFn = this.sortFn,
|
||
result = this.parent.toArray();
|
||
|
||
result.sort(sortFn);
|
||
|
||
return forEach(result, fn);
|
||
};
|
||
|
||
/**
|
||
* @examples
|
||
* var items = [{ a: 4 }, { a: 3 }, { a: 5 }];
|
||
*
|
||
* Lazy(items).sortBy('a').reverse();
|
||
* // => sequence: [{ a: 5 }, { a: 4 }, { a: 3 }]
|
||
*
|
||
* Lazy(items).sortBy('a').reverse().reverse();
|
||
* // => sequence: [{ a: 3 }, { a: 4 }, { a: 5 }]
|
||
*/
|
||
SortedSequence.prototype.reverse = function reverse() {
|
||
return new SortedSequence(this.parent, reverseArguments(this.sortFn));
|
||
};
|
||
|
||
/**
|
||
* Creates a new {@link ObjectLikeSequence} comprising the elements in this
|
||
* one, grouped together according to some key. The value associated with each
|
||
* key in the resulting object-like sequence is an array containing all of
|
||
* the elements in this sequence with that key.
|
||
*
|
||
* @public
|
||
* @param {Function|string} keyFn The function to call on the elements in this
|
||
* sequence to obtain a key by which to group them, or a string representing
|
||
* a parameter to read from all the elements in this sequence.
|
||
* @param {Function|string} valFn (Optional) The function to call on the elements
|
||
* in this sequence to assign to the value for each instance to appear in the
|
||
* group, or a string representing a parameter to read from all the elements
|
||
* in this sequence.
|
||
* @returns {ObjectLikeSequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* function oddOrEven(x) {
|
||
* return x % 2 === 0 ? 'even' : 'odd';
|
||
* }
|
||
* function square(x) {
|
||
* return x*x;
|
||
* }
|
||
*
|
||
* var numbers = [1, 2, 3, 4, 5];
|
||
*
|
||
* Lazy(numbers).groupBy(oddOrEven) // sequence: { odd: [1, 3, 5], even: [2, 4] }
|
||
* Lazy(numbers).groupBy(oddOrEven).get("odd") // => [1, 3, 5]
|
||
* Lazy(numbers).groupBy(oddOrEven).get("foo") // => undefined
|
||
* Lazy(numbers).groupBy(oddOrEven, square).get("even") // => [4, 16]
|
||
*
|
||
* Lazy([
|
||
* { name: 'toString' },
|
||
* { name: 'toString' }
|
||
* ]).groupBy('name');
|
||
* // => sequence: {
|
||
* 'toString': [
|
||
* { name: 'toString' },
|
||
* { name: 'toString' }
|
||
* ]
|
||
* }
|
||
*/
|
||
Sequence.prototype.groupBy = function groupBy(keyFn, valFn) {
|
||
return new GroupedSequence(this, keyFn, valFn);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function GroupedSequence(parent, keyFn, valFn) {
|
||
this.parent = parent;
|
||
this.keyFn = keyFn;
|
||
this.valFn = valFn;
|
||
}
|
||
|
||
// GroupedSequence must have its prototype set after ObjectLikeSequence has
|
||
// been fully initialized.
|
||
|
||
/**
|
||
* Creates a new {@link ObjectLikeSequence} comprising the elements in this
|
||
* one, indexed according to some key.
|
||
*
|
||
* @public
|
||
* @param {Function|string} keyFn The function to call on the elements in this
|
||
* sequence to obtain a key by which to index them, or a string
|
||
* representing a property to read from all the elements in this sequence.
|
||
* @param {Function|string} valFn (Optional) The function to call on the elements
|
||
* in this sequence to assign to the value of the indexed object, or a string
|
||
* representing a parameter to read from all the elements in this sequence.
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* var people = [
|
||
* { name: 'Bob', age: 25 },
|
||
* { name: 'Fred', age: 34 }
|
||
* ];
|
||
*
|
||
* var bob = people[0],
|
||
* fred = people[1];
|
||
*
|
||
* Lazy(people).indexBy('name') // sequence: { 'Bob': bob, 'Fred': fred }
|
||
* Lazy(people).indexBy('name', 'age') // sequence: { 'Bob': 25, 'Fred': 34 }
|
||
*/
|
||
Sequence.prototype.indexBy = function(keyFn, valFn) {
|
||
return new IndexedSequence(this, keyFn, valFn);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function IndexedSequence(parent, keyFn, valFn) {
|
||
this.parent = parent;
|
||
this.keyFn = keyFn;
|
||
this.valFn = valFn;
|
||
}
|
||
|
||
// IndexedSequence must have its prototype set after ObjectLikeSequence has
|
||
// been fully initialized.
|
||
|
||
/**
|
||
* Creates a new {@link ObjectLikeSequence} containing the unique keys of all
|
||
* the elements in this sequence, each paired with the number of elements
|
||
* in this sequence having that key.
|
||
*
|
||
* @public
|
||
* @param {Function|string} keyFn The function to call on the elements in this
|
||
* sequence to obtain a key by which to count them, or a string representing
|
||
* a parameter to read from all the elements in this sequence.
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* function oddOrEven(x) {
|
||
* return x % 2 === 0 ? 'even' : 'odd';
|
||
* }
|
||
*
|
||
* var numbers = [1, 2, 3, 4, 5];
|
||
*
|
||
* Lazy(numbers).countBy(oddOrEven) // sequence: { odd: 3, even: 2 }
|
||
* Lazy(numbers).countBy(oddOrEven).get("odd") // => 3
|
||
* Lazy(numbers).countBy(oddOrEven).get("foo") // => undefined
|
||
*/
|
||
Sequence.prototype.countBy = function countBy(keyFn) {
|
||
return new CountedSequence(this, keyFn);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function CountedSequence(parent, keyFn) {
|
||
this.parent = parent;
|
||
this.keyFn = keyFn;
|
||
}
|
||
|
||
// CountedSequence, like GroupedSequence, must have its prototype set after
|
||
// ObjectLikeSequence has been fully initialized.
|
||
|
||
/**
|
||
* Creates a new sequence with every unique element from this one appearing
|
||
* exactly once (i.e., with duplicates removed).
|
||
*
|
||
* @public
|
||
* @aka unique
|
||
* @param {Function} keyFn An optional function to produce the key for each
|
||
* object. This key is then tested for uniqueness as opposed to the
|
||
* object reference.
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 2, 3, 3, 3]).uniq() // sequence: [1, 2, 3]
|
||
* Lazy([{ name: 'mike' },
|
||
* { name: 'sarah' },
|
||
* { name: 'mike' }
|
||
* ]).uniq('name')
|
||
* // sequence: [{ name: 'mike' }, { name: 'sarah' }]
|
||
*
|
||
* @benchmarks
|
||
* function randomOf(array) {
|
||
* return function() {
|
||
* return array[Math.floor(Math.random() * array.length)];
|
||
* };
|
||
* }
|
||
*
|
||
* var mostUnique = Lazy.generate(randomOf(_.range(100)), 100).toArray(),
|
||
* someUnique = Lazy.generate(randomOf(_.range(50)), 100).toArray(),
|
||
* mostDupes = Lazy.generate(randomOf(_.range(5)), 100).toArray();
|
||
*
|
||
* Lazy(mostUnique).uniq().each(Lazy.noop) // lazy - mostly unique elements
|
||
* Lazy(someUnique).uniq().each(Lazy.noop) // lazy - some unique elements
|
||
* Lazy(mostDupes).uniq().each(Lazy.noop) // lazy - mostly duplicate elements
|
||
* _.each(_.uniq(mostUnique), _.noop) // lodash - mostly unique elements
|
||
* _.each(_.uniq(someUnique), _.noop) // lodash - some unique elements
|
||
* _.each(_.uniq(mostDupes), _.noop) // lodash - mostly duplicate elements
|
||
*/
|
||
Sequence.prototype.uniq = function uniq(keyFn) {
|
||
return new UniqueSequence(this, keyFn);
|
||
};
|
||
|
||
Sequence.prototype.unique = function unique(keyFn) {
|
||
return this.uniq(keyFn);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function UniqueSequence(parent, keyFn) {
|
||
this.parent = parent;
|
||
this.keyFn = keyFn;
|
||
}
|
||
|
||
UniqueSequence.prototype = new Sequence();
|
||
|
||
UniqueSequence.prototype.each = function each(fn) {
|
||
var cache = new Set(),
|
||
keyFn = this.keyFn,
|
||
i = 0;
|
||
|
||
if (keyFn) {
|
||
keyFn = createCallback(keyFn);
|
||
return this.parent.each(function(e) {
|
||
if (cache.add(keyFn(e))) {
|
||
return fn(e, i++);
|
||
}
|
||
});
|
||
|
||
} else {
|
||
return this.parent.each(function(e) {
|
||
if (cache.add(e)) {
|
||
return fn(e, i++);
|
||
}
|
||
});
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence by combining the elements from this sequence with
|
||
* corresponding elements from the specified array(s).
|
||
*
|
||
* @public
|
||
* @param {...Array} var_args One or more arrays of elements to combine with
|
||
* those of this sequence.
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2]).zip([3, 4]) // sequence: [[1, 3], [2, 4]]
|
||
*
|
||
* @benchmarks
|
||
* var smArrL = Lazy.range(10).toArray(),
|
||
* smArrR = Lazy.range(10, 20).toArray(),
|
||
* lgArrL = Lazy.range(100).toArray(),
|
||
* lgArrR = Lazy.range(100, 200).toArray();
|
||
*
|
||
* Lazy(smArrL).zip(smArrR).each(Lazy.noop) // lazy - zipping 10-element arrays
|
||
* Lazy(lgArrL).zip(lgArrR).each(Lazy.noop) // lazy - zipping 100-element arrays
|
||
* _.each(_.zip(smArrL, smArrR), _.noop) // lodash - zipping 10-element arrays
|
||
* _.each(_.zip(lgArrL, lgArrR), _.noop) // lodash - zipping 100-element arrays
|
||
*/
|
||
Sequence.prototype.zip = function zip(var_args) {
|
||
if (arguments.length === 1) {
|
||
return new SimpleZippedSequence(this, (/** @type {Array} */ var_args));
|
||
} else {
|
||
return new ZippedSequence(this, arraySlice.call(arguments, 0));
|
||
}
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function ZippedSequence(parent, arrays) {
|
||
this.parent = parent;
|
||
this.arrays = arrays;
|
||
}
|
||
|
||
ZippedSequence.prototype = new Sequence();
|
||
|
||
ZippedSequence.prototype.each = function each(fn) {
|
||
var arrays = this.arrays,
|
||
i = 0;
|
||
this.parent.each(function(e) {
|
||
var group = [e];
|
||
for (var j = 0; j < arrays.length; ++j) {
|
||
if (arrays[j].length > i) {
|
||
group.push(arrays[j][i]);
|
||
}
|
||
}
|
||
return fn(group, i++);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence with the same elements as this one, in a randomized
|
||
* order.
|
||
*
|
||
* @public
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3, 4, 5]).shuffle().value() // =~ [1, 2, 3, 4, 5]
|
||
*/
|
||
Sequence.prototype.shuffle = function shuffle() {
|
||
return new ShuffledSequence(this);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function ShuffledSequence(parent) {
|
||
this.parent = parent;
|
||
}
|
||
|
||
ShuffledSequence.prototype = new Sequence();
|
||
|
||
ShuffledSequence.prototype.each = function each(fn) {
|
||
var shuffled = this.parent.toArray(),
|
||
floor = Math.floor,
|
||
random = Math.random,
|
||
j = 0;
|
||
|
||
for (var i = shuffled.length - 1; i > 0; --i) {
|
||
swap(shuffled, i, floor(random() * (i + 1)));
|
||
if (fn(shuffled[i], j++) === false) {
|
||
return;
|
||
}
|
||
}
|
||
fn(shuffled[0], j);
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence with every element from this sequence, and with arrays
|
||
* exploded so that a sequence of arrays (of arrays) becomes a flat sequence of
|
||
* values.
|
||
*
|
||
* @public
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, [2, 3], [4, [5]]]).flatten() // sequence: [1, 2, 3, 4, 5]
|
||
* Lazy([1, Lazy([2, 3])]).flatten() // sequence: [1, 2, 3]
|
||
*/
|
||
Sequence.prototype.flatten = function flatten() {
|
||
return new FlattenedSequence(this);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function FlattenedSequence(parent) {
|
||
this.parent = parent;
|
||
}
|
||
|
||
FlattenedSequence.prototype = new Sequence();
|
||
|
||
FlattenedSequence.prototype.each = function each(fn) {
|
||
var index = 0;
|
||
|
||
return this.parent.each(function recurseVisitor(e) {
|
||
if (e instanceof Array) {
|
||
return forEach(e, recurseVisitor);
|
||
}
|
||
|
||
if (e instanceof Sequence) {
|
||
return e.each(recurseVisitor);
|
||
}
|
||
|
||
return fn(e, index++);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence with the same elements as this one, except for all
|
||
* falsy values (`false`, `0`, `""`, `null`, and `undefined`).
|
||
*
|
||
* @public
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* Lazy(["foo", null, "bar", undefined]).compact() // sequence: ["foo", "bar"]
|
||
*/
|
||
Sequence.prototype.compact = function compact() {
|
||
return this.filter(function(e) { return !!e; });
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence with all the elements of this sequence that are not
|
||
* also among the specified arguments.
|
||
*
|
||
* @public
|
||
* @aka difference
|
||
* @param {...*} var_args The values, or array(s) of values, to be excluded from the
|
||
* resulting sequence.
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3, 4, 5]).without(2, 3) // sequence: [1, 4, 5]
|
||
* Lazy([1, 2, 3, 4, 5]).without([4, 5]) // sequence: [1, 2, 3]
|
||
*/
|
||
Sequence.prototype.without = function without(var_args) {
|
||
return new WithoutSequence(this, arraySlice.call(arguments, 0));
|
||
};
|
||
|
||
Sequence.prototype.difference = function difference(var_args) {
|
||
return this.without.apply(this, arguments);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function WithoutSequence(parent, values) {
|
||
this.parent = parent;
|
||
this.values = values;
|
||
}
|
||
|
||
WithoutSequence.prototype = new Sequence();
|
||
|
||
WithoutSequence.prototype.each = function each(fn) {
|
||
var set = createSet(this.values),
|
||
i = 0;
|
||
return this.parent.each(function(e) {
|
||
if (!set.contains(e)) {
|
||
return fn(e, i++);
|
||
}
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence with all the unique elements either in this sequence
|
||
* or among the specified arguments.
|
||
*
|
||
* @public
|
||
* @param {...*} var_args The values, or array(s) of values, to be additionally
|
||
* included in the resulting sequence.
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* Lazy(["foo", "bar"]).union([]) // sequence: ["foo", "bar"]
|
||
* Lazy(["foo", "bar"]).union(["bar", "baz"]) // sequence: ["foo", "bar", "baz"]
|
||
*/
|
||
Sequence.prototype.union = function union(var_args) {
|
||
return this.concat(var_args).uniq();
|
||
};
|
||
|
||
/**
|
||
* Creates a new sequence with all the elements of this sequence that also
|
||
* appear among the specified arguments.
|
||
*
|
||
* @public
|
||
* @param {...*} var_args The values, or array(s) of values, in which elements
|
||
* from this sequence must also be included to end up in the resulting sequence.
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* Lazy(["foo", "bar"]).intersection([]) // sequence: []
|
||
* Lazy(["foo", "bar"]).intersection(["bar", "baz"]) // sequence: ["bar"]
|
||
*/
|
||
Sequence.prototype.intersection = function intersection(var_args) {
|
||
if (arguments.length === 1 && arguments[0] instanceof Array) {
|
||
return new SimpleIntersectionSequence(this, (/** @type {Array} */ var_args));
|
||
} else {
|
||
return new IntersectionSequence(this, arraySlice.call(arguments, 0));
|
||
}
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function IntersectionSequence(parent, arrays) {
|
||
this.parent = parent;
|
||
this.arrays = arrays;
|
||
}
|
||
|
||
IntersectionSequence.prototype = new Sequence();
|
||
|
||
IntersectionSequence.prototype.each = function each(fn) {
|
||
var sets = Lazy(this.arrays).map(function(values) {
|
||
return new UniqueMemoizer(Lazy(values).getIterator());
|
||
});
|
||
|
||
var setIterator = new UniqueMemoizer(sets.getIterator()),
|
||
i = 0;
|
||
|
||
return this.parent.each(function(e) {
|
||
var includedInAll = true;
|
||
setIterator.each(function(set) {
|
||
if (!set.contains(e)) {
|
||
includedInAll = false;
|
||
return false;
|
||
}
|
||
});
|
||
|
||
if (includedInAll) {
|
||
return fn(e, i++);
|
||
}
|
||
});
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function UniqueMemoizer(iterator) {
|
||
this.iterator = iterator;
|
||
this.set = new Set();
|
||
this.memo = [];
|
||
this.currentValue = undefined;
|
||
}
|
||
|
||
UniqueMemoizer.prototype.current = function current() {
|
||
return this.currentValue;
|
||
};
|
||
|
||
UniqueMemoizer.prototype.moveNext = function moveNext() {
|
||
var iterator = this.iterator,
|
||
set = this.set,
|
||
memo = this.memo,
|
||
current;
|
||
|
||
while (iterator.moveNext()) {
|
||
current = iterator.current();
|
||
if (set.add(current)) {
|
||
memo.push(current);
|
||
this.currentValue = current;
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
};
|
||
|
||
UniqueMemoizer.prototype.each = function each(fn) {
|
||
var memo = this.memo,
|
||
length = memo.length,
|
||
i = -1;
|
||
|
||
while (++i < length) {
|
||
if (fn(memo[i], i) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
while (this.moveNext()) {
|
||
if (fn(this.currentValue, i++) === false) {
|
||
break;
|
||
}
|
||
}
|
||
};
|
||
|
||
UniqueMemoizer.prototype.contains = function contains(e) {
|
||
if (this.set.contains(e)) {
|
||
return true;
|
||
}
|
||
|
||
while (this.moveNext()) {
|
||
if (this.currentValue === e) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
return false;
|
||
};
|
||
|
||
/**
|
||
* Checks whether every element in this sequence satisfies a given predicate.
|
||
*
|
||
* @public
|
||
* @aka all
|
||
* @param {Function} predicate A function to call on (potentially) every element
|
||
* in this sequence.
|
||
* @returns {boolean} True if `predicate` returns true for every element in the
|
||
* sequence (or the sequence is empty). False if `predicate` returns false
|
||
* for at least one element.
|
||
*
|
||
* @examples
|
||
* var numbers = [1, 2, 3, 4, 5];
|
||
*
|
||
* var objects = [{ foo: true }, { foo: false, bar: true }];
|
||
*
|
||
* Lazy(numbers).every(isEven) // => false
|
||
* Lazy(numbers).every(isPositive) // => true
|
||
* Lazy(objects).all('foo') // => false
|
||
* Lazy(objects).all('bar') // => false
|
||
*/
|
||
Sequence.prototype.every = function every(predicate) {
|
||
predicate = createCallback(predicate);
|
||
|
||
return this.each(function(e, i) {
|
||
return !!predicate(e, i);
|
||
});
|
||
};
|
||
|
||
Sequence.prototype.all = function all(predicate) {
|
||
return this.every(predicate);
|
||
};
|
||
|
||
/**
|
||
* Checks whether at least one element in this sequence satisfies a given
|
||
* predicate (or, if no predicate is specified, whether the sequence contains at
|
||
* least one element).
|
||
*
|
||
* @public
|
||
* @aka any
|
||
* @param {Function=} predicate A function to call on (potentially) every element
|
||
* in this sequence.
|
||
* @returns {boolean} True if `predicate` returns true for at least one element
|
||
* in the sequence. False if `predicate` returns false for every element (or
|
||
* the sequence is empty).
|
||
*
|
||
* @examples
|
||
* var numbers = [1, 2, 3, 4, 5];
|
||
*
|
||
* Lazy(numbers).some() // => true
|
||
* Lazy(numbers).some(isEven) // => true
|
||
* Lazy(numbers).some(isNegative) // => false
|
||
* Lazy([]).some() // => false
|
||
*/
|
||
Sequence.prototype.some = function some(predicate) {
|
||
predicate = createCallback(predicate, true);
|
||
|
||
var success = false;
|
||
this.each(function(e) {
|
||
if (predicate(e)) {
|
||
success = true;
|
||
return false;
|
||
}
|
||
});
|
||
return success;
|
||
};
|
||
|
||
Sequence.prototype.any = function any(predicate) {
|
||
return this.some(predicate);
|
||
};
|
||
|
||
/**
|
||
* Checks whether NO elements in this sequence satisfy the given predicate
|
||
* (the opposite of {@link Sequence#all}, basically).
|
||
*
|
||
* @public
|
||
* @param {Function=} predicate A function to call on (potentially) every element
|
||
* in this sequence.
|
||
* @returns {boolean} True if `predicate` does not return true for any element
|
||
* in the sequence. False if `predicate` returns true for at least one
|
||
* element.
|
||
*
|
||
* @examples
|
||
* var numbers = [1, 2, 3, 4, 5];
|
||
*
|
||
* Lazy(numbers).none() // => false
|
||
* Lazy(numbers).none(isEven) // => false
|
||
* Lazy(numbers).none(isNegative) // => true
|
||
* Lazy([]).none(isEven) // => true
|
||
* Lazy([]).none(isNegative) // => true
|
||
* Lazy([]).none() // => true
|
||
*/
|
||
Sequence.prototype.none = function none(predicate) {
|
||
return !this.any(predicate);
|
||
};
|
||
|
||
/**
|
||
* Checks whether the sequence has no elements.
|
||
*
|
||
* @public
|
||
* @returns {boolean} True if the sequence is empty, false if it contains at
|
||
* least one element.
|
||
*
|
||
* @examples
|
||
* Lazy([]).isEmpty() // => true
|
||
* Lazy([1, 2, 3]).isEmpty() // => false
|
||
*/
|
||
Sequence.prototype.isEmpty = function isEmpty() {
|
||
return !this.any();
|
||
};
|
||
|
||
/**
|
||
* Performs (at worst) a linear search from the head of this sequence,
|
||
* returning the first index at which the specified value is found.
|
||
*
|
||
* @public
|
||
* @param {*} value The element to search for in the sequence.
|
||
* @returns {number} The index within this sequence where the given value is
|
||
* located, or -1 if the sequence doesn't contain the value.
|
||
*
|
||
* @examples
|
||
* function reciprocal(x) { return 1 / x; }
|
||
*
|
||
* Lazy(["foo", "bar", "baz"]).indexOf("bar") // => 1
|
||
* Lazy([1, 2, 3]).indexOf(4) // => -1
|
||
* Lazy([1, 2, 3]).map(reciprocal).indexOf(0.5) // => 1
|
||
*/
|
||
Sequence.prototype.indexOf = function indexOf(value) {
|
||
var foundIndex = -1;
|
||
this.each(function(e, i) {
|
||
if (e === value) {
|
||
foundIndex = i;
|
||
return false;
|
||
}
|
||
});
|
||
return foundIndex;
|
||
};
|
||
|
||
/**
|
||
* Performs (at worst) a linear search from the tail of this sequence,
|
||
* returning the last index at which the specified value is found.
|
||
*
|
||
* @public
|
||
* @param {*} value The element to search for in the sequence.
|
||
* @returns {number} The last index within this sequence where the given value
|
||
* is located, or -1 if the sequence doesn't contain the value.
|
||
*
|
||
* @examples
|
||
* Lazy(["a", "b", "c", "b", "a"]).lastIndexOf("b") // => 3
|
||
* Lazy([1, 2, 3]).lastIndexOf(0) // => -1
|
||
* Lazy([2, 2, 1, 2, 4]).filter(isEven).lastIndexOf(2) // 2
|
||
*/
|
||
Sequence.prototype.lastIndexOf = function lastIndexOf(value) {
|
||
var reversed = this.getIndex().reverse(),
|
||
index = reversed.indexOf(value);
|
||
if (index !== -1) {
|
||
index = reversed.length() - index - 1;
|
||
}
|
||
return index;
|
||
};
|
||
|
||
/**
|
||
* Performs a binary search of this sequence, returning the lowest index where
|
||
* the given value is either found, or where it belongs (if it is not already
|
||
* in the sequence).
|
||
*
|
||
* This method assumes the sequence is in sorted order and will fail otherwise.
|
||
*
|
||
* @public
|
||
* @param {*} value The element to search for in the sequence.
|
||
* @returns {number} An index within this sequence where the given value is
|
||
* located, or where it belongs in sorted order.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 3, 6, 9]).sortedIndex(3) // => 1
|
||
* Lazy([1, 3, 6, 9]).sortedIndex(7) // => 3
|
||
* Lazy([5, 10, 15, 20]).filter(isEven).sortedIndex(10) // => 0
|
||
* Lazy([5, 10, 15, 20]).filter(isEven).sortedIndex(12) // => 1
|
||
*/
|
||
Sequence.prototype.sortedIndex = function sortedIndex(value) {
|
||
var indexed = this.getIndex(),
|
||
lower = 0,
|
||
upper = indexed.length(),
|
||
i;
|
||
|
||
while (lower < upper) {
|
||
i = (lower + upper) >>> 1;
|
||
if (compare(indexed.get(i), value) === -1) {
|
||
lower = i + 1;
|
||
} else {
|
||
upper = i;
|
||
}
|
||
}
|
||
return lower;
|
||
};
|
||
|
||
/**
|
||
* Checks whether the given value is in this sequence.
|
||
*
|
||
* @public
|
||
* @param {*} value The element to search for in the sequence.
|
||
* @returns {boolean} True if the sequence contains the value, false if not.
|
||
*
|
||
* @examples
|
||
* var numbers = [5, 10, 15, 20];
|
||
*
|
||
* Lazy(numbers).contains(15) // => true
|
||
* Lazy(numbers).contains(13) // => false
|
||
*/
|
||
Sequence.prototype.contains = function contains(value) {
|
||
return this.indexOf(value) !== -1;
|
||
};
|
||
|
||
/**
|
||
* Aggregates a sequence into a single value according to some accumulator
|
||
* function.
|
||
*
|
||
* For an asynchronous sequence, instead of immediately returning a result
|
||
* (which it can't, obviously), this method returns an {@link AsyncHandle}
|
||
* whose `onComplete` method can be called to supply a callback to handle the
|
||
* final result once iteration has completed.
|
||
*
|
||
* @public
|
||
* @aka inject, foldl
|
||
* @param {Function} aggregator The function through which to pass every element
|
||
* in the sequence. For every element, the function will be passed the total
|
||
* aggregated result thus far and the element itself, and should return a
|
||
* new aggregated result.
|
||
* @param {*=} memo The starting value to use for the aggregated result
|
||
* (defaults to the first element in the sequence).
|
||
* @returns {*} The result of the aggregation, or, for asynchronous sequences,
|
||
* an {@link AsyncHandle} whose `onComplete` method accepts a callback to
|
||
* handle the final result.
|
||
*
|
||
* @examples
|
||
* function multiply(x, y) { return x * y; }
|
||
*
|
||
* var numbers = [1, 2, 3, 4];
|
||
*
|
||
* Lazy(numbers).reduce(multiply) // => 24
|
||
* Lazy(numbers).reduce(multiply, 5) // => 120
|
||
*/
|
||
Sequence.prototype.reduce = function reduce(aggregator, memo) {
|
||
if (arguments.length < 2) {
|
||
return this.tail().reduce(aggregator, this.head());
|
||
}
|
||
|
||
var eachResult = this.each(function(e, i) {
|
||
memo = aggregator(memo, e, i);
|
||
});
|
||
|
||
// TODO: Think of a way more efficient solution to this problem.
|
||
if (eachResult instanceof AsyncHandle) {
|
||
return eachResult.then(function() { return memo; });
|
||
}
|
||
|
||
return memo;
|
||
};
|
||
|
||
Sequence.prototype.inject =
|
||
Sequence.prototype.foldl = function foldl(aggregator, memo) {
|
||
return this.reduce(aggregator, memo);
|
||
};
|
||
|
||
/**
|
||
* Aggregates a sequence, from the tail, into a single value according to some
|
||
* accumulator function.
|
||
*
|
||
* @public
|
||
* @aka foldr
|
||
* @param {Function} aggregator The function through which to pass every element
|
||
* in the sequence. For every element, the function will be passed the total
|
||
* aggregated result thus far and the element itself, and should return a
|
||
* new aggregated result.
|
||
* @param {*} memo The starting value to use for the aggregated result.
|
||
* @returns {*} The result of the aggregation.
|
||
*
|
||
* @examples
|
||
* function append(s1, s2) {
|
||
* return s1 + s2;
|
||
* }
|
||
*
|
||
* function isVowel(str) {
|
||
* return "aeiou".indexOf(str) !== -1;
|
||
* }
|
||
*
|
||
* Lazy("abcde").reduceRight(append) // => "edcba"
|
||
* Lazy("abcde").filter(isVowel).reduceRight(append) // => "ea"
|
||
*/
|
||
Sequence.prototype.reduceRight = function reduceRight(aggregator, memo) {
|
||
if (arguments.length < 2) {
|
||
return this.initial(1).reduceRight(aggregator, this.last());
|
||
}
|
||
|
||
// This bothers me... but frankly, calling reverse().reduce() is potentially
|
||
// going to eagerly evaluate the sequence anyway; so it's really not an issue.
|
||
var indexed = this.getIndex(),
|
||
i = indexed.length() - 1;
|
||
return indexed.reverse().reduce(function(m, e) {
|
||
return aggregator(m, e, i--);
|
||
}, memo);
|
||
};
|
||
|
||
Sequence.prototype.foldr = function foldr(aggregator, memo) {
|
||
return this.reduceRight(aggregator, memo);
|
||
};
|
||
|
||
/**
|
||
* Groups this sequence into consecutive (overlapping) segments of a specified
|
||
* length. If the underlying sequence has fewer elements than the specfied
|
||
* length, then this sequence will be empty.
|
||
*
|
||
* @public
|
||
* @param {number} length The length of each consecutive segment.
|
||
* @returns {Sequence} The resulting sequence of consecutive segments.
|
||
*
|
||
* @examples
|
||
* Lazy([]).consecutive(2) // => sequence: []
|
||
* Lazy([1]).consecutive(2) // => sequence: []
|
||
* Lazy([1, 2]).consecutive(2) // => sequence: [[1, 2]]
|
||
* Lazy([1, 2, 3]).consecutive(2) // => sequence: [[1, 2], [2, 3]]
|
||
* Lazy([1, 2, 3]).consecutive(0) // => sequence: [[]]
|
||
* Lazy([1, 2, 3]).consecutive(1) // => sequence: [[1], [2], [3]]
|
||
*/
|
||
Sequence.prototype.consecutive = function consecutive(count) {
|
||
var queue = new Queue(count);
|
||
var segments = this.map(function(element) {
|
||
if (queue.add(element).count === count) {
|
||
return queue.toArray();
|
||
}
|
||
});
|
||
return segments.compact();
|
||
};
|
||
|
||
/**
|
||
* Breaks this sequence into chunks (arrays) of a specified length.
|
||
*
|
||
* @public
|
||
* @param {number} size The size of each chunk.
|
||
* @returns {Sequence} The resulting sequence of chunks.
|
||
*
|
||
* @examples
|
||
* Lazy([]).chunk(2) // sequence: []
|
||
* Lazy([1, 2, 3]).chunk(2) // sequence: [[1, 2], [3]]
|
||
* Lazy([1, 2, 3]).chunk(1) // sequence: [[1], [2], [3]]
|
||
* Lazy([1, 2, 3]).chunk(4) // sequence: [[1, 2, 3]]
|
||
* Lazy([1, 2, 3]).chunk(0) // throws
|
||
*/
|
||
Sequence.prototype.chunk = function chunk(size) {
|
||
if (size < 1) {
|
||
throw new Error("You must specify a positive chunk size.");
|
||
}
|
||
|
||
return new ChunkedSequence(this, size);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function ChunkedSequence(parent, size) {
|
||
this.parent = parent;
|
||
this.chunkSize = size;
|
||
}
|
||
|
||
ChunkedSequence.prototype = new Sequence();
|
||
|
||
ChunkedSequence.prototype.getIterator = function getIterator() {
|
||
return new ChunkedIterator(this.parent, this.chunkSize);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function ChunkedIterator(sequence, size) {
|
||
this.iterator = sequence.getIterator();
|
||
this.size = size;
|
||
}
|
||
|
||
ChunkedIterator.prototype.current = function current() {
|
||
return this.currentChunk;
|
||
};
|
||
|
||
ChunkedIterator.prototype.moveNext = function moveNext() {
|
||
var iterator = this.iterator,
|
||
chunkSize = this.size,
|
||
chunk = [];
|
||
|
||
while (chunk.length < chunkSize && iterator.moveNext()) {
|
||
chunk.push(iterator.current());
|
||
}
|
||
|
||
if (chunk.length === 0) {
|
||
return false;
|
||
}
|
||
|
||
this.currentChunk = chunk;
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* Passes each element in the sequence to the specified callback during
|
||
* iteration. This is like {@link Sequence#each}, except that it can be
|
||
* inserted anywhere in the middle of a chain of methods to "intercept" the
|
||
* values in the sequence at that point.
|
||
*
|
||
* @public
|
||
* @param {Function} callback A function to call on every element in the
|
||
* sequence during iteration. The return value of this function does not
|
||
* matter.
|
||
* @returns {Sequence} A sequence comprising the same elements as this one.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3]).tap(fn).each(Lazy.noop); // calls fn 3 times
|
||
*/
|
||
Sequence.prototype.tap = function tap(callback) {
|
||
return new TappedSequence(this, callback);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function TappedSequence(parent, callback) {
|
||
this.parent = parent;
|
||
this.callback = callback;
|
||
}
|
||
|
||
TappedSequence.prototype = new Sequence();
|
||
|
||
TappedSequence.prototype.each = function each(fn) {
|
||
var callback = this.callback;
|
||
return this.parent.each(function(e, i) {
|
||
callback(e, i);
|
||
return fn(e, i);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Seaches for the first element in the sequence satisfying a given predicate.
|
||
*
|
||
* @public
|
||
* @aka detect
|
||
* @param {Function} predicate A function to call on (potentially) every element
|
||
* in the sequence.
|
||
* @returns {*} The first element in the sequence for which `predicate` returns
|
||
* `true`, or `undefined` if no such element is found.
|
||
*
|
||
* @examples
|
||
* function divisibleBy3(x) {
|
||
* return x % 3 === 0;
|
||
* }
|
||
*
|
||
* var numbers = [5, 6, 7, 8, 9, 10];
|
||
*
|
||
* Lazy(numbers).find(divisibleBy3) // => 6
|
||
* Lazy(numbers).find(isNegative) // => undefined
|
||
*/
|
||
Sequence.prototype.find = function find(predicate) {
|
||
return this.filter(predicate).first();
|
||
};
|
||
|
||
Sequence.prototype.detect = function detect(predicate) {
|
||
return this.find(predicate);
|
||
};
|
||
|
||
/**
|
||
* Gets the minimum value in the sequence.
|
||
*
|
||
* @public
|
||
* @param {Function=} valueFn The function by which the value for comparison is
|
||
* calculated for each element in the sequence.
|
||
* @returns {*} The element with the lowest value in the sequence, or
|
||
* `Infinity` if the sequence is empty.
|
||
*
|
||
* @examples
|
||
* function negate(x) { return x * -1; }
|
||
*
|
||
* Lazy([]).min() // => Infinity
|
||
* Lazy([6, 18, 2, 49, 34]).min() // => 2
|
||
* Lazy([6, 18, 2, 49, 34]).min(negate) // => 49
|
||
*/
|
||
Sequence.prototype.min = function min(valueFn) {
|
||
if (typeof valueFn !== "undefined") {
|
||
return this.minBy(valueFn);
|
||
}
|
||
|
||
return this.reduce(function(x, y) { return y < x ? y : x; }, Infinity);
|
||
};
|
||
|
||
Sequence.prototype.minBy = function minBy(valueFn) {
|
||
valueFn = createCallback(valueFn);
|
||
return this.reduce(function(x, y) { return valueFn(y) < valueFn(x) ? y : x; });
|
||
};
|
||
|
||
/**
|
||
* Gets the maximum value in the sequence.
|
||
*
|
||
* @public
|
||
* @param {Function=} valueFn The function by which the value for comparison is
|
||
* calculated for each element in the sequence.
|
||
* @returns {*} The element with the highest value in the sequence, or
|
||
* `-Infinity` if the sequence is empty.
|
||
*
|
||
* @examples
|
||
* function reverseDigits(x) {
|
||
* return Number(String(x).split('').reverse().join(''));
|
||
* }
|
||
*
|
||
* Lazy([]).max() // => -Infinity
|
||
* Lazy([6, 18, 2, 48, 29]).max() // => 48
|
||
* Lazy([6, 18, 2, 48, 29]).max(reverseDigits) // => 29
|
||
*/
|
||
Sequence.prototype.max = function max(valueFn) {
|
||
if (typeof valueFn !== "undefined") {
|
||
return this.maxBy(valueFn);
|
||
}
|
||
|
||
return this.reduce(function(x, y) { return y > x ? y : x; }, -Infinity);
|
||
};
|
||
|
||
Sequence.prototype.maxBy = function maxBy(valueFn) {
|
||
valueFn = createCallback(valueFn);
|
||
return this.reduce(function(x, y) { return valueFn(y) > valueFn(x) ? y : x; });
|
||
};
|
||
|
||
/**
|
||
* Gets the sum of the values in the sequence.
|
||
*
|
||
* @public
|
||
* @param {Function=} valueFn The function used to select the values that will
|
||
* be summed up.
|
||
* @returns {*} The sum.
|
||
*
|
||
* @examples
|
||
* Lazy([]).sum() // => 0
|
||
* Lazy([1, 2, 3, 4]).sum() // => 10
|
||
* Lazy([1.2, 3.4]).sum(Math.floor) // => 4
|
||
* Lazy(['foo', 'bar']).sum('length') // => 6
|
||
*/
|
||
Sequence.prototype.sum = function sum(valueFn) {
|
||
if (typeof valueFn !== "undefined") {
|
||
return this.sumBy(valueFn);
|
||
}
|
||
|
||
return this.reduce(function(x, y) { return x + y; }, 0);
|
||
};
|
||
|
||
Sequence.prototype.sumBy = function sumBy(valueFn) {
|
||
valueFn = createCallback(valueFn);
|
||
return this.reduce(function(x, y) { return x + valueFn(y); }, 0);
|
||
};
|
||
|
||
/**
|
||
* Creates a string from joining together all of the elements in this sequence,
|
||
* separated by the given delimiter.
|
||
*
|
||
* @public
|
||
* @aka toString
|
||
* @param {string=} delimiter The separator to insert between every element from
|
||
* this sequence in the resulting string (defaults to `","`).
|
||
* @returns {string} The delimited string.
|
||
*
|
||
* @examples
|
||
* Lazy([6, 29, 1984]).join("/") // => "6/29/1984"
|
||
* Lazy(["a", "b", "c"]).join() // => "a,b,c"
|
||
* Lazy(["a", "b", "c"]).join("") // => "abc"
|
||
* Lazy([1, 2, 3]).join() // => "1,2,3"
|
||
* Lazy([1, 2, 3]).join("") // => "123"
|
||
* Lazy(["", "", ""]).join(",") // => ",,"
|
||
*/
|
||
Sequence.prototype.join = function join(delimiter) {
|
||
delimiter = typeof delimiter === "string" ? delimiter : ",";
|
||
|
||
return this.reduce(function(str, e, i) {
|
||
if (i > 0) {
|
||
str += delimiter;
|
||
}
|
||
return str + e;
|
||
}, "");
|
||
};
|
||
|
||
Sequence.prototype.toString = function toString(delimiter) {
|
||
return this.join(delimiter);
|
||
};
|
||
|
||
/**
|
||
* Creates a sequence, with the same elements as this one, that will be iterated
|
||
* over asynchronously when calling `each`.
|
||
*
|
||
* @public
|
||
* @param {number=} interval The approximate period, in milliseconds, that
|
||
* should elapse between each element in the resulting sequence. Omitting
|
||
* this argument will result in the fastest possible asynchronous iteration.
|
||
* @returns {AsyncSequence} The new asynchronous sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3]).async(100).each(fn) // calls fn 3 times asynchronously
|
||
*/
|
||
Sequence.prototype.async = function async(interval) {
|
||
return new AsyncSequence(this, interval);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function SimpleIntersectionSequence(parent, array) {
|
||
this.parent = parent;
|
||
this.array = array;
|
||
this.each = getEachForIntersection(array);
|
||
}
|
||
|
||
SimpleIntersectionSequence.prototype = new Sequence();
|
||
|
||
SimpleIntersectionSequence.prototype.eachMemoizerCache = function eachMemoizerCache(fn) {
|
||
var iterator = new UniqueMemoizer(Lazy(this.array).getIterator()),
|
||
i = 0;
|
||
|
||
return this.parent.each(function(e) {
|
||
if (iterator.contains(e)) {
|
||
return fn(e, i++);
|
||
}
|
||
});
|
||
};
|
||
|
||
SimpleIntersectionSequence.prototype.eachArrayCache = function eachArrayCache(fn) {
|
||
var array = this.array,
|
||
find = arrayContains,
|
||
i = 0;
|
||
|
||
return this.parent.each(function(e) {
|
||
if (find(array, e)) {
|
||
return fn(e, i++);
|
||
}
|
||
});
|
||
};
|
||
|
||
function getEachForIntersection(source) {
|
||
if (source.length < 40) {
|
||
return SimpleIntersectionSequence.prototype.eachArrayCache;
|
||
} else {
|
||
return SimpleIntersectionSequence.prototype.eachMemoizerCache;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* An optimized version of {@link ZippedSequence}, when zipping a sequence with
|
||
* only one array.
|
||
*
|
||
* @param {Sequence} parent The underlying sequence.
|
||
* @param {Array} array The array with which to zip the sequence.
|
||
* @constructor
|
||
*/
|
||
function SimpleZippedSequence(parent, array) {
|
||
this.parent = parent;
|
||
this.array = array;
|
||
}
|
||
|
||
SimpleZippedSequence.prototype = new Sequence();
|
||
|
||
SimpleZippedSequence.prototype.each = function each(fn) {
|
||
var array = this.array;
|
||
return this.parent.each(function(e, i) {
|
||
return fn([e, array[i]], i);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* An `ArrayLikeSequence` is a {@link Sequence} that provides random access to
|
||
* its elements. This extends the API for iterating with the additional methods
|
||
* {@link #get} and {@link #length}, allowing a sequence to act as a "view" into
|
||
* a collection or other indexed data source.
|
||
*
|
||
* The initial sequence created by wrapping an array with `Lazy(array)` is an
|
||
* `ArrayLikeSequence`.
|
||
*
|
||
* All methods of `ArrayLikeSequence` that conceptually should return
|
||
* something like a array (with indexed access) return another
|
||
* `ArrayLikeSequence`, for example:
|
||
*
|
||
* - {@link Sequence#map}
|
||
* - {@link ArrayLikeSequence#slice}
|
||
* - {@link Sequence#take} and {@link Sequence#drop}
|
||
* - {@link Sequence#reverse}
|
||
*
|
||
* The above is not an exhaustive list. There are also certain other cases
|
||
* where it might be possible to return an `ArrayLikeSequence` (e.g., calling
|
||
* {@link Sequence#concat} with a single array argument), but this is not
|
||
* guaranteed by the API.
|
||
*
|
||
* Note that in many cases, it is not possible to provide indexed access
|
||
* without first performing at least a partial iteration of the underlying
|
||
* sequence. In these cases an `ArrayLikeSequence` will not be returned:
|
||
*
|
||
* - {@link Sequence#filter}
|
||
* - {@link Sequence#uniq}
|
||
* - {@link Sequence#union}
|
||
* - {@link Sequence#intersect}
|
||
*
|
||
* etc. The above methods only return ordinary {@link Sequence} objects.
|
||
*
|
||
* Defining custom array-like sequences
|
||
* ------------------------------------
|
||
*
|
||
* Creating a custom `ArrayLikeSequence` is essentially the same as creating a
|
||
* custom {@link Sequence}. You just have a couple more methods you need to
|
||
* implement: `get` and (optionally) `length`.
|
||
*
|
||
* Here's an example. Let's define a sequence type called `OffsetSequence` that
|
||
* offsets each of its parent's elements by a set distance, and circles back to
|
||
* the beginning after reaching the end. **Remember**: the initialization
|
||
* function you pass to {@link #define} should always accept a `parent` as its
|
||
* first parameter.
|
||
*
|
||
* ArrayLikeSequence.define("offset", {
|
||
* init: function(parent, offset) {
|
||
* this.offset = offset;
|
||
* },
|
||
*
|
||
* get: function(i) {
|
||
* return this.parent.get((i + this.offset) % this.parent.length());
|
||
* }
|
||
* });
|
||
*
|
||
* It's worth noting a couple of things here.
|
||
*
|
||
* First, Lazy's default implementation of `length` simply returns the parent's
|
||
* length. In this case, since an `OffsetSequence` will always have the same
|
||
* number of elements as its parent, that implementation is fine; so we don't
|
||
* need to override it.
|
||
*
|
||
* Second, the default implementation of `each` uses `get` and `length` to
|
||
* essentially create a `for` loop, which is fine here. If you want to implement
|
||
* `each` your own way, you can do that; but in most cases (as here), you can
|
||
* probably just stick with the default.
|
||
*
|
||
* So we're already done, after only implementing `get`! Pretty easy, huh?
|
||
*
|
||
* Now the `offset` method will be chainable from any `ArrayLikeSequence`. So
|
||
* for example:
|
||
*
|
||
* Lazy([1, 2, 3]).map(mapFn).offset(3);
|
||
*
|
||
* ...will work, but:
|
||
*
|
||
* Lazy([1, 2, 3]).filter(mapFn).offset(3);
|
||
*
|
||
* ...will not (because `filter` does not return an `ArrayLikeSequence`).
|
||
*
|
||
* (Also, as with the example provided for defining custom {@link Sequence}
|
||
* types, this example really could have been implemented using a function
|
||
* already available as part of Lazy.js: in this case, {@link Sequence#map}.)
|
||
*
|
||
* @public
|
||
* @constructor
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3]) // instanceof Lazy.ArrayLikeSequence
|
||
* Lazy([1, 2, 3]).map(Lazy.identity) // instanceof Lazy.ArrayLikeSequence
|
||
* Lazy([1, 2, 3]).take(2) // instanceof Lazy.ArrayLikeSequence
|
||
* Lazy([1, 2, 3]).drop(2) // instanceof Lazy.ArrayLikeSequence
|
||
* Lazy([1, 2, 3]).reverse() // instanceof Lazy.ArrayLikeSequence
|
||
* Lazy([1, 2, 3]).slice(1, 2) // instanceof Lazy.ArrayLikeSequence
|
||
*/
|
||
function ArrayLikeSequence() {}
|
||
|
||
ArrayLikeSequence.prototype = new Sequence();
|
||
|
||
/**
|
||
* Create a new constructor function for a type inheriting from
|
||
* `ArrayLikeSequence`.
|
||
*
|
||
* @public
|
||
* @param {string|Array.<string>} methodName The name(s) of the method(s) to be
|
||
* used for constructing the new sequence. The method will be attached to
|
||
* the `ArrayLikeSequence` prototype so that it can be chained with any other
|
||
* methods that return array-like sequences.
|
||
* @param {Object} overrides An object containing function overrides for this
|
||
* new sequence type. **Must** include `get`. *May* include `init`,
|
||
* `length`, `getIterator`, and `each`. For each function, `this` will be
|
||
* the new sequence and `this.parent` will be the source sequence.
|
||
* @returns {Function} A constructor for a new type inheriting from
|
||
* `ArrayLikeSequence`.
|
||
*
|
||
* @examples
|
||
* Lazy.ArrayLikeSequence.define("offset", {
|
||
* init: function(offset) {
|
||
* this.offset = offset;
|
||
* },
|
||
*
|
||
* get: function(i) {
|
||
* return this.parent.get((i + this.offset) % this.parent.length());
|
||
* }
|
||
* });
|
||
*
|
||
* Lazy([1, 2, 3]).offset(1) // sequence: [2, 3, 1]
|
||
*/
|
||
ArrayLikeSequence.define = function define(methodName, overrides) {
|
||
if (!overrides || typeof overrides.get !== 'function') {
|
||
throw new Error("A custom array-like sequence must implement *at least* get!");
|
||
}
|
||
|
||
return defineSequenceType(ArrayLikeSequence, methodName, overrides);
|
||
};
|
||
|
||
/**
|
||
* Returns the element at the specified index.
|
||
*
|
||
* @public
|
||
* @param {number} i The index to access.
|
||
* @returns {*} The element.
|
||
*
|
||
* @examples
|
||
* function increment(x) { return x + 1; }
|
||
*
|
||
* Lazy([1, 2, 3]).get(1) // => 2
|
||
* Lazy([1, 2, 3]).get(-1) // => undefined
|
||
* Lazy([1, 2, 3]).map(increment).get(1) // => 3
|
||
*/
|
||
ArrayLikeSequence.prototype.get = function get(i) {
|
||
return this.parent.get(i);
|
||
};
|
||
|
||
/**
|
||
* Returns the length of the sequence.
|
||
*
|
||
* @public
|
||
* @returns {number} The length.
|
||
*
|
||
* @examples
|
||
* function increment(x) { return x + 1; }
|
||
*
|
||
* Lazy([]).length() // => 0
|
||
* Lazy([1, 2, 3]).length() // => 3
|
||
* Lazy([1, 2, 3]).map(increment).length() // => 3
|
||
*/
|
||
ArrayLikeSequence.prototype.length = function length() {
|
||
return this.parent.length();
|
||
};
|
||
|
||
/**
|
||
* Returns the current sequence (since it is already indexed).
|
||
*/
|
||
ArrayLikeSequence.prototype.getIndex = function getIndex() {
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#getIterator}.
|
||
*/
|
||
ArrayLikeSequence.prototype.getIterator = function getIterator() {
|
||
return new IndexedIterator(this);
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Iterator} meant to work with already-indexed
|
||
* sequences.
|
||
*
|
||
* @param {ArrayLikeSequence} sequence The sequence to iterate over.
|
||
* @constructor
|
||
*/
|
||
function IndexedIterator(sequence) {
|
||
this.sequence = sequence;
|
||
this.index = -1;
|
||
}
|
||
|
||
IndexedIterator.prototype.current = function current() {
|
||
return this.sequence.get(this.index);
|
||
};
|
||
|
||
IndexedIterator.prototype.moveNext = function moveNext() {
|
||
if (this.index >= this.sequence.length() - 1) {
|
||
return false;
|
||
}
|
||
|
||
++this.index;
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#each}.
|
||
*/
|
||
ArrayLikeSequence.prototype.each = function each(fn) {
|
||
var length = this.length(),
|
||
i = -1;
|
||
|
||
while (++i < length) {
|
||
if (fn(this.get(i), i) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* Returns a new sequence with the same elements as this one, minus the last
|
||
* element.
|
||
*
|
||
* @public
|
||
* @returns {ArrayLikeSequence} The new array-like sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3]).pop() // sequence: [1, 2]
|
||
* Lazy([]).pop() // sequence: []
|
||
*/
|
||
ArrayLikeSequence.prototype.pop = function pop() {
|
||
return this.initial();
|
||
};
|
||
|
||
/**
|
||
* Returns a new sequence with the same elements as this one, minus the first
|
||
* element.
|
||
*
|
||
* @public
|
||
* @returns {ArrayLikeSequence} The new array-like sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3]).shift() // sequence: [2, 3]
|
||
* Lazy([]).shift() // sequence: []
|
||
*/
|
||
ArrayLikeSequence.prototype.shift = function shift() {
|
||
return this.drop();
|
||
};
|
||
|
||
/**
|
||
* Returns a new sequence comprising the portion of this sequence starting
|
||
* from the specified starting index and continuing until the specified ending
|
||
* index or to the end of the sequence.
|
||
*
|
||
* @public
|
||
* @param {number} begin The index at which the new sequence should start.
|
||
* @param {number=} end The index at which the new sequence should end.
|
||
* @returns {ArrayLikeSequence} The new array-like sequence.
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3, 4, 5]).slice(0) // sequence: [1, 2, 3, 4, 5]
|
||
* Lazy([1, 2, 3, 4, 5]).slice(2) // sequence: [3, 4, 5]
|
||
* Lazy([1, 2, 3, 4, 5]).slice(2, 4) // sequence: [3, 4]
|
||
* Lazy([1, 2, 3, 4, 5]).slice(-1) // sequence: [5]
|
||
* Lazy([1, 2, 3, 4, 5]).slice(1, -1) // sequence: [2, 3, 4]
|
||
* Lazy([1, 2, 3, 4, 5]).slice(0, 10) // sequence: [1, 2, 3, 4, 5]
|
||
*/
|
||
ArrayLikeSequence.prototype.slice = function slice(begin, end) {
|
||
var length = this.length();
|
||
|
||
if (begin < 0) {
|
||
begin = length + begin;
|
||
}
|
||
|
||
var result = this.drop(begin);
|
||
|
||
if (typeof end === "number") {
|
||
if (end < 0) {
|
||
end = length + end;
|
||
}
|
||
result = result.take(end - begin);
|
||
}
|
||
|
||
return result;
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#map}, which creates an
|
||
* {@link ArrayLikeSequence} so that the result still provides random access.
|
||
*
|
||
* @public
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3]).map(Lazy.identity) // instanceof Lazy.ArrayLikeSequence
|
||
*/
|
||
ArrayLikeSequence.prototype.map = function map(mapFn) {
|
||
return new IndexedMappedSequence(this, createCallback(mapFn));
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function IndexedMappedSequence(parent, mapFn) {
|
||
this.parent = parent;
|
||
this.mapFn = mapFn;
|
||
}
|
||
|
||
IndexedMappedSequence.prototype = new ArrayLikeSequence();
|
||
|
||
IndexedMappedSequence.prototype.get = function get(i) {
|
||
if (i < 0 || i >= this.parent.length()) {
|
||
return undefined;
|
||
}
|
||
|
||
return this.mapFn(this.parent.get(i), i);
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#filter}.
|
||
*/
|
||
ArrayLikeSequence.prototype.filter = function filter(filterFn) {
|
||
return new IndexedFilteredSequence(this, createCallback(filterFn));
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function IndexedFilteredSequence(parent, filterFn) {
|
||
this.parent = parent;
|
||
this.filterFn = filterFn;
|
||
}
|
||
|
||
IndexedFilteredSequence.prototype = new FilteredSequence();
|
||
|
||
IndexedFilteredSequence.prototype.each = function each(fn) {
|
||
var parent = this.parent,
|
||
filterFn = this.filterFn,
|
||
length = this.parent.length(),
|
||
i = -1,
|
||
j = 0,
|
||
e;
|
||
|
||
while (++i < length) {
|
||
e = parent.get(i);
|
||
if (filterFn(e, i) && fn(e, j++) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#reverse}, which creates an
|
||
* {@link ArrayLikeSequence} so that the result still provides random access.
|
||
*
|
||
* @public
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3]).reverse() // instanceof Lazy.ArrayLikeSequence
|
||
*/
|
||
ArrayLikeSequence.prototype.reverse = function reverse() {
|
||
return new IndexedReversedSequence(this);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function IndexedReversedSequence(parent) {
|
||
this.parent = parent;
|
||
}
|
||
|
||
IndexedReversedSequence.prototype = new ArrayLikeSequence();
|
||
|
||
IndexedReversedSequence.prototype.get = function get(i) {
|
||
return this.parent.get(this.length() - i - 1);
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#first}, which creates an
|
||
* {@link ArrayLikeSequence} so that the result still provides random access.
|
||
*
|
||
* @public
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3]).first(2) // instanceof Lazy.ArrayLikeSequence
|
||
*/
|
||
ArrayLikeSequence.prototype.first = function first(count) {
|
||
if (typeof count === "undefined") {
|
||
return this.get(0);
|
||
}
|
||
|
||
return new IndexedTakeSequence(this, count);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function IndexedTakeSequence(parent, count) {
|
||
this.parent = parent;
|
||
this.count = count;
|
||
}
|
||
|
||
IndexedTakeSequence.prototype = new ArrayLikeSequence();
|
||
|
||
IndexedTakeSequence.prototype.length = function length() {
|
||
var parentLength = this.parent.length();
|
||
return this.count <= parentLength ? this.count : parentLength;
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#rest}, which creates an
|
||
* {@link ArrayLikeSequence} so that the result still provides random access.
|
||
*
|
||
* @public
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2, 3]).rest() // instanceof Lazy.ArrayLikeSequence
|
||
*/
|
||
ArrayLikeSequence.prototype.rest = function rest(count) {
|
||
return new IndexedDropSequence(this, count);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function IndexedDropSequence(parent, count) {
|
||
this.parent = parent;
|
||
this.count = typeof count === "number" ? count : 1;
|
||
}
|
||
|
||
IndexedDropSequence.prototype = new ArrayLikeSequence();
|
||
|
||
IndexedDropSequence.prototype.get = function get(i) {
|
||
return this.parent.get(this.count + i);
|
||
};
|
||
|
||
IndexedDropSequence.prototype.length = function length() {
|
||
var parentLength = this.parent.length();
|
||
return this.count <= parentLength ? parentLength - this.count : 0;
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#concat} that returns another
|
||
* {@link ArrayLikeSequence} *if* the argument is an array.
|
||
*
|
||
* @public
|
||
* @param {...*} var_args
|
||
*
|
||
* @examples
|
||
* Lazy([1, 2]).concat([3, 4]) // instanceof Lazy.ArrayLikeSequence
|
||
* Lazy([1, 2]).concat([3, 4]) // sequence: [1, 2, 3, 4]
|
||
*/
|
||
ArrayLikeSequence.prototype.concat = function concat(var_args) {
|
||
if (arguments.length === 1 && arguments[0] instanceof Array) {
|
||
return new IndexedConcatenatedSequence(this, (/** @type {Array} */ var_args));
|
||
} else {
|
||
return Sequence.prototype.concat.apply(this, arguments);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function IndexedConcatenatedSequence(parent, other) {
|
||
this.parent = parent;
|
||
this.other = other;
|
||
}
|
||
|
||
IndexedConcatenatedSequence.prototype = new ArrayLikeSequence();
|
||
|
||
IndexedConcatenatedSequence.prototype.get = function get(i) {
|
||
var parentLength = this.parent.length();
|
||
if (i < parentLength) {
|
||
return this.parent.get(i);
|
||
} else {
|
||
return this.other[i - parentLength];
|
||
}
|
||
};
|
||
|
||
IndexedConcatenatedSequence.prototype.length = function length() {
|
||
return this.parent.length() + this.other.length;
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#uniq}.
|
||
*/
|
||
ArrayLikeSequence.prototype.uniq = function uniq(keyFn) {
|
||
return new IndexedUniqueSequence(this, createCallback(keyFn));
|
||
};
|
||
|
||
/**
|
||
* @param {ArrayLikeSequence} parent
|
||
* @constructor
|
||
*/
|
||
function IndexedUniqueSequence(parent, keyFn) {
|
||
this.parent = parent;
|
||
this.each = getEachForParent(parent);
|
||
this.keyFn = keyFn;
|
||
}
|
||
|
||
IndexedUniqueSequence.prototype = new Sequence();
|
||
|
||
IndexedUniqueSequence.prototype.eachArrayCache = function eachArrayCache(fn) {
|
||
// Basically the same implementation as w/ the set, but using an array because
|
||
// it's cheaper for smaller sequences.
|
||
var parent = this.parent,
|
||
keyFn = this.keyFn,
|
||
length = parent.length(),
|
||
cache = [],
|
||
find = arrayContains,
|
||
key, value,
|
||
i = -1,
|
||
j = 0;
|
||
|
||
while (++i < length) {
|
||
value = parent.get(i);
|
||
key = keyFn(value);
|
||
if (!find(cache, key)) {
|
||
cache.push(key);
|
||
if (fn(value, j++) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
IndexedUniqueSequence.prototype.eachSetCache = UniqueSequence.prototype.each;
|
||
|
||
function getEachForParent(parent) {
|
||
if (parent.length() < 100) {
|
||
return IndexedUniqueSequence.prototype.eachArrayCache;
|
||
} else {
|
||
return UniqueSequence.prototype.each;
|
||
}
|
||
}
|
||
|
||
// Now that we've fully initialized the ArrayLikeSequence prototype, we can
|
||
// set the prototype for MemoizedSequence.
|
||
|
||
MemoizedSequence.prototype = new ArrayLikeSequence();
|
||
|
||
MemoizedSequence.prototype.cache = function cache() {
|
||
return this.cachedResult || (this.cachedResult = this.parent.toArray());
|
||
};
|
||
|
||
MemoizedSequence.prototype.get = function get(i) {
|
||
return this.cache()[i];
|
||
};
|
||
|
||
MemoizedSequence.prototype.length = function length() {
|
||
return this.cache().length;
|
||
};
|
||
|
||
MemoizedSequence.prototype.slice = function slice(begin, end) {
|
||
return this.cache().slice(begin, end);
|
||
};
|
||
|
||
MemoizedSequence.prototype.toArray = function toArray() {
|
||
return this.cache().slice(0);
|
||
};
|
||
|
||
/**
|
||
* ArrayWrapper is the most basic {@link Sequence}. It directly wraps an array
|
||
* and implements the same methods as {@link ArrayLikeSequence}, but more
|
||
* efficiently.
|
||
*
|
||
* @constructor
|
||
*/
|
||
function ArrayWrapper(source) {
|
||
this.source = source;
|
||
}
|
||
|
||
ArrayWrapper.prototype = new ArrayLikeSequence();
|
||
|
||
ArrayWrapper.prototype.root = function root() {
|
||
return this;
|
||
};
|
||
|
||
ArrayWrapper.prototype.isAsync = function isAsync() {
|
||
return false;
|
||
};
|
||
|
||
/**
|
||
* Returns the element at the specified index in the source array.
|
||
*
|
||
* @param {number} i The index to access.
|
||
* @returns {*} The element.
|
||
*/
|
||
ArrayWrapper.prototype.get = function get(i) {
|
||
return this.source[i];
|
||
};
|
||
|
||
/**
|
||
* Returns the length of the source array.
|
||
*
|
||
* @returns {number} The length.
|
||
*/
|
||
ArrayWrapper.prototype.length = function length() {
|
||
return this.source.length;
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#each}.
|
||
*/
|
||
ArrayWrapper.prototype.each = function each(fn) {
|
||
return forEach(this.source, fn);
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#map}.
|
||
*/
|
||
ArrayWrapper.prototype.map = function map(mapFn) {
|
||
return new MappedArrayWrapper(this, createCallback(mapFn));
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#filter}.
|
||
*/
|
||
ArrayWrapper.prototype.filter = function filter(filterFn) {
|
||
return new FilteredArrayWrapper(this, createCallback(filterFn));
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#uniq}.
|
||
*/
|
||
ArrayWrapper.prototype.uniq = function uniq(keyFn) {
|
||
return new UniqueArrayWrapper(this, keyFn);
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link ArrayLikeSequence#concat}.
|
||
*
|
||
* @param {...*} var_args
|
||
*/
|
||
ArrayWrapper.prototype.concat = function concat(var_args) {
|
||
if (arguments.length === 1 && arguments[0] instanceof Array) {
|
||
return new ConcatArrayWrapper(this, (/** @type {Array} */ var_args));
|
||
} else {
|
||
return ArrayLikeSequence.prototype.concat.apply(this, arguments);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#toArray}.
|
||
*/
|
||
ArrayWrapper.prototype.toArray = function toArray() {
|
||
return this.source.slice(0);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function MappedArrayWrapper(parent, mapFn) {
|
||
this.parent = parent;
|
||
this.mapFn = mapFn;
|
||
}
|
||
|
||
MappedArrayWrapper.prototype = new ArrayLikeSequence();
|
||
|
||
MappedArrayWrapper.prototype.get = function get(i) {
|
||
var source = this.parent.source;
|
||
|
||
if (i < 0 || i >= source.length) {
|
||
return undefined;
|
||
}
|
||
|
||
return this.mapFn(source[i]);
|
||
};
|
||
|
||
MappedArrayWrapper.prototype.length = function length() {
|
||
return this.parent.source.length;
|
||
};
|
||
|
||
MappedArrayWrapper.prototype.each = function each(fn) {
|
||
var source = this.parent.source,
|
||
length = source.length,
|
||
mapFn = this.mapFn,
|
||
i = -1;
|
||
|
||
while (++i < length) {
|
||
if (fn(mapFn(source[i], i), i) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function FilteredArrayWrapper(parent, filterFn) {
|
||
this.parent = parent;
|
||
this.filterFn = filterFn;
|
||
}
|
||
|
||
FilteredArrayWrapper.prototype = new FilteredSequence();
|
||
|
||
FilteredArrayWrapper.prototype.each = function each(fn) {
|
||
var source = this.parent.source,
|
||
filterFn = this.filterFn,
|
||
length = source.length,
|
||
i = -1,
|
||
j = 0,
|
||
e;
|
||
|
||
while (++i < length) {
|
||
e = source[i];
|
||
if (filterFn(e, i) && fn(e, j++) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function UniqueArrayWrapper(parent, keyFn) {
|
||
this.parent = parent;
|
||
this.each = getEachForSource(parent.source);
|
||
this.keyFn = keyFn;
|
||
}
|
||
|
||
UniqueArrayWrapper.prototype = new Sequence();
|
||
|
||
UniqueArrayWrapper.prototype.eachNoCache = function eachNoCache(fn) {
|
||
var source = this.parent.source,
|
||
keyFn = this.keyFn,
|
||
length = source.length,
|
||
find = arrayContainsBefore,
|
||
value,
|
||
|
||
// Yes, this is hideous.
|
||
// Trying to get performance first, will refactor next!
|
||
i = -1,
|
||
k = 0;
|
||
|
||
while (++i < length) {
|
||
value = source[i];
|
||
if (!find(source, value, i, keyFn) && fn(value, k++) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
UniqueArrayWrapper.prototype.eachArrayCache = function eachArrayCache(fn) {
|
||
// Basically the same implementation as w/ the set, but using an array because
|
||
// it's cheaper for smaller sequences.
|
||
var source = this.parent.source,
|
||
keyFn = this.keyFn,
|
||
length = source.length,
|
||
cache = [],
|
||
find = arrayContains,
|
||
key, value,
|
||
i = -1,
|
||
j = 0;
|
||
|
||
if (keyFn) {
|
||
keyFn = createCallback(keyFn);
|
||
while (++i < length) {
|
||
value = source[i];
|
||
key = keyFn(value);
|
||
if (!find(cache, key)) {
|
||
cache.push(key);
|
||
if (fn(value, j++) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
} else {
|
||
while (++i < length) {
|
||
value = source[i];
|
||
if (!find(cache, value)) {
|
||
cache.push(value);
|
||
if (fn(value, j++) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
UniqueArrayWrapper.prototype.eachSetCache = UniqueSequence.prototype.each;
|
||
|
||
/**
|
||
* My latest findings here...
|
||
*
|
||
* So I hadn't really given the set-based approach enough credit. The main issue
|
||
* was that my Set implementation was totally not optimized at all. After pretty
|
||
* heavily optimizing it (just take a look; it's a monstrosity now!), it now
|
||
* becomes the fastest option for much smaller values of N.
|
||
*/
|
||
function getEachForSource(source) {
|
||
if (source.length < 40) {
|
||
return UniqueArrayWrapper.prototype.eachNoCache;
|
||
} else if (source.length < 100) {
|
||
return UniqueArrayWrapper.prototype.eachArrayCache;
|
||
} else {
|
||
return UniqueArrayWrapper.prototype.eachSetCache;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function ConcatArrayWrapper(parent, other) {
|
||
this.parent = parent;
|
||
this.other = other;
|
||
}
|
||
|
||
ConcatArrayWrapper.prototype = new ArrayLikeSequence();
|
||
|
||
ConcatArrayWrapper.prototype.get = function get(i) {
|
||
var source = this.parent.source,
|
||
sourceLength = source.length;
|
||
|
||
if (i < sourceLength) {
|
||
return source[i];
|
||
} else {
|
||
return this.other[i - sourceLength];
|
||
}
|
||
};
|
||
|
||
ConcatArrayWrapper.prototype.length = function length() {
|
||
return this.parent.source.length + this.other.length;
|
||
};
|
||
|
||
ConcatArrayWrapper.prototype.each = function each(fn) {
|
||
var source = this.parent.source,
|
||
sourceLength = source.length,
|
||
other = this.other,
|
||
otherLength = other.length,
|
||
i = 0,
|
||
j = -1;
|
||
|
||
while (++j < sourceLength) {
|
||
if (fn(source[j], i++) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
j = -1;
|
||
while (++j < otherLength) {
|
||
if (fn(other[j], i++) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* An `ObjectLikeSequence` object represents a sequence of key/value pairs.
|
||
*
|
||
* The initial sequence you get by wrapping an object with `Lazy(object)` is
|
||
* an `ObjectLikeSequence`.
|
||
*
|
||
* All methods of `ObjectLikeSequence` that conceptually should return
|
||
* something like an object return another `ObjectLikeSequence`.
|
||
*
|
||
* @public
|
||
* @constructor
|
||
*
|
||
* @examples
|
||
* var obj = { foo: 'bar' };
|
||
*
|
||
* Lazy(obj).assign({ bar: 'baz' }) // instanceof Lazy.ObjectLikeSequence
|
||
* Lazy(obj).defaults({ bar: 'baz' }) // instanceof Lazy.ObjectLikeSequence
|
||
* Lazy(obj).invert() // instanceof Lazy.ObjectLikeSequence
|
||
*/
|
||
function ObjectLikeSequence() {}
|
||
|
||
ObjectLikeSequence.prototype = new Sequence();
|
||
|
||
/**
|
||
* Create a new constructor function for a type inheriting from
|
||
* `ObjectLikeSequence`.
|
||
*
|
||
* @public
|
||
* @param {string|Array.<string>} methodName The name(s) of the method(s) to be
|
||
* used for constructing the new sequence. The method will be attached to
|
||
* the `ObjectLikeSequence` prototype so that it can be chained with any other
|
||
* methods that return object-like sequences.
|
||
* @param {Object} overrides An object containing function overrides for this
|
||
* new sequence type. **Must** include `each`. *May* include `init` and
|
||
* `get` (for looking up an element by key).
|
||
* @returns {Function} A constructor for a new type inheriting from
|
||
* `ObjectLikeSequence`.
|
||
*
|
||
* @examples
|
||
* function downcaseKey(value, key) {
|
||
* return [key.toLowerCase(), value];
|
||
* }
|
||
*
|
||
* Lazy.ObjectLikeSequence.define("caseInsensitive", {
|
||
* init: function() {
|
||
* var downcased = this.parent
|
||
* .map(downcaseKey)
|
||
* .toObject();
|
||
* this.downcased = Lazy(downcased);
|
||
* },
|
||
*
|
||
* get: function(key) {
|
||
* return this.downcased.get(key.toLowerCase());
|
||
* },
|
||
*
|
||
* each: function(fn) {
|
||
* return this.downcased.each(fn);
|
||
* }
|
||
* });
|
||
*
|
||
* Lazy({ Foo: 'bar' }).caseInsensitive() // sequence: { foo: 'bar' }
|
||
* Lazy({ FOO: 'bar' }).caseInsensitive().get('foo') // => 'bar'
|
||
* Lazy({ FOO: 'bar' }).caseInsensitive().get('FOO') // => 'bar'
|
||
*/
|
||
ObjectLikeSequence.define = function define(methodName, overrides) {
|
||
if (!overrides || typeof overrides.each !== 'function') {
|
||
throw new Error("A custom object-like sequence must implement *at least* each!");
|
||
}
|
||
|
||
return defineSequenceType(ObjectLikeSequence, methodName, overrides);
|
||
};
|
||
|
||
ObjectLikeSequence.prototype.value = function value() {
|
||
return this.toObject();
|
||
};
|
||
|
||
/**
|
||
* Gets the element at the specified key in this sequence.
|
||
*
|
||
* @public
|
||
* @param {string} key The key.
|
||
* @returns {*} The element.
|
||
*
|
||
* @examples
|
||
* Lazy({ foo: "bar" }).get("foo") // => "bar"
|
||
* Lazy({ foo: "bar" }).extend({ foo: "baz" }).get("foo") // => "baz"
|
||
* Lazy({ foo: "bar" }).defaults({ bar: "baz" }).get("bar") // => "baz"
|
||
* Lazy({ foo: "bar" }).invert().get("bar") // => "foo"
|
||
* Lazy({ foo: 1, bar: 2 }).pick(["foo"]).get("foo") // => 1
|
||
* Lazy({ foo: 1, bar: 2 }).pick(["foo"]).get("bar") // => undefined
|
||
* Lazy({ foo: 1, bar: 2 }).omit(["foo"]).get("bar") // => 2
|
||
* Lazy({ foo: 1, bar: 2 }).omit(["foo"]).get("foo") // => undefined
|
||
*/
|
||
ObjectLikeSequence.prototype.get = function get(key) {
|
||
var pair = this.pairs().find(function(pair) {
|
||
return pair[0] === key;
|
||
});
|
||
|
||
return pair ? pair[1] : undefined;
|
||
};
|
||
|
||
/**
|
||
* Returns a {@link Sequence} whose elements are the keys of this object-like
|
||
* sequence.
|
||
*
|
||
* @public
|
||
* @returns {Sequence} The sequence based on this sequence's keys.
|
||
*
|
||
* @examples
|
||
* Lazy({ hello: "hola", goodbye: "hasta luego" }).keys() // sequence: ["hello", "goodbye"]
|
||
*/
|
||
ObjectLikeSequence.prototype.keys = function keys() {
|
||
return this.map(function(v, k) { return k; });
|
||
};
|
||
|
||
/**
|
||
* Returns a {@link Sequence} whose elements are the values of this object-like
|
||
* sequence.
|
||
*
|
||
* @public
|
||
* @returns {Sequence} The sequence based on this sequence's values.
|
||
*
|
||
* @examples
|
||
* Lazy({ hello: "hola", goodbye: "hasta luego" }).values() // sequence: ["hola", "hasta luego"]
|
||
*/
|
||
ObjectLikeSequence.prototype.values = function values() {
|
||
return this.map(function(v, k) { return v; });
|
||
};
|
||
|
||
/**
|
||
* Throws an exception. Asynchronous iteration over object-like sequences is
|
||
* not supported.
|
||
*
|
||
* @public
|
||
* @examples
|
||
* Lazy({ foo: 'bar' }).async() // throws
|
||
*/
|
||
ObjectLikeSequence.prototype.async = function async() {
|
||
throw new Error('An ObjectLikeSequence does not support asynchronous iteration.');
|
||
};
|
||
|
||
ObjectLikeSequence.prototype.filter = function filter(filterFn) {
|
||
return new FilteredObjectLikeSequence(this, createCallback(filterFn));
|
||
};
|
||
|
||
function FilteredObjectLikeSequence(parent, filterFn) {
|
||
this.parent = parent;
|
||
this.filterFn = filterFn;
|
||
}
|
||
|
||
FilteredObjectLikeSequence.prototype = new ObjectLikeSequence();
|
||
|
||
FilteredObjectLikeSequence.prototype.each = function each(fn) {
|
||
var filterFn = this.filterFn;
|
||
|
||
return this.parent.each(function(v, k) {
|
||
if (filterFn(v, k)) {
|
||
return fn(v, k);
|
||
}
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Returns this same sequence. (Reversing an object-like sequence doesn't make
|
||
* any sense.)
|
||
*/
|
||
ObjectLikeSequence.prototype.reverse = function reverse() {
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns an {@link ObjectLikeSequence} whose elements are the combination of
|
||
* this sequence and another object. In the case of a key appearing in both this
|
||
* sequence and the given object, the other object's value will override the
|
||
* one in this sequence.
|
||
*
|
||
* @public
|
||
* @aka extend
|
||
* @param {Object} other The other object to assign to this sequence.
|
||
* @returns {ObjectLikeSequence} A new sequence comprising elements from this
|
||
* sequence plus the contents of `other`.
|
||
*
|
||
* @examples
|
||
* Lazy({ "uno": 1, "dos": 2 }).assign({ "tres": 3 }) // sequence: { uno: 1, dos: 2, tres: 3 }
|
||
* Lazy({ foo: "bar" }).assign({ foo: "baz" }); // sequence: { foo: "baz" }
|
||
*/
|
||
ObjectLikeSequence.prototype.assign = function assign(other) {
|
||
return new AssignSequence(this, other);
|
||
};
|
||
|
||
ObjectLikeSequence.prototype.extend = function extend(other) {
|
||
return this.assign(other);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function AssignSequence(parent, other) {
|
||
this.parent = parent;
|
||
this.other = other;
|
||
}
|
||
|
||
AssignSequence.prototype = new ObjectLikeSequence();
|
||
|
||
AssignSequence.prototype.get = function get(key) {
|
||
return this.other[key] || this.parent.get(key);
|
||
};
|
||
|
||
AssignSequence.prototype.each = function each(fn) {
|
||
var merged = new Set(),
|
||
done = false;
|
||
|
||
Lazy(this.other).each(function(value, key) {
|
||
if (fn(value, key) === false) {
|
||
done = true;
|
||
return false;
|
||
}
|
||
|
||
merged.add(key);
|
||
});
|
||
|
||
if (!done) {
|
||
return this.parent.each(function(value, key) {
|
||
if (!merged.contains(key) && fn(value, key) === false) {
|
||
return false;
|
||
}
|
||
});
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Returns an {@link ObjectLikeSequence} whose elements are the combination of
|
||
* this sequence and a 'default' object. In the case of a key appearing in both
|
||
* this sequence and the given object, this sequence's value will override the
|
||
* default object's.
|
||
*
|
||
* @public
|
||
* @param {Object} defaults The 'default' object to use for missing keys in this
|
||
* sequence.
|
||
* @returns {ObjectLikeSequence} A new sequence comprising elements from this
|
||
* sequence supplemented by the contents of `defaults`.
|
||
*
|
||
* @examples
|
||
* Lazy({ name: "Dan" }).defaults({ name: "User", password: "passw0rd" }) // sequence: { name: "Dan", password: "passw0rd" }
|
||
*/
|
||
ObjectLikeSequence.prototype.defaults = function defaults(defaults) {
|
||
return new DefaultsSequence(this, defaults);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function DefaultsSequence(parent, defaults) {
|
||
this.parent = parent;
|
||
this.defaults = defaults;
|
||
}
|
||
|
||
DefaultsSequence.prototype = new ObjectLikeSequence();
|
||
|
||
DefaultsSequence.prototype.get = function get(key) {
|
||
return this.parent.get(key) || this.defaults[key];
|
||
};
|
||
|
||
DefaultsSequence.prototype.each = function each(fn) {
|
||
var merged = new Set(),
|
||
done = false;
|
||
|
||
this.parent.each(function(value, key) {
|
||
if (fn(value, key) === false) {
|
||
done = true;
|
||
return false;
|
||
}
|
||
|
||
if (typeof value !== "undefined") {
|
||
merged.add(key);
|
||
}
|
||
});
|
||
|
||
if (!done) {
|
||
Lazy(this.defaults).each(function(value, key) {
|
||
if (!merged.contains(key) && fn(value, key) === false) {
|
||
return false;
|
||
}
|
||
});
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Returns an {@link ObjectLikeSequence} whose values are this sequence's keys,
|
||
* and whose keys are this sequence's values.
|
||
*
|
||
* @public
|
||
* @returns {ObjectLikeSequence} A new sequence comprising the inverted keys and
|
||
* values from this sequence.
|
||
*
|
||
* @examples
|
||
* Lazy({ first: "Dan", last: "Tao" }).invert() // sequence: { Dan: "first", Tao: "last" }
|
||
*/
|
||
ObjectLikeSequence.prototype.invert = function invert() {
|
||
return new InvertedSequence(this);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function InvertedSequence(parent) {
|
||
this.parent = parent;
|
||
}
|
||
|
||
InvertedSequence.prototype = new ObjectLikeSequence();
|
||
|
||
InvertedSequence.prototype.each = function each(fn) {
|
||
this.parent.each(function(value, key) {
|
||
return fn(key, value);
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Produces an {@link ObjectLikeSequence} consisting of all the recursively
|
||
* merged values from this and the given object(s) or sequence(s).
|
||
*
|
||
* Note that by default this method only merges "vanilla" objects (bags of
|
||
* key/value pairs), not arrays or any other custom object types. To customize
|
||
* how merging works, you can provide the mergeFn argument, e.g. to handling
|
||
* merging arrays, strings, or other types of objects.
|
||
*
|
||
* @public
|
||
* @param {...Object|ObjectLikeSequence} others The other object(s) or
|
||
* sequence(s) whose values will be merged into this one.
|
||
* @param {Function=} mergeFn An optional function used to customize merging
|
||
* behavior. The function should take two values as parameters and return
|
||
* whatever the "merged" form of those values is. If the function returns
|
||
* undefined then the new value will simply replace the old one in the
|
||
* final result.
|
||
* @returns {ObjectLikeSequence} The new sequence consisting of merged values.
|
||
*
|
||
* @examples
|
||
* // These examples are completely stolen from Lo-Dash's documentation:
|
||
* // lodash.com/docs#merge
|
||
*
|
||
* var names = {
|
||
* 'characters': [
|
||
* { 'name': 'barney' },
|
||
* { 'name': 'fred' }
|
||
* ]
|
||
* };
|
||
*
|
||
* var ages = {
|
||
* 'characters': [
|
||
* { 'age': 36 },
|
||
* { 'age': 40 }
|
||
* ]
|
||
* };
|
||
*
|
||
* var food = {
|
||
* 'fruits': ['apple'],
|
||
* 'vegetables': ['beet']
|
||
* };
|
||
*
|
||
* var otherFood = {
|
||
* 'fruits': ['banana'],
|
||
* 'vegetables': ['carrot']
|
||
* };
|
||
*
|
||
* function mergeArrays(a, b) {
|
||
* return Array.isArray(a) ? a.concat(b) : undefined;
|
||
* }
|
||
*
|
||
* Lazy(names).merge(ages); // => sequence: { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] }
|
||
* Lazy(food).merge(otherFood, mergeArrays); // => sequence: { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] }
|
||
*
|
||
* // ----- Now for my own tests: -----
|
||
*
|
||
* // merges objects
|
||
* Lazy({ foo: 1 }).merge({ foo: 2 }); // => sequence: { foo: 2 }
|
||
* Lazy({ foo: 1 }).merge({ bar: 2 }); // => sequence: { foo: 1, bar: 2 }
|
||
*
|
||
* // goes deep
|
||
* Lazy({ foo: { bar: 1 } }).merge({ foo: { bar: 2 } }); // => sequence: { foo: { bar: 2 } }
|
||
* Lazy({ foo: { bar: 1 } }).merge({ foo: { baz: 2 } }); // => sequence: { foo: { bar: 1, baz: 2 } }
|
||
* Lazy({ foo: { bar: 1 } }).merge({ foo: { baz: 2 } }); // => sequence: { foo: { bar: 1, baz: 2 } }
|
||
*
|
||
* // gives precedence to later sources
|
||
* Lazy({ foo: 1 }).merge({ bar: 2 }, { bar: 3 }); // => sequence: { foo: 1, bar: 3 }
|
||
*
|
||
* // undefined gets passed over
|
||
* Lazy({ foo: 1 }).merge({ foo: undefined }); // => sequence: { foo: 1 }
|
||
*
|
||
* // null doesn't get passed over
|
||
* Lazy({ foo: 1 }).merge({ foo: null }); // => sequence: { foo: null }
|
||
*
|
||
* // array contents get merged as well
|
||
* Lazy({ foo: [{ bar: 1 }] }).merge({ foo: [{ baz: 2 }] }); // => sequence: { foo: [{ bar: 1, baz: 2}] }
|
||
*/
|
||
ObjectLikeSequence.prototype.merge = function merge(var_args) {
|
||
var mergeFn = arguments.length > 1 && typeof arguments[arguments.length - 1] === "function" ?
|
||
arrayPop.call(arguments) : null;
|
||
return new MergedSequence(this, arraySlice.call(arguments, 0), mergeFn);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function MergedSequence(parent, others, mergeFn) {
|
||
this.parent = parent;
|
||
this.others = others;
|
||
this.mergeFn = mergeFn;
|
||
}
|
||
|
||
MergedSequence.prototype = new ObjectLikeSequence();
|
||
|
||
MergedSequence.prototype.each = function each(fn) {
|
||
var others = this.others,
|
||
mergeFn = this.mergeFn || mergeObjects,
|
||
keys = {};
|
||
|
||
var iteratedFullSource = this.parent.each(function(value, key) {
|
||
var merged = value;
|
||
|
||
forEach(others, function(other) {
|
||
if (key in other) {
|
||
merged = mergeFn(merged, other[key]);
|
||
}
|
||
});
|
||
|
||
keys[key] = true;
|
||
|
||
return fn(merged, key);
|
||
});
|
||
|
||
if (iteratedFullSource === false) {
|
||
return false;
|
||
}
|
||
|
||
var remaining = {};
|
||
|
||
forEach(others, function(other) {
|
||
for (var k in other) {
|
||
if (!keys[k]) {
|
||
remaining[k] = mergeFn(remaining[k], other[k]);
|
||
}
|
||
}
|
||
});
|
||
|
||
return Lazy(remaining).each(fn);
|
||
};
|
||
|
||
/**
|
||
* @private
|
||
* @examples
|
||
* mergeObjects({ foo: 1 }, { bar: 2 }); // => { foo: 1, bar: 2 }
|
||
* mergeObjects({ foo: { bar: 1 } }, { foo: { baz: 2 } }); // => { foo: { bar: 1, baz: 2 } }
|
||
* mergeObjects({ foo: { bar: 1 } }, { foo: undefined }); // => { foo: { bar: 1 } }
|
||
* mergeObjects({ foo: { bar: 1 } }, { foo: null }); // => { foo: null }
|
||
* mergeObjects({ array: [0, 1, 2] }, { array: [3, 4, 5] }).array; // instanceof Array
|
||
* mergeObjects({ date: new Date() }, { date: new Date() }).date; // instanceof Date
|
||
* mergeObjects([{ foo: 1 }], [{ bar: 2 }]); // => [{ foo: 1, bar: 2 }]
|
||
*/
|
||
function mergeObjects(a, b) {
|
||
var merged, prop;
|
||
|
||
if (typeof b === 'undefined') {
|
||
return a;
|
||
}
|
||
|
||
// Check that we're dealing with two objects or two arrays.
|
||
if (isVanillaObject(a) && isVanillaObject(b)) {
|
||
merged = {};
|
||
} else if (a instanceof Array && b instanceof Array) {
|
||
merged = [];
|
||
} else {
|
||
// Otherwise there's no merging to do -- just replace a w/ b.
|
||
return b;
|
||
}
|
||
|
||
for (prop in a) {
|
||
merged[prop] = mergeObjects(a[prop], b[prop]);
|
||
}
|
||
for (prop in b) {
|
||
if (!merged[prop]) {
|
||
merged[prop] = b[prop];
|
||
}
|
||
}
|
||
return merged;
|
||
}
|
||
|
||
/**
|
||
* Checks whether an object is a "vanilla" object, i.e. {'foo': 'bar'} as
|
||
* opposed to an array, date, etc.
|
||
*
|
||
* @private
|
||
* @examples
|
||
* isVanillaObject({foo: 'bar'}); // => true
|
||
* isVanillaObject(new Date()); // => false
|
||
* isVanillaObject([1, 2, 3]); // => false
|
||
*/
|
||
function isVanillaObject(object) {
|
||
return object && object.constructor === Object;
|
||
}
|
||
|
||
/**
|
||
* Creates a {@link Sequence} consisting of the keys from this sequence whose
|
||
* values are functions.
|
||
*
|
||
* @public
|
||
* @aka methods
|
||
* @returns {Sequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* var dog = {
|
||
* name: "Fido",
|
||
* breed: "Golden Retriever",
|
||
* bark: function() { console.log("Woof!"); },
|
||
* wagTail: function() { console.log("TODO: implement robotic dog interface"); }
|
||
* };
|
||
*
|
||
* Lazy(dog).functions() // sequence: ["bark", "wagTail"]
|
||
*/
|
||
ObjectLikeSequence.prototype.functions = function functions() {
|
||
return this
|
||
.filter(function(v, k) { return typeof(v) === "function"; })
|
||
.map(function(v, k) { return k; });
|
||
};
|
||
|
||
ObjectLikeSequence.prototype.methods = function methods() {
|
||
return this.functions();
|
||
};
|
||
|
||
/**
|
||
* Creates an {@link ObjectLikeSequence} consisting of the key/value pairs from
|
||
* this sequence whose keys are included in the given array of property names.
|
||
*
|
||
* @public
|
||
* @param {Array} properties An array of the properties to "pick" from this
|
||
* sequence.
|
||
* @returns {ObjectLikeSequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* var players = {
|
||
* "who": "first",
|
||
* "what": "second",
|
||
* "i don't know": "third"
|
||
* };
|
||
*
|
||
* Lazy(players).pick(["who", "what"]) // sequence: { who: "first", what: "second" }
|
||
*/
|
||
ObjectLikeSequence.prototype.pick = function pick(properties) {
|
||
return new PickSequence(this, properties);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function PickSequence(parent, properties) {
|
||
this.parent = parent;
|
||
this.properties = properties;
|
||
}
|
||
|
||
PickSequence.prototype = new ObjectLikeSequence();
|
||
|
||
PickSequence.prototype.get = function get(key) {
|
||
return arrayContains(this.properties, key) ? this.parent.get(key) : undefined;
|
||
};
|
||
|
||
PickSequence.prototype.each = function each(fn) {
|
||
var inArray = arrayContains,
|
||
properties = this.properties;
|
||
|
||
return this.parent.each(function(value, key) {
|
||
if (inArray(properties, key)) {
|
||
return fn(value, key);
|
||
}
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Creates an {@link ObjectLikeSequence} consisting of the key/value pairs from
|
||
* this sequence excluding those with the specified keys.
|
||
*
|
||
* @public
|
||
* @param {Array} properties An array of the properties to *omit* from this
|
||
* sequence.
|
||
* @returns {ObjectLikeSequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* var players = {
|
||
* "who": "first",
|
||
* "what": "second",
|
||
* "i don't know": "third"
|
||
* };
|
||
*
|
||
* Lazy(players).omit(["who", "what"]) // sequence: { "i don't know": "third" }
|
||
*/
|
||
ObjectLikeSequence.prototype.omit = function omit(properties) {
|
||
return new OmitSequence(this, properties);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function OmitSequence(parent, properties) {
|
||
this.parent = parent;
|
||
this.properties = properties;
|
||
}
|
||
|
||
OmitSequence.prototype = new ObjectLikeSequence();
|
||
|
||
OmitSequence.prototype.get = function get(key) {
|
||
return arrayContains(this.properties, key) ? undefined : this.parent.get(key);
|
||
};
|
||
|
||
OmitSequence.prototype.each = function each(fn) {
|
||
var inArray = arrayContains,
|
||
properties = this.properties;
|
||
|
||
return this.parent.each(function(value, key) {
|
||
if (!inArray(properties, key)) {
|
||
return fn(value, key);
|
||
}
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Maps the key/value pairs in this sequence to arrays.
|
||
*
|
||
* @public
|
||
* @aka toArray
|
||
* @returns {Sequence} An sequence of `[key, value]` pairs.
|
||
*
|
||
* @examples
|
||
* var colorCodes = {
|
||
* red: "#f00",
|
||
* green: "#0f0",
|
||
* blue: "#00f"
|
||
* };
|
||
*
|
||
* Lazy(colorCodes).pairs() // sequence: [["red", "#f00"], ["green", "#0f0"], ["blue", "#00f"]]
|
||
*/
|
||
ObjectLikeSequence.prototype.pairs = function pairs() {
|
||
return this.map(function(v, k) { return [k, v]; });
|
||
};
|
||
|
||
/**
|
||
* Creates an array from the key/value pairs in this sequence.
|
||
*
|
||
* @public
|
||
* @returns {Array} An array of `[key, value]` elements.
|
||
*
|
||
* @examples
|
||
* var colorCodes = {
|
||
* red: "#f00",
|
||
* green: "#0f0",
|
||
* blue: "#00f"
|
||
* };
|
||
*
|
||
* Lazy(colorCodes).toArray() // => [["red", "#f00"], ["green", "#0f0"], ["blue", "#00f"]]
|
||
*/
|
||
ObjectLikeSequence.prototype.toArray = function toArray() {
|
||
return this.pairs().toArray();
|
||
};
|
||
|
||
/**
|
||
* Creates an object with the key/value pairs from this sequence.
|
||
*
|
||
* @public
|
||
* @returns {Object} An object with the same key/value pairs as this sequence.
|
||
*
|
||
* @examples
|
||
* var colorCodes = {
|
||
* red: "#f00",
|
||
* green: "#0f0",
|
||
* blue: "#00f"
|
||
* };
|
||
*
|
||
* Lazy(colorCodes).toObject() // => { red: "#f00", green: "#0f0", blue: "#00f" }
|
||
*/
|
||
ObjectLikeSequence.prototype.toObject = function toObject() {
|
||
return this.reduce(function(object, value, key) {
|
||
object[key] = value;
|
||
return object;
|
||
}, {});
|
||
};
|
||
|
||
// Now that we've fully initialized the ObjectLikeSequence prototype, we can
|
||
// actually set the prototypes for GroupedSequence, IndexedSequence, and
|
||
// CountedSequence.
|
||
|
||
GroupedSequence.prototype = new ObjectLikeSequence();
|
||
|
||
GroupedSequence.prototype.each = function each(fn) {
|
||
var keyFn = createCallback(this.keyFn),
|
||
valFn = createCallback(this.valFn),
|
||
result;
|
||
|
||
result = this.parent.reduce(function(grouped,e) {
|
||
var key = keyFn(e),
|
||
val = valFn(e);
|
||
if (!(grouped[key] instanceof Array)) {
|
||
grouped[key] = [val];
|
||
} else {
|
||
grouped[key].push(val);
|
||
}
|
||
return grouped;
|
||
},{});
|
||
|
||
return transform(function(grouped) {
|
||
for (var key in grouped) {
|
||
if (fn(grouped[key], key) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
}, result);
|
||
};
|
||
|
||
IndexedSequence.prototype = new ObjectLikeSequence();
|
||
|
||
IndexedSequence.prototype.each = function each(fn) {
|
||
var keyFn = createCallback(this.keyFn),
|
||
valFn = createCallback(this.valFn),
|
||
indexed = {};
|
||
|
||
return this.parent.each(function(e) {
|
||
var key = keyFn(e),
|
||
val = valFn(e);
|
||
|
||
if (!indexed[key]) {
|
||
indexed[key] = val;
|
||
return fn(val, key);
|
||
}
|
||
});
|
||
};
|
||
|
||
CountedSequence.prototype = new ObjectLikeSequence();
|
||
|
||
CountedSequence.prototype.each = function each(fn) {
|
||
var keyFn = createCallback(this.keyFn),
|
||
counted = {};
|
||
|
||
this.parent.each(function(e) {
|
||
var key = keyFn(e);
|
||
if (!counted[key]) {
|
||
counted[key] = 1;
|
||
} else {
|
||
counted[key] += 1;
|
||
}
|
||
});
|
||
|
||
for (var key in counted) {
|
||
if (fn(counted[key], key) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* Watches for all changes to a specified property (or properties) of an
|
||
* object and produces a sequence whose elements have the properties
|
||
* `{ property, value }` indicating which property changed and what it was
|
||
* changed to.
|
||
*
|
||
* Note that this method **only works on directly wrapped objects**; it will
|
||
* *not* work on any arbitrary {@link ObjectLikeSequence}.
|
||
*
|
||
* @public
|
||
* @param {(string|Array)=} propertyNames A property name or array of property
|
||
* names to watch. If this parameter is `undefined`, all of the object's
|
||
* current (enumerable) properties will be watched.
|
||
* @returns {Sequence} A sequence comprising `{ property, value }` objects
|
||
* describing each change to the specified property/properties.
|
||
*
|
||
* @examples
|
||
* var obj = {},
|
||
* changes = [];
|
||
*
|
||
* Lazy(obj).watch('foo').each(function(change) {
|
||
* changes.push(change);
|
||
* });
|
||
*
|
||
* obj.foo = 1;
|
||
* obj.bar = 2;
|
||
* obj.foo = 3;
|
||
*
|
||
* obj.foo; // => 3
|
||
* changes; // => [{ property: 'foo', value: 1 }, { property: 'foo', value: 3 }]
|
||
*/
|
||
ObjectLikeSequence.prototype.watch = function watch(propertyNames) {
|
||
throw new Error('You can only call #watch on a directly wrapped object.');
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function ObjectWrapper(source) {
|
||
this.source = source;
|
||
}
|
||
|
||
ObjectWrapper.prototype = new ObjectLikeSequence();
|
||
|
||
ObjectWrapper.prototype.root = function root() {
|
||
return this;
|
||
};
|
||
|
||
ObjectWrapper.prototype.isAsync = function isAsync() {
|
||
return false;
|
||
};
|
||
|
||
ObjectWrapper.prototype.get = function get(key) {
|
||
return this.source[key];
|
||
};
|
||
|
||
ObjectWrapper.prototype.each = function each(fn) {
|
||
var source = this.source,
|
||
key;
|
||
|
||
for (key in source) {
|
||
if (fn(source[key], key) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* A `StringLikeSequence` represents a sequence of characters.
|
||
*
|
||
* The initial sequence you get by wrapping a string with `Lazy(string)` is a
|
||
* `StringLikeSequence`.
|
||
*
|
||
* All methods of `StringLikeSequence` that conceptually should return
|
||
* something like a string return another `StringLikeSequence`.
|
||
*
|
||
* @public
|
||
* @constructor
|
||
*
|
||
* @examples
|
||
* function upcase(str) { return str.toUpperCase(); }
|
||
*
|
||
* Lazy('foo') // instanceof Lazy.StringLikeSequence
|
||
* Lazy('foo').toUpperCase() // instanceof Lazy.StringLikeSequence
|
||
* Lazy('foo').reverse() // instanceof Lazy.StringLikeSequence
|
||
* Lazy('foo').take(2) // instanceof Lazy.StringLikeSequence
|
||
* Lazy('foo').drop(1) // instanceof Lazy.StringLikeSequence
|
||
* Lazy('foo').substring(1) // instanceof Lazy.StringLikeSequence
|
||
*
|
||
* // Note that `map` does not create a `StringLikeSequence` because there's
|
||
* // no guarantee the mapping function will return characters. In the event
|
||
* // you do want to map a string onto a string-like sequence, use
|
||
* // `mapString`:
|
||
* Lazy('foo').map(Lazy.identity) // instanceof Lazy.ArrayLikeSequence
|
||
* Lazy('foo').mapString(Lazy.identity) // instanceof Lazy.StringLikeSequence
|
||
*/
|
||
function StringLikeSequence() {}
|
||
|
||
StringLikeSequence.prototype = new ArrayLikeSequence();
|
||
|
||
/**
|
||
* Create a new constructor function for a type inheriting from
|
||
* `StringLikeSequence`.
|
||
*
|
||
* @public
|
||
* @param {string|Array.<string>} methodName The name(s) of the method(s) to be
|
||
* used for constructing the new sequence. The method will be attached to
|
||
* the `StringLikeSequence` prototype so that it can be chained with any other
|
||
* methods that return string-like sequences.
|
||
* @param {Object} overrides An object containing function overrides for this
|
||
* new sequence type. Has the same requirements as
|
||
* {@link ArrayLikeSequence.define}.
|
||
* @returns {Function} A constructor for a new type inheriting from
|
||
* `StringLikeSequence`.
|
||
*
|
||
* @examples
|
||
* Lazy.StringLikeSequence.define("zomg", {
|
||
* length: function() {
|
||
* return this.parent.length() + "!!ZOMG!!!1".length;
|
||
* },
|
||
*
|
||
* get: function(i) {
|
||
* if (i < this.parent.length()) {
|
||
* return this.parent.get(i);
|
||
* }
|
||
* return "!!ZOMG!!!1".charAt(i - this.parent.length());
|
||
* }
|
||
* });
|
||
*
|
||
* Lazy('foo').zomg() // sequence: "foo!!ZOMG!!!1"
|
||
*/
|
||
StringLikeSequence.define = function define(methodName, overrides) {
|
||
if (!overrides || typeof overrides.get !== 'function') {
|
||
throw new Error("A custom string-like sequence must implement *at least* get!");
|
||
}
|
||
|
||
return defineSequenceType(StringLikeSequence, methodName, overrides);
|
||
};
|
||
|
||
StringLikeSequence.prototype.value = function value() {
|
||
return this.toString();
|
||
};
|
||
|
||
/**
|
||
* Returns an {@link IndexedIterator} that will step over each character in this
|
||
* sequence one by one.
|
||
*
|
||
* @returns {IndexedIterator} The iterator.
|
||
*/
|
||
StringLikeSequence.prototype.getIterator = function getIterator() {
|
||
return new CharIterator(this);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function CharIterator(source) {
|
||
this.source = Lazy(source);
|
||
this.index = -1;
|
||
}
|
||
|
||
CharIterator.prototype.current = function current() {
|
||
return this.source.charAt(this.index);
|
||
};
|
||
|
||
CharIterator.prototype.moveNext = function moveNext() {
|
||
return (++this.index < this.source.length());
|
||
};
|
||
|
||
/**
|
||
* Returns the character at the given index of this sequence, or the empty
|
||
* string if the specified index lies outside the bounds of the sequence.
|
||
*
|
||
* @public
|
||
* @param {number} i The index of this sequence.
|
||
* @returns {string} The character at the specified index.
|
||
*
|
||
* @examples
|
||
* Lazy("foo").charAt(0) // => "f"
|
||
* Lazy("foo").charAt(-1) // => ""
|
||
* Lazy("foo").charAt(10) // => ""
|
||
*/
|
||
StringLikeSequence.prototype.charAt = function charAt(i) {
|
||
return this.get(i);
|
||
};
|
||
|
||
/**
|
||
* Returns the character code at the given index of this sequence, or `NaN` if
|
||
* the index lies outside the bounds of the sequence.
|
||
*
|
||
* @public
|
||
* @param {number} i The index of the character whose character code you want.
|
||
* @returns {number} The character code.
|
||
*
|
||
* @examples
|
||
* Lazy("abc").charCodeAt(0) // => 97
|
||
* Lazy("abc").charCodeAt(-1) // => NaN
|
||
* Lazy("abc").charCodeAt(10) // => NaN
|
||
*/
|
||
StringLikeSequence.prototype.charCodeAt = function charCodeAt(i) {
|
||
var char = this.charAt(i);
|
||
if (!char) { return NaN; }
|
||
|
||
return char.charCodeAt(0);
|
||
};
|
||
|
||
/**
|
||
* Returns a {@link StringLikeSequence} comprising the characters from *this*
|
||
* sequence starting at `start` and ending at `stop` (exclusive), or---if
|
||
* `stop` is `undefined`, including the rest of the sequence.
|
||
*
|
||
* @public
|
||
* @param {number} start The index where this sequence should begin.
|
||
* @param {number=} stop The index (exclusive) where this sequence should end.
|
||
* @returns {StringLikeSequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* Lazy("foo").substring(1) // sequence: "oo"
|
||
* Lazy("foo").substring(-1) // sequence: "foo"
|
||
* Lazy("hello").substring(1, 3) // sequence: "el"
|
||
* Lazy("hello").substring(1, 9) // sequence: "ello"
|
||
*/
|
||
StringLikeSequence.prototype.substring = function substring(start, stop) {
|
||
return new StringSegment(this, start, stop);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function StringSegment(parent, start, stop) {
|
||
this.parent = parent;
|
||
this.start = Math.max(0, start);
|
||
this.stop = stop;
|
||
}
|
||
|
||
StringSegment.prototype = new StringLikeSequence();
|
||
|
||
StringSegment.prototype.get = function get(i) {
|
||
return this.parent.get(i + this.start);
|
||
};
|
||
|
||
StringSegment.prototype.length = function length() {
|
||
return (typeof this.stop === "number" ? this.stop : this.parent.length()) - this.start;
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#first} that returns another
|
||
* {@link StringLikeSequence} (or just the first character, if `count` is
|
||
* undefined).
|
||
*
|
||
* @public
|
||
* @examples
|
||
* Lazy('foo').first() // => 'f'
|
||
* Lazy('fo').first(2) // sequence: 'fo'
|
||
* Lazy('foo').first(10) // sequence: 'foo'
|
||
* Lazy('foo').toUpperCase().first() // => 'F'
|
||
* Lazy('foo').toUpperCase().first(2) // sequence: 'FO'
|
||
*/
|
||
StringLikeSequence.prototype.first = function first(count) {
|
||
if (typeof count === "undefined") {
|
||
return this.charAt(0);
|
||
}
|
||
|
||
return this.substring(0, count);
|
||
};
|
||
|
||
/**
|
||
* An optimized version of {@link Sequence#last} that returns another
|
||
* {@link StringLikeSequence} (or just the last character, if `count` is
|
||
* undefined).
|
||
*
|
||
* @public
|
||
* @examples
|
||
* Lazy('foo').last() // => 'o'
|
||
* Lazy('foo').last(2) // sequence: 'oo'
|
||
* Lazy('foo').last(10) // sequence: 'foo'
|
||
* Lazy('foo').toUpperCase().last() // => 'O'
|
||
* Lazy('foo').toUpperCase().last(2) // sequence: 'OO'
|
||
*/
|
||
StringLikeSequence.prototype.last = function last(count) {
|
||
if (typeof count === "undefined") {
|
||
return this.charAt(this.length() - 1);
|
||
}
|
||
|
||
return this.substring(this.length() - count);
|
||
};
|
||
|
||
StringLikeSequence.prototype.drop = function drop(count) {
|
||
return this.substring(count);
|
||
};
|
||
|
||
/**
|
||
* Finds the index of the first occurrence of the given substring within this
|
||
* sequence, starting from the specified index (or the beginning of the
|
||
* sequence).
|
||
*
|
||
* @public
|
||
* @param {string} substring The substring to search for.
|
||
* @param {number=} startIndex The index from which to start the search.
|
||
* @returns {number} The first index where the given substring is found, or
|
||
* -1 if it isn't in the sequence.
|
||
*
|
||
* @examples
|
||
* Lazy('canal').indexOf('a') // => 1
|
||
* Lazy('canal').indexOf('a', 2) // => 3
|
||
* Lazy('canal').indexOf('ana') // => 1
|
||
* Lazy('canal').indexOf('andy') // => -1
|
||
* Lazy('canal').indexOf('x') // => -1
|
||
*/
|
||
StringLikeSequence.prototype.indexOf = function indexOf(substring, startIndex) {
|
||
return this.toString().indexOf(substring, startIndex);
|
||
};
|
||
|
||
/**
|
||
* Finds the index of the last occurrence of the given substring within this
|
||
* sequence, starting from the specified index (or the end of the sequence)
|
||
* and working backwards.
|
||
*
|
||
* @public
|
||
* @param {string} substring The substring to search for.
|
||
* @param {number=} startIndex The index from which to start the search.
|
||
* @returns {number} The last index where the given substring is found, or
|
||
* -1 if it isn't in the sequence.
|
||
*
|
||
* @examples
|
||
* Lazy('canal').lastIndexOf('a') // => 3
|
||
* Lazy('canal').lastIndexOf('a', 2) // => 1
|
||
* Lazy('canal').lastIndexOf('ana') // => 1
|
||
* Lazy('canal').lastIndexOf('andy') // => -1
|
||
* Lazy('canal').lastIndexOf('x') // => -1
|
||
*/
|
||
StringLikeSequence.prototype.lastIndexOf = function lastIndexOf(substring, startIndex) {
|
||
return this.toString().lastIndexOf(substring, startIndex);
|
||
};
|
||
|
||
/**
|
||
* Checks if this sequence contains a given substring.
|
||
*
|
||
* @public
|
||
* @param {string} substring The substring to check for.
|
||
* @returns {boolean} Whether or not this sequence contains `substring`.
|
||
*
|
||
* @examples
|
||
* Lazy('hello').contains('ell') // => true
|
||
* Lazy('hello').contains('') // => true
|
||
* Lazy('hello').contains('abc') // => false
|
||
*/
|
||
StringLikeSequence.prototype.contains = function contains(substring) {
|
||
return this.indexOf(substring) !== -1;
|
||
};
|
||
|
||
/**
|
||
* Checks if this sequence ends with a given suffix.
|
||
*
|
||
* @public
|
||
* @param {string} suffix The suffix to check for.
|
||
* @returns {boolean} Whether or not this sequence ends with `suffix`.
|
||
*
|
||
* @examples
|
||
* Lazy('foo').endsWith('oo') // => true
|
||
* Lazy('foo').endsWith('') // => true
|
||
* Lazy('foo').endsWith('abc') // => false
|
||
*/
|
||
StringLikeSequence.prototype.endsWith = function endsWith(suffix) {
|
||
return this.substring(this.length() - suffix.length).toString() === suffix;
|
||
};
|
||
|
||
/**
|
||
* Checks if this sequence starts with a given prefix.
|
||
*
|
||
* @public
|
||
* @param {string} prefix The prefix to check for.
|
||
* @returns {boolean} Whether or not this sequence starts with `prefix`.
|
||
*
|
||
* @examples
|
||
* Lazy('foo').startsWith('fo') // => true
|
||
* Lazy('foo').startsWith('') // => true
|
||
* Lazy('foo').startsWith('abc') // => false
|
||
*/
|
||
StringLikeSequence.prototype.startsWith = function startsWith(prefix) {
|
||
return this.substring(0, prefix.length).toString() === prefix;
|
||
};
|
||
|
||
/**
|
||
* Converts all of the characters in this string to uppercase.
|
||
*
|
||
* @public
|
||
* @returns {StringLikeSequence} A new sequence with the same characters as
|
||
* this sequence, all uppercase.
|
||
*
|
||
* @examples
|
||
* function nextLetter(a) {
|
||
* return String.fromCharCode(a.charCodeAt(0) + 1);
|
||
* }
|
||
*
|
||
* Lazy('foo').toUpperCase() // sequence: 'FOO'
|
||
* Lazy('foo').substring(1).toUpperCase() // sequence: 'OO'
|
||
* Lazy('abc').mapString(nextLetter).toUpperCase() // sequence: 'BCD'
|
||
*/
|
||
StringLikeSequence.prototype.toUpperCase = function toUpperCase() {
|
||
return this.mapString(function(char) { return char.toUpperCase(); });
|
||
};
|
||
|
||
/**
|
||
* Converts all of the characters in this string to lowercase.
|
||
*
|
||
* @public
|
||
* @returns {StringLikeSequence} A new sequence with the same characters as
|
||
* this sequence, all lowercase.
|
||
*
|
||
* @examples
|
||
* function nextLetter(a) {
|
||
* return String.fromCharCode(a.charCodeAt(0) + 1);
|
||
* }
|
||
*
|
||
* Lazy('FOO').toLowerCase() // sequence: 'foo'
|
||
* Lazy('FOO').substring(1).toLowerCase() // sequence: 'oo'
|
||
* Lazy('ABC').mapString(nextLetter).toLowerCase() // sequence: 'bcd'
|
||
*/
|
||
StringLikeSequence.prototype.toLowerCase = function toLowerCase() {
|
||
return this.mapString(function(char) { return char.toLowerCase(); });
|
||
};
|
||
|
||
/**
|
||
* Maps the characters of this sequence onto a new {@link StringLikeSequence}.
|
||
*
|
||
* @public
|
||
* @param {Function} mapFn The function used to map characters from this
|
||
* sequence onto the new sequence.
|
||
* @returns {StringLikeSequence} The new sequence.
|
||
*
|
||
* @examples
|
||
* function upcase(char) { return char.toUpperCase(); }
|
||
*
|
||
* Lazy("foo").mapString(upcase) // sequence: "FOO"
|
||
* Lazy("foo").mapString(upcase).charAt(0) // => "F"
|
||
* Lazy("foo").mapString(upcase).charCodeAt(0) // => 70
|
||
* Lazy("foo").mapString(upcase).substring(1) // sequence: "OO"
|
||
*/
|
||
StringLikeSequence.prototype.mapString = function mapString(mapFn) {
|
||
return new MappedStringLikeSequence(this, mapFn);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function MappedStringLikeSequence(parent, mapFn) {
|
||
this.parent = parent;
|
||
this.mapFn = mapFn;
|
||
}
|
||
|
||
MappedStringLikeSequence.prototype = new StringLikeSequence();
|
||
MappedStringLikeSequence.prototype.get = IndexedMappedSequence.prototype.get;
|
||
MappedStringLikeSequence.prototype.length = IndexedMappedSequence.prototype.length;
|
||
|
||
/**
|
||
* Returns a copy of this sequence that reads back to front.
|
||
*
|
||
* @public
|
||
*
|
||
* @examples
|
||
* Lazy("abcdefg").reverse() // sequence: "gfedcba"
|
||
*/
|
||
StringLikeSequence.prototype.reverse = function reverse() {
|
||
return new ReversedStringLikeSequence(this);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function ReversedStringLikeSequence(parent) {
|
||
this.parent = parent;
|
||
}
|
||
|
||
ReversedStringLikeSequence.prototype = new StringLikeSequence();
|
||
ReversedStringLikeSequence.prototype.get = IndexedReversedSequence.prototype.get;
|
||
ReversedStringLikeSequence.prototype.length = IndexedReversedSequence.prototype.length;
|
||
|
||
StringLikeSequence.prototype.toString = function toString() {
|
||
return this.join("");
|
||
};
|
||
|
||
/**
|
||
* Creates a {@link Sequence} comprising all of the matches for the specified
|
||
* pattern in the underlying string.
|
||
*
|
||
* @public
|
||
* @param {RegExp} pattern The pattern to match.
|
||
* @returns {Sequence} A sequence of all the matches.
|
||
*
|
||
* @examples
|
||
* Lazy("abracadabra").match(/a[bcd]/) // sequence: ["ab", "ac", "ad", "ab"]
|
||
* Lazy("fee fi fo fum").match(/\w+/) // sequence: ["fee", "fi", "fo", "fum"]
|
||
* Lazy("hello").match(/xyz/) // sequence: []
|
||
*/
|
||
StringLikeSequence.prototype.match = function match(pattern) {
|
||
return new StringMatchSequence(this, pattern);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function StringMatchSequence(parent, pattern) {
|
||
this.parent = parent;
|
||
this.pattern = pattern;
|
||
}
|
||
|
||
StringMatchSequence.prototype = new Sequence();
|
||
|
||
StringMatchSequence.prototype.getIterator = function getIterator() {
|
||
return new StringMatchIterator(this.parent.toString(), this.pattern);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function StringMatchIterator(source, pattern) {
|
||
this.source = source;
|
||
this.pattern = cloneRegex(pattern);
|
||
}
|
||
|
||
StringMatchIterator.prototype.current = function current() {
|
||
return this.match[0];
|
||
};
|
||
|
||
StringMatchIterator.prototype.moveNext = function moveNext() {
|
||
return !!(this.match = this.pattern.exec(this.source));
|
||
};
|
||
|
||
/**
|
||
* Creates a {@link Sequence} comprising all of the substrings of this string
|
||
* separated by the given delimiter, which can be either a string or a regular
|
||
* expression.
|
||
*
|
||
* @public
|
||
* @param {string|RegExp} delimiter The delimiter to use for recognizing
|
||
* substrings.
|
||
* @returns {Sequence} A sequence of all the substrings separated by the given
|
||
* delimiter.
|
||
*
|
||
* @examples
|
||
* Lazy("foo").split("") // sequence: ["f", "o", "o"]
|
||
* Lazy("yo dawg").split(" ") // sequence: ["yo", "dawg"]
|
||
* Lazy("bah bah\tblack sheep").split(/\s+/) // sequence: ["bah", "bah", "black", "sheep"]
|
||
*/
|
||
StringLikeSequence.prototype.split = function split(delimiter) {
|
||
return new SplitStringSequence(this, delimiter);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function SplitStringSequence(parent, pattern) {
|
||
this.parent = parent;
|
||
this.pattern = pattern;
|
||
}
|
||
|
||
SplitStringSequence.prototype = new Sequence();
|
||
|
||
SplitStringSequence.prototype.getIterator = function getIterator() {
|
||
var source = this.parent.toString();
|
||
|
||
if (this.pattern instanceof RegExp) {
|
||
if (this.pattern.source === "" || this.pattern.source === "(?:)") {
|
||
return new CharIterator(source);
|
||
} else {
|
||
return new SplitWithRegExpIterator(source, this.pattern);
|
||
}
|
||
} else if (this.pattern === "") {
|
||
return new CharIterator(source);
|
||
} else {
|
||
return new SplitWithStringIterator(source, this.pattern);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function SplitWithRegExpIterator(source, pattern) {
|
||
this.source = source;
|
||
this.pattern = cloneRegex(pattern);
|
||
}
|
||
|
||
SplitWithRegExpIterator.prototype.current = function current() {
|
||
return this.source.substring(this.start, this.end);
|
||
};
|
||
|
||
SplitWithRegExpIterator.prototype.moveNext = function moveNext() {
|
||
if (!this.pattern) {
|
||
return false;
|
||
}
|
||
|
||
var match = this.pattern.exec(this.source);
|
||
|
||
if (match) {
|
||
this.start = this.nextStart ? this.nextStart : 0;
|
||
this.end = match.index;
|
||
this.nextStart = match.index + match[0].length;
|
||
return true;
|
||
|
||
} else if (this.pattern) {
|
||
this.start = this.nextStart;
|
||
this.end = undefined;
|
||
this.nextStart = undefined;
|
||
this.pattern = undefined;
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function SplitWithStringIterator(source, delimiter) {
|
||
this.source = source;
|
||
this.delimiter = delimiter;
|
||
}
|
||
|
||
SplitWithStringIterator.prototype.current = function current() {
|
||
return this.source.substring(this.leftIndex, this.rightIndex);
|
||
};
|
||
|
||
SplitWithStringIterator.prototype.moveNext = function moveNext() {
|
||
if (!this.finished) {
|
||
this.leftIndex = typeof this.leftIndex !== "undefined" ?
|
||
this.rightIndex + this.delimiter.length :
|
||
0;
|
||
this.rightIndex = this.source.indexOf(this.delimiter, this.leftIndex);
|
||
}
|
||
|
||
if (this.rightIndex === -1) {
|
||
this.finished = true;
|
||
this.rightIndex = undefined;
|
||
return true;
|
||
}
|
||
|
||
return !this.finished;
|
||
};
|
||
|
||
/**
|
||
* Wraps a string exposing {@link #match} and {@link #split} methods that return
|
||
* {@link Sequence} objects instead of arrays, improving on the efficiency of
|
||
* JavaScript's built-in `String#split` and `String.match` methods and
|
||
* supporting asynchronous iteration.
|
||
*
|
||
* @param {string} source The string to wrap.
|
||
* @constructor
|
||
*/
|
||
function StringWrapper(source) {
|
||
this.source = source;
|
||
}
|
||
|
||
StringWrapper.prototype = new StringLikeSequence();
|
||
|
||
StringWrapper.prototype.root = function root() {
|
||
return this;
|
||
};
|
||
|
||
StringWrapper.prototype.isAsync = function isAsync() {
|
||
return false;
|
||
};
|
||
|
||
StringWrapper.prototype.get = function get(i) {
|
||
return this.source.charAt(i);
|
||
};
|
||
|
||
StringWrapper.prototype.length = function length() {
|
||
return this.source.length;
|
||
};
|
||
|
||
StringWrapper.prototype.toString = function toString() {
|
||
return this.source;
|
||
};
|
||
|
||
/**
|
||
* A `GeneratedSequence` does not wrap an in-memory colllection but rather
|
||
* determines its elements on-the-fly during iteration according to a generator
|
||
* function.
|
||
*
|
||
* You create a `GeneratedSequence` by calling {@link Lazy.generate}.
|
||
*
|
||
* @public
|
||
* @constructor
|
||
* @param {function(number):*} generatorFn A function which accepts an index
|
||
* and returns a value for the element at that position in the sequence.
|
||
* @param {number=} length The length of the sequence. If this argument is
|
||
* omitted, the sequence will go on forever.
|
||
*/
|
||
function GeneratedSequence(generatorFn, length) {
|
||
this.get = generatorFn;
|
||
this.fixedLength = length;
|
||
}
|
||
|
||
GeneratedSequence.prototype = new Sequence();
|
||
|
||
GeneratedSequence.prototype.isAsync = function isAsync() {
|
||
return false;
|
||
};
|
||
|
||
/**
|
||
* Returns the length of this sequence.
|
||
*
|
||
* @public
|
||
* @returns {number} The length, or `undefined` if this is an indefinite
|
||
* sequence.
|
||
*/
|
||
GeneratedSequence.prototype.length = function length() {
|
||
return this.fixedLength;
|
||
};
|
||
|
||
/**
|
||
* Iterates over the sequence produced by invoking this sequence's generator
|
||
* function up to its specified length, or, if length is `undefined`,
|
||
* indefinitely (in which case the sequence will go on forever--you would need
|
||
* to call, e.g., {@link Sequence#take} to limit iteration).
|
||
*
|
||
* @public
|
||
* @param {Function} fn The function to call on each output from the generator
|
||
* function.
|
||
*/
|
||
GeneratedSequence.prototype.each = function each(fn) {
|
||
var generatorFn = this.get,
|
||
length = this.fixedLength,
|
||
i = 0;
|
||
|
||
while (typeof length === "undefined" || i < length) {
|
||
if (fn(generatorFn(i), i++) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
GeneratedSequence.prototype.getIterator = function getIterator() {
|
||
return new GeneratedIterator(this);
|
||
};
|
||
|
||
/**
|
||
* Iterates over a generated sequence. (This allows generated sequences to be
|
||
* iterated asynchronously.)
|
||
*
|
||
* @param {GeneratedSequence} sequence The generated sequence to iterate over.
|
||
* @constructor
|
||
*/
|
||
function GeneratedIterator(sequence) {
|
||
this.sequence = sequence;
|
||
this.index = 0;
|
||
this.currentValue = null;
|
||
}
|
||
|
||
GeneratedIterator.prototype.current = function current() {
|
||
return this.currentValue;
|
||
};
|
||
|
||
GeneratedIterator.prototype.moveNext = function moveNext() {
|
||
var sequence = this.sequence;
|
||
|
||
if (typeof sequence.fixedLength === "number" && this.index >= sequence.fixedLength) {
|
||
return false;
|
||
}
|
||
|
||
this.currentValue = sequence.get(this.index++);
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* An `AsyncSequence` iterates over its elements asynchronously when
|
||
* {@link #each} is called.
|
||
*
|
||
* You get an `AsyncSequence` by calling {@link Sequence#async} on any
|
||
* sequence. Note that some sequence types may not support asynchronous
|
||
* iteration.
|
||
*
|
||
* Returning values
|
||
* ----------------
|
||
*
|
||
* Because of its asynchronous nature, an `AsyncSequence` cannot be used in the
|
||
* same way as other sequences for functions that return values directly (e.g.,
|
||
* `reduce`, `max`, `any`, even `toArray`).
|
||
*
|
||
* Instead, these methods return an `AsyncHandle` whose `onComplete` method
|
||
* accepts a callback that will be called with the final result once iteration
|
||
* has finished.
|
||
*
|
||
* Defining custom asynchronous sequences
|
||
* --------------------------------------
|
||
*
|
||
* There are plenty of ways to define an asynchronous sequence. Here's one.
|
||
*
|
||
* 1. First, implement an {@link Iterator}. This is an object whose prototype
|
||
* has the methods {@link Iterator#moveNext} (which returns a `boolean`) and
|
||
* {@link current} (which returns the current value).
|
||
* 2. Next, create a simple wrapper that inherits from `AsyncSequence`, whose
|
||
* `getIterator` function returns an instance of the iterator type you just
|
||
* defined.
|
||
*
|
||
* The default implementation for {@link #each} on an `AsyncSequence` is to
|
||
* create an iterator and then asynchronously call {@link Iterator#moveNext}
|
||
* (using `setImmediate`, if available, otherwise `setTimeout`) until the iterator
|
||
* can't move ahead any more.
|
||
*
|
||
* @public
|
||
* @constructor
|
||
* @param {Sequence} parent A {@link Sequence} to wrap, to expose asynchronous
|
||
* iteration.
|
||
* @param {number=} interval How many milliseconds should elapse between each
|
||
* element when iterating over this sequence. If this argument is omitted,
|
||
* asynchronous iteration will be executed as fast as possible.
|
||
*/
|
||
function AsyncSequence(parent, interval) {
|
||
if (parent instanceof AsyncSequence) {
|
||
throw new Error("Sequence is already asynchronous!");
|
||
}
|
||
|
||
this.parent = parent;
|
||
this.interval = interval;
|
||
this.onNextCallback = getOnNextCallback(interval);
|
||
this.cancelCallback = getCancelCallback(interval);
|
||
}
|
||
|
||
AsyncSequence.prototype = new Sequence();
|
||
|
||
AsyncSequence.prototype.isAsync = function isAsync() {
|
||
return true;
|
||
};
|
||
|
||
/**
|
||
* Throws an exception. You cannot manually iterate over an asynchronous
|
||
* sequence.
|
||
*
|
||
* @public
|
||
* @example
|
||
* Lazy([1, 2, 3]).async().getIterator() // throws
|
||
*/
|
||
AsyncSequence.prototype.getIterator = function getIterator() {
|
||
throw new Error('An AsyncSequence does not support synchronous iteration.');
|
||
};
|
||
|
||
/**
|
||
* An asynchronous version of {@link Sequence#each}.
|
||
*
|
||
* @public
|
||
* @param {Function} fn The function to invoke asynchronously on each element in
|
||
* the sequence one by one.
|
||
* @returns {AsyncHandle} An {@link AsyncHandle} providing the ability to
|
||
* cancel the asynchronous iteration (by calling `cancel()`) as well as
|
||
* supply callback(s) for when an error is encountered (`onError`) or when
|
||
* iteration is complete (`onComplete`).
|
||
*/
|
||
AsyncSequence.prototype.each = function each(fn) {
|
||
var iterator = this.parent.getIterator(),
|
||
onNextCallback = this.onNextCallback,
|
||
cancelCallback = this.cancelCallback,
|
||
i = 0;
|
||
|
||
var handle = new AsyncHandle(function cancel() {
|
||
if (cancellationId) {
|
||
cancelCallback(cancellationId);
|
||
}
|
||
});
|
||
|
||
var cancellationId = onNextCallback(function iterate() {
|
||
cancellationId = null;
|
||
|
||
try {
|
||
if (iterator.moveNext() && fn(iterator.current(), i++) !== false) {
|
||
cancellationId = onNextCallback(iterate);
|
||
|
||
} else {
|
||
handle._resolve();
|
||
}
|
||
|
||
} catch (e) {
|
||
handle._reject(e);
|
||
}
|
||
});
|
||
|
||
return handle;
|
||
};
|
||
|
||
/**
|
||
* An `AsyncHandle` provides a [Promises/A+](http://promises-aplus.github.io/promises-spec/)
|
||
* compliant interface for an {@link AsyncSequence} that is currently (or was)
|
||
* iterating over its elements.
|
||
*
|
||
* In addition to behaving as a promise, an `AsyncHandle` provides the ability
|
||
* to {@link AsyncHandle#cancel} iteration (if `cancelFn` is provided)
|
||
* and also offers convenient {@link AsyncHandle#onComplete} and
|
||
* {@link AsyncHandle#onError} methods to attach listeners for when iteration
|
||
* is complete or an error is thrown during iteration.
|
||
*
|
||
* @public
|
||
* @param {Function} cancelFn A function to cancel asynchronous iteration.
|
||
* This is passed in to support different cancellation mechanisms for
|
||
* different forms of asynchronous sequences (e.g., timeout-based
|
||
* sequences, sequences based on I/O, etc.).
|
||
* @constructor
|
||
*
|
||
* @example
|
||
* // Create a sequence of 100,000 random numbers, in chunks of 100.
|
||
* var sequence = Lazy.generate(Math.random)
|
||
* .chunk(100)
|
||
* .async()
|
||
* .take(1000);
|
||
*
|
||
* // Reduce-style operations -- i.e., operations that return a *value* (as
|
||
* // opposed to a *sequence*) -- return an AsyncHandle for async sequences.
|
||
* var handle = sequence.toArray();
|
||
*
|
||
* handle.onComplete(function(array) {
|
||
* // Do something w/ 1,000-element array.
|
||
* });
|
||
*
|
||
* // Since an AsyncHandle is a promise, you can also use it to create
|
||
* // subsequent promises using `then` (see the Promises/A+ spec for more
|
||
* // info).
|
||
* var flattened = handle.then(function(array) {
|
||
* return Lazy(array).flatten();
|
||
* });
|
||
*/
|
||
function AsyncHandle(cancelFn) {
|
||
this.resolveListeners = [];
|
||
this.rejectListeners = [];
|
||
this.state = PENDING;
|
||
this.cancelFn = cancelFn;
|
||
}
|
||
|
||
// Async handle states
|
||
var PENDING = 1,
|
||
RESOLVED = 2,
|
||
REJECTED = 3;
|
||
|
||
AsyncHandle.prototype.then = function then(onFulfilled, onRejected) {
|
||
var promise = new AsyncHandle(this.cancelFn);
|
||
|
||
this.resolveListeners.push(function(value) {
|
||
try {
|
||
if (typeof onFulfilled !== 'function') {
|
||
resolve(promise, value);
|
||
return;
|
||
}
|
||
|
||
resolve(promise, onFulfilled(value));
|
||
|
||
} catch (e) {
|
||
promise._reject(e);
|
||
}
|
||
});
|
||
|
||
this.rejectListeners.push(function(reason) {
|
||
try {
|
||
if (typeof onRejected !== 'function') {
|
||
promise._reject(reason);
|
||
return;
|
||
}
|
||
|
||
resolve(promise, onRejected(reason));
|
||
|
||
} catch (e) {
|
||
promise._reject(e);
|
||
}
|
||
});
|
||
|
||
if (this.state === RESOLVED) {
|
||
this._resolve(this.value);
|
||
}
|
||
|
||
if (this.state === REJECTED) {
|
||
this._reject(this.reason);
|
||
}
|
||
|
||
return promise;
|
||
};
|
||
|
||
AsyncHandle.prototype._resolve = function _resolve(value) {
|
||
if (this.state === REJECTED) {
|
||
return;
|
||
}
|
||
|
||
if (this.state === PENDING) {
|
||
this.state = RESOLVED;
|
||
this.value = value;
|
||
}
|
||
|
||
consumeListeners(this.resolveListeners, this.value);
|
||
};
|
||
|
||
AsyncHandle.prototype._reject = function _reject(reason) {
|
||
if (this.state === RESOLVED) {
|
||
return;
|
||
}
|
||
|
||
if (this.state === PENDING) {
|
||
this.state = REJECTED;
|
||
this.reason = reason;
|
||
}
|
||
|
||
consumeListeners(this.rejectListeners, this.reason);
|
||
};
|
||
|
||
/**
|
||
* Cancels asynchronous iteration.
|
||
*
|
||
* @public
|
||
*/
|
||
AsyncHandle.prototype.cancel = function cancel() {
|
||
if (this.cancelFn) {
|
||
this.cancelFn();
|
||
this.cancelFn = null;
|
||
this._resolve(false);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Updates the handle with a callback to execute when iteration is completed.
|
||
*
|
||
* @public
|
||
* @param {Function} callback The function to call when the asynchronous
|
||
* iteration is completed.
|
||
* @return {AsyncHandle} A reference to the handle (for chaining).
|
||
*/
|
||
AsyncHandle.prototype.onComplete = function onComplete(callback) {
|
||
this.resolveListeners.push(callback);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Updates the handle with a callback to execute if/when any error is
|
||
* encountered during asynchronous iteration.
|
||
*
|
||
* @public
|
||
* @param {Function} callback The function to call, with any associated error
|
||
* object, when an error occurs.
|
||
* @return {AsyncHandle} A reference to the handle (for chaining).
|
||
*/
|
||
AsyncHandle.prototype.onError = function onError(callback) {
|
||
this.rejectListeners.push(callback);
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Promise resolution procedure:
|
||
* http://promises-aplus.github.io/promises-spec/#the_promise_resolution_procedure
|
||
*/
|
||
function resolve(promise, x) {
|
||
if (promise === x) {
|
||
promise._reject(new TypeError('Cannot resolve a promise to itself'));
|
||
return;
|
||
}
|
||
|
||
if (x instanceof AsyncHandle) {
|
||
x.then(
|
||
function(value) { resolve(promise, value); },
|
||
function(reason) { promise._reject(reason); }
|
||
);
|
||
return;
|
||
}
|
||
|
||
var then;
|
||
try {
|
||
then = (/function|object/).test(typeof x) && x != null && x.then;
|
||
} catch (e) {
|
||
promise._reject(e);
|
||
return;
|
||
}
|
||
|
||
var thenableState = PENDING;
|
||
if (typeof then === 'function') {
|
||
try {
|
||
then.call(
|
||
x,
|
||
function resolvePromise(value) {
|
||
if (thenableState !== PENDING) {
|
||
return;
|
||
}
|
||
thenableState = RESOLVED;
|
||
resolve(promise, value);
|
||
},
|
||
function rejectPromise(reason) {
|
||
if (thenableState !== PENDING) {
|
||
return;
|
||
}
|
||
thenableState = REJECTED;
|
||
promise._reject(reason);
|
||
}
|
||
);
|
||
} catch (e) {
|
||
if (thenableState !== PENDING) {
|
||
return;
|
||
}
|
||
|
||
promise._reject(e);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
promise._resolve(x);
|
||
}
|
||
|
||
function consumeListeners(listeners, value, callback) {
|
||
callback || (callback = getOnNextCallback());
|
||
|
||
callback(function() {
|
||
if (listeners.length > 0) {
|
||
listeners.shift()(value);
|
||
consumeListeners(listeners, value, callback);
|
||
}
|
||
});
|
||
}
|
||
|
||
function getOnNextCallback(interval) {
|
||
if (typeof interval === "undefined") {
|
||
if (typeof setImmediate === "function") {
|
||
return setImmediate;
|
||
}
|
||
}
|
||
|
||
interval = interval || 0;
|
||
return function(fn) {
|
||
return setTimeout(fn, interval);
|
||
};
|
||
}
|
||
|
||
function getCancelCallback(interval) {
|
||
if (typeof interval === "undefined") {
|
||
if (typeof clearImmediate === "function") {
|
||
return clearImmediate;
|
||
}
|
||
}
|
||
|
||
return clearTimeout;
|
||
}
|
||
|
||
/**
|
||
* Transform a value, whether the value is retrieved asynchronously or directly.
|
||
*
|
||
* @private
|
||
* @param {Function} fn The function that transforms the value.
|
||
* @param {*} value The value to be transformed. This can be an {@link AsyncHandle} when the value
|
||
* is retrieved asynchronously, otherwise it can be anything.
|
||
* @returns {*} An {@link AsyncHandle} when `value` is also an {@link AsyncHandle}, otherwise
|
||
* whatever `fn` resulted in.
|
||
*/
|
||
function transform(fn, value) {
|
||
if (value instanceof AsyncHandle) {
|
||
return value.then(function() { fn(value); });
|
||
}
|
||
return fn(value);
|
||
}
|
||
|
||
/**
|
||
* An async version of {@link Sequence#reverse}.
|
||
*/
|
||
AsyncSequence.prototype.reverse = function reverse() {
|
||
return this.parent.reverse().async();
|
||
};
|
||
|
||
/**
|
||
* A version of {@link Sequence#find} which returns an {@link AsyncHandle}.
|
||
*
|
||
* @public
|
||
* @param {Function} predicate A function to call on (potentially) every element
|
||
* in the sequence.
|
||
* @returns {AsyncHandle} An {@link AsyncHandle} (promise) which resolves to
|
||
* the found element, once it is detected, or else `undefined`.
|
||
*/
|
||
AsyncSequence.prototype.find = function find(predicate) {
|
||
var found;
|
||
|
||
var handle = this.each(function(e, i) {
|
||
if (predicate(e, i)) {
|
||
found = e;
|
||
return false;
|
||
}
|
||
});
|
||
|
||
return handle.then(function() { return found; });
|
||
};
|
||
|
||
/**
|
||
* A version of {@link Sequence#indexOf} which returns an {@link AsyncHandle}.
|
||
*
|
||
* @public
|
||
* @param {*} value The element to search for in the sequence.
|
||
* @returns {AsyncHandle} An {@link AsyncHandle} (promise) which resolves to
|
||
* the found index, once it is detected, or -1.
|
||
*/
|
||
AsyncSequence.prototype.indexOf = function indexOf(value) {
|
||
var foundIndex = -1;
|
||
|
||
var handle = this.each(function(e, i) {
|
||
if (e === value) {
|
||
foundIndex = i;
|
||
return false;
|
||
}
|
||
});
|
||
|
||
return handle.then(function() {
|
||
return foundIndex;
|
||
});
|
||
};
|
||
|
||
/**
|
||
* A version of {@link Sequence#contains} which returns an {@link AsyncHandle}.
|
||
*
|
||
* @public
|
||
* @param {*} value The element to search for in the sequence.
|
||
* @returns {AsyncHandle} An {@link AsyncHandle} (promise) which resolves to
|
||
* either `true` or `false` to indicate whether the element was found.
|
||
*/
|
||
AsyncSequence.prototype.contains = function contains(value) {
|
||
var found = false;
|
||
|
||
var handle = this.each(function(e) {
|
||
if (e === value) {
|
||
found = true;
|
||
return false;
|
||
}
|
||
});
|
||
|
||
return handle.then(function() {
|
||
return found;
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Just return the same sequence for `AsyncSequence#async` (I see no harm in this).
|
||
*/
|
||
AsyncSequence.prototype.async = function async() {
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* See {@link ObjectLikeSequence#watch} for docs.
|
||
*/
|
||
ObjectWrapper.prototype.watch = function watch(propertyNames) {
|
||
return new WatchedPropertySequence(this.source, propertyNames);
|
||
};
|
||
|
||
function WatchedPropertySequence(object, propertyNames) {
|
||
this.listeners = [];
|
||
|
||
if (!propertyNames) {
|
||
propertyNames = Lazy(object).keys().toArray();
|
||
} else if (!(propertyNames instanceof Array)) {
|
||
propertyNames = [propertyNames];
|
||
}
|
||
|
||
var listeners = this.listeners,
|
||
index = 0;
|
||
|
||
Lazy(propertyNames).each(function(propertyName) {
|
||
var propertyValue = object[propertyName];
|
||
|
||
Object.defineProperty(object, propertyName, {
|
||
get: function() {
|
||
return propertyValue;
|
||
},
|
||
|
||
set: function(value) {
|
||
for (var i = listeners.length - 1; i >= 0; --i) {
|
||
if (listeners[i]({ property: propertyName, value: value }, index) === false) {
|
||
listeners.splice(i, 1);
|
||
}
|
||
}
|
||
propertyValue = value;
|
||
++index;
|
||
}
|
||
});
|
||
});
|
||
}
|
||
|
||
WatchedPropertySequence.prototype = new AsyncSequence();
|
||
|
||
WatchedPropertySequence.prototype.each = function each(fn) {
|
||
this.listeners.push(fn);
|
||
};
|
||
|
||
/**
|
||
* A StreamLikeSequence comprises a sequence of 'chunks' of data, which are
|
||
* typically multiline strings.
|
||
*
|
||
* @constructor
|
||
*/
|
||
function StreamLikeSequence() {}
|
||
|
||
StreamLikeSequence.prototype = new AsyncSequence();
|
||
|
||
StreamLikeSequence.prototype.isAsync = function isAsync() {
|
||
return true;
|
||
};
|
||
|
||
StreamLikeSequence.prototype.split = function split(delimiter) {
|
||
return new SplitStreamSequence(this, delimiter);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function SplitStreamSequence(parent, delimiter) {
|
||
this.parent = parent;
|
||
this.delimiter = delimiter;
|
||
this.each = this.getEachForDelimiter(delimiter);
|
||
}
|
||
|
||
SplitStreamSequence.prototype = new Sequence();
|
||
|
||
SplitStreamSequence.prototype.getEachForDelimiter = function getEachForDelimiter(delimiter) {
|
||
if (delimiter instanceof RegExp) {
|
||
return this.regexEach;
|
||
}
|
||
|
||
return this.stringEach;
|
||
};
|
||
|
||
SplitStreamSequence.prototype.regexEach = function each(fn) {
|
||
var delimiter = cloneRegex(this.delimiter),
|
||
buffer = '',
|
||
start = 0, end,
|
||
index = 0;
|
||
|
||
var handle = this.parent.each(function(chunk) {
|
||
buffer += chunk;
|
||
|
||
var match;
|
||
while (match = delimiter.exec(buffer)) {
|
||
end = match.index;
|
||
if (fn(buffer.substring(start, end), index++) === false) {
|
||
return false;
|
||
}
|
||
start = end + match[0].length;
|
||
}
|
||
|
||
buffer = buffer.substring(start);
|
||
start = 0;
|
||
});
|
||
|
||
handle.onComplete(function() {
|
||
if (buffer.length > 0) {
|
||
fn(buffer, index++);
|
||
}
|
||
});
|
||
|
||
return handle;
|
||
};
|
||
|
||
SplitStreamSequence.prototype.stringEach = function each(fn) {
|
||
var delimiter = this.delimiter,
|
||
pieceIndex = 0,
|
||
buffer = '',
|
||
bufferIndex = 0;
|
||
|
||
var handle = this.parent.each(function(chunk) {
|
||
buffer += chunk;
|
||
var delimiterIndex;
|
||
while ((delimiterIndex = buffer.indexOf(delimiter)) >= 0) {
|
||
var piece = buffer.substr(0,delimiterIndex);
|
||
buffer = buffer.substr(delimiterIndex+delimiter.length);
|
||
if (fn(piece,pieceIndex++) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
return true;
|
||
});
|
||
|
||
handle.onComplete(function() {
|
||
fn(buffer, pieceIndex++);
|
||
});
|
||
|
||
return handle;
|
||
};
|
||
|
||
StreamLikeSequence.prototype.lines = function lines() {
|
||
return this.split("\n");
|
||
};
|
||
|
||
StreamLikeSequence.prototype.match = function match(pattern) {
|
||
return new MatchedStreamSequence(this, pattern);
|
||
};
|
||
|
||
/**
|
||
* @constructor
|
||
*/
|
||
function MatchedStreamSequence(parent, pattern) {
|
||
this.parent = parent;
|
||
this.pattern = cloneRegex(pattern);
|
||
}
|
||
|
||
MatchedStreamSequence.prototype = new AsyncSequence();
|
||
|
||
MatchedStreamSequence.prototype.each = function each(fn) {
|
||
var pattern = this.pattern,
|
||
done = false,
|
||
i = 0;
|
||
|
||
return this.parent.each(function(chunk) {
|
||
Lazy(chunk).match(pattern).each(function(match) {
|
||
if (fn(match, i++) === false) {
|
||
done = true;
|
||
return false;
|
||
}
|
||
});
|
||
|
||
return !done;
|
||
});
|
||
};
|
||
|
||
/**
|
||
* Defines a wrapper for custom {@link StreamLikeSequence}s. This is useful
|
||
* if you want a way to handle a stream of events as a sequence, but you can't
|
||
* use Lazy's existing interface (i.e., you're wrapping an object from a
|
||
* library with its own custom events).
|
||
*
|
||
* This method defines a *factory*: that is, it produces a function that can
|
||
* be used to wrap objects and return a {@link Sequence}. Hopefully the
|
||
* example will make this clear.
|
||
*
|
||
* @public
|
||
* @param {Function} initializer An initialization function called on objects
|
||
* created by this factory. `this` will be bound to the created object,
|
||
* which is an instance of {@link StreamLikeSequence}. Use `emit` to
|
||
* generate data for the sequence.
|
||
* @returns {Function} A function that creates a new {@link StreamLikeSequence},
|
||
* initializes it using the specified function, and returns it.
|
||
*
|
||
* @example
|
||
* var factory = Lazy.createWrapper(function(eventSource) {
|
||
* var sequence = this;
|
||
*
|
||
* eventSource.handleEvent(function(data) {
|
||
* sequence.emit(data);
|
||
* });
|
||
* });
|
||
*
|
||
* var eventEmitter = {
|
||
* triggerEvent: function(data) {
|
||
* eventEmitter.eventHandler(data);
|
||
* },
|
||
* handleEvent: function(handler) {
|
||
* eventEmitter.eventHandler = handler;
|
||
* },
|
||
* eventHandler: function() {}
|
||
* };
|
||
*
|
||
* var events = [];
|
||
*
|
||
* factory(eventEmitter).each(function(e) {
|
||
* events.push(e);
|
||
* });
|
||
*
|
||
* eventEmitter.triggerEvent('foo');
|
||
* eventEmitter.triggerEvent('bar');
|
||
*
|
||
* events // => ['foo', 'bar']
|
||
*/
|
||
Lazy.createWrapper = function createWrapper(initializer) {
|
||
var ctor = function() {
|
||
this.listeners = [];
|
||
};
|
||
|
||
ctor.prototype = new StreamLikeSequence();
|
||
|
||
ctor.prototype.each = function(listener) {
|
||
this.listeners.push(listener);
|
||
};
|
||
|
||
ctor.prototype.emit = function(data) {
|
||
var listeners = this.listeners;
|
||
|
||
for (var len = listeners.length, i = len - 1; i >= 0; --i) {
|
||
if (listeners[i](data) === false) {
|
||
listeners.splice(i, 1);
|
||
}
|
||
}
|
||
};
|
||
|
||
return function() {
|
||
var sequence = new ctor();
|
||
initializer.apply(sequence, arguments);
|
||
return sequence;
|
||
};
|
||
};
|
||
|
||
/**
|
||
* Creates a {@link GeneratedSequence} using the specified generator function
|
||
* and (optionally) length.
|
||
*
|
||
* @public
|
||
* @param {function(number):*} generatorFn The function used to generate the
|
||
* sequence. This function accepts an index as a parameter and should return
|
||
* a value for that index in the resulting sequence.
|
||
* @param {number=} length The length of the sequence, for sequences with a
|
||
* definite length.
|
||
* @returns {GeneratedSequence} The generated sequence.
|
||
*
|
||
* @examples
|
||
* var randomNumbers = Lazy.generate(Math.random);
|
||
* var countingNumbers = Lazy.generate(function(i) { return i + 1; }, 5);
|
||
*
|
||
* randomNumbers // instanceof Lazy.GeneratedSequence
|
||
* randomNumbers.length() // => undefined
|
||
* countingNumbers // sequence: [1, 2, 3, 4, 5]
|
||
* countingNumbers.length() // => 5
|
||
*/
|
||
Lazy.generate = function generate(generatorFn, length) {
|
||
return new GeneratedSequence(generatorFn, length);
|
||
};
|
||
|
||
/**
|
||
* Creates a sequence from a given starting value, up to a specified stopping
|
||
* value, incrementing by a given step. Invalid values for any of these
|
||
* arguments (e.g., a step of 0) result in an empty sequence.
|
||
*
|
||
* @public
|
||
* @returns {GeneratedSequence} The sequence defined by the given ranges.
|
||
*
|
||
* @examples
|
||
* Lazy.range(3) // sequence: [0, 1, 2]
|
||
* Lazy.range(1, 4) // sequence: [1, 2, 3]
|
||
* Lazy.range(2, 10, 2) // sequence: [2, 4, 6, 8]
|
||
* Lazy.range(5, 1, 2) // sequence: []
|
||
* Lazy.range(5, 15, -2) // sequence: []
|
||
* Lazy.range(3, 10, 3) // sequence: [3, 6, 9]
|
||
* Lazy.range(5, 2) // sequence: [5, 4, 3]
|
||
* Lazy.range(7, 2, -2) // sequence: [7, 5, 3]
|
||
* Lazy.range(3, 5, 0) // sequence: []
|
||
*/
|
||
Lazy.range = function range() {
|
||
var start = arguments.length > 1 ? arguments[0] : 0,
|
||
stop = arguments.length > 1 ? arguments[1] : arguments[0],
|
||
step = arguments.length > 2 && arguments[2];
|
||
|
||
if (step === false) {
|
||
step = stop > start ? 1 : -1;
|
||
}
|
||
|
||
if (step === 0) {
|
||
return Lazy([]);
|
||
}
|
||
|
||
return Lazy.generate(function(i) { return start + (step * i); })
|
||
.take(Math.ceil((stop - start) / step));
|
||
};
|
||
|
||
/**
|
||
* Creates a sequence consisting of the given value repeated a specified number
|
||
* of times.
|
||
*
|
||
* @public
|
||
* @param {*} value The value to repeat.
|
||
* @param {number=} count The number of times the value should be repeated in
|
||
* the sequence. If this argument is omitted, the value will repeat forever.
|
||
* @returns {GeneratedSequence} The sequence containing the repeated value.
|
||
*
|
||
* @examples
|
||
* Lazy.repeat("hi", 3) // sequence: ["hi", "hi", "hi"]
|
||
* Lazy.repeat("young") // instanceof Lazy.GeneratedSequence
|
||
* Lazy.repeat("young").length() // => undefined
|
||
* Lazy.repeat("young").take(3) // sequence: ["young", "young", "young"]
|
||
*/
|
||
Lazy.repeat = function repeat(value, count) {
|
||
return Lazy.generate(function() { return value; }, count);
|
||
};
|
||
|
||
Lazy.Sequence = Sequence;
|
||
Lazy.ArrayLikeSequence = ArrayLikeSequence;
|
||
Lazy.ObjectLikeSequence = ObjectLikeSequence;
|
||
Lazy.StringLikeSequence = StringLikeSequence;
|
||
Lazy.StreamLikeSequence = StreamLikeSequence;
|
||
Lazy.GeneratedSequence = GeneratedSequence;
|
||
Lazy.AsyncSequence = AsyncSequence;
|
||
Lazy.AsyncHandle = AsyncHandle;
|
||
|
||
/*** Useful utility methods ***/
|
||
|
||
/**
|
||
* Creates a shallow copy of an array or object.
|
||
*
|
||
* @examples
|
||
* var array = [1, 2, 3], clonedArray,
|
||
* object = { foo: 1, bar: 2 }, clonedObject;
|
||
*
|
||
* clonedArray = Lazy.clone(array); // => [1, 2, 3]
|
||
* clonedArray.push(4); // clonedArray == [1, 2, 3, 4]
|
||
* array; // => [1, 2, 3]
|
||
*
|
||
* clonedObject = Lazy.clone(object); // => { foo: 1, bar: 2 }
|
||
* clonedObject.baz = 3; // clonedObject == { foo: 1, bar: 2, baz: 3 }
|
||
* object; // => { foo: 1, bar: 2 }
|
||
*/
|
||
Lazy.clone = function clone(target) {
|
||
return Lazy(target).value();
|
||
};
|
||
|
||
/**
|
||
* Marks a method as deprecated, so calling it will issue a console warning.
|
||
*/
|
||
Lazy.deprecate = function deprecate(message, fn) {
|
||
return function() {
|
||
console.warn(message);
|
||
return fn.apply(this, arguments);
|
||
};
|
||
};
|
||
|
||
var arrayPop = Array.prototype.pop,
|
||
arraySlice = Array.prototype.slice;
|
||
|
||
/**
|
||
* Creates a callback... you know, Lo-Dash style.
|
||
*
|
||
* - for functions, just returns the function
|
||
* - for strings, returns a pluck-style callback
|
||
* - for objects, returns a where-style callback
|
||
*
|
||
* @private
|
||
* @param {Function|string|Object} callback A function, string, or object to
|
||
* convert to a callback.
|
||
* @param {*} defaultReturn If the callback is undefined, a default return
|
||
* value to use for the function.
|
||
* @returns {Function} The callback function.
|
||
*
|
||
* @examples
|
||
* createCallback(function() {}) // instanceof Function
|
||
* createCallback('foo') // instanceof Function
|
||
* createCallback('foo')({ foo: 'bar'}) // => 'bar'
|
||
* createCallback({ foo: 'bar' })({ foo: 'bar' }) // => true
|
||
* createCallback({ foo: 'bar' })({ foo: 'baz' }) // => false
|
||
*/
|
||
function createCallback(callback, defaultValue) {
|
||
switch (typeof callback) {
|
||
case "function":
|
||
return callback;
|
||
|
||
case "string":
|
||
return function(e) {
|
||
return e[callback];
|
||
};
|
||
|
||
case "object":
|
||
return function(e) {
|
||
return Lazy(callback).all(function(value, key) {
|
||
return e[key] === value;
|
||
});
|
||
};
|
||
|
||
case "undefined":
|
||
return defaultValue ?
|
||
function() { return defaultValue; } :
|
||
Lazy.identity;
|
||
|
||
default:
|
||
throw new Error("Don't know how to make a callback from a " + typeof callback + "!");
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Takes a function that returns a value for one argument and produces a
|
||
* function that compares two arguments.
|
||
*
|
||
* @private
|
||
* @param {Function|string|Object} callback A function, string, or object to
|
||
* convert to a callback using `createCallback`.
|
||
* @returns {Function} A function that accepts two values and returns 1 if
|
||
* the first is greater, -1 if the second is greater, or 0 if they are
|
||
* equivalent.
|
||
*
|
||
* @examples
|
||
* createComparator('a')({ a: 1 }, { a: 2 }); // => -1
|
||
* createComparator('a')({ a: 6 }, { a: 2 }); // => 1
|
||
* createComparator('a')({ a: 1 }, { a: 1 }); // => 0
|
||
* createComparator()(3, 5); // => -1
|
||
* createComparator()(7, 5); // => 1
|
||
* createComparator()(3, 3); // => 0
|
||
*/
|
||
function createComparator(callback, descending) {
|
||
if (!callback) { return compare; }
|
||
|
||
callback = createCallback(callback);
|
||
|
||
return function(x, y) {
|
||
return compare(callback(x), callback(y));
|
||
};
|
||
}
|
||
|
||
/**
|
||
* Takes a function and returns a function with the same logic but the
|
||
* arguments reversed. Only applies to functions w/ arity=2 as this is private
|
||
* and I can do what I want.
|
||
*
|
||
* @private
|
||
* @param {Function} fn The function to "reverse"
|
||
* @returns {Function} The "reversed" function
|
||
*
|
||
* @examples
|
||
* reverseArguments(function(x, y) { return x + y; })('a', 'b'); // => 'ba'
|
||
*/
|
||
function reverseArguments(fn) {
|
||
return function(x, y) { return fn(y, x); };
|
||
}
|
||
|
||
/**
|
||
* Creates a Set containing the specified values.
|
||
*
|
||
* @param {...Array} values One or more array(s) of values used to populate the
|
||
* set.
|
||
* @returns {Set} A new set containing the values passed in.
|
||
*/
|
||
function createSet(values) {
|
||
var set = new Set();
|
||
Lazy(values || []).flatten().each(function(e) {
|
||
set.add(e);
|
||
});
|
||
return set;
|
||
}
|
||
|
||
/**
|
||
* Compares two elements for sorting purposes.
|
||
*
|
||
* @private
|
||
* @param {*} x The left element to compare.
|
||
* @param {*} y The right element to compare.
|
||
* @returns {number} 1 if x > y, -1 if x < y, or 0 if x and y are equal.
|
||
*
|
||
* @examples
|
||
* compare(1, 2) // => -1
|
||
* compare(1, 1) // => 0
|
||
* compare(2, 1) // => 1
|
||
* compare('a', 'b') // => -1
|
||
*/
|
||
function compare(x, y) {
|
||
if (x === y) {
|
||
return 0;
|
||
}
|
||
|
||
return x > y ? 1 : -1;
|
||
}
|
||
|
||
/**
|
||
* Iterates over every element in an array.
|
||
*
|
||
* @param {Array} array The array.
|
||
* @param {Function} fn The function to call on every element, which can return
|
||
* false to stop the iteration early.
|
||
* @returns {boolean} True if every element in the entire sequence was iterated,
|
||
* otherwise false.
|
||
*/
|
||
function forEach(array, fn) {
|
||
var i = -1,
|
||
len = array.length;
|
||
|
||
while (++i < len) {
|
||
if (fn(array[i], i) === false) {
|
||
return false;
|
||
}
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
function getFirst(sequence) {
|
||
var result;
|
||
sequence.each(function(e) {
|
||
result = e;
|
||
return false;
|
||
});
|
||
return result;
|
||
}
|
||
|
||
/**
|
||
* Checks if an element exists in an array.
|
||
*
|
||
* @private
|
||
* @param {Array} array
|
||
* @param {*} element
|
||
* @returns {boolean} Whether or not the element exists in the array.
|
||
*
|
||
* @examples
|
||
* arrayContains([1, 2], 2) // => true
|
||
* arrayContains([1, 2], 3) // => false
|
||
* arrayContains([undefined], undefined) // => true
|
||
* arrayContains([NaN], NaN) // => true
|
||
*/
|
||
function arrayContains(array, element) {
|
||
var i = -1,
|
||
length = array.length;
|
||
|
||
// Special handling for NaN
|
||
if (element !== element) {
|
||
while (++i < length) {
|
||
if (array[i] !== array[i]) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
while (++i < length) {
|
||
if (array[i] === element) {
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Checks if an element exists in an array before a given index.
|
||
*
|
||
* @private
|
||
* @param {Array} array
|
||
* @param {*} element
|
||
* @param {number} index
|
||
* @param {Function} keyFn
|
||
* @returns {boolean}
|
||
*
|
||
* @examples
|
||
* arrayContainsBefore([1, 2, 3], 3, 2) // => false
|
||
* arrayContainsBefore([1, 2, 3], 3, 3) // => true
|
||
*/
|
||
function arrayContainsBefore(array, element, index, keyFn) {
|
||
var i = -1;
|
||
|
||
if (keyFn) {
|
||
keyFn = createCallback(keyFn);
|
||
while (++i < index) {
|
||
if (keyFn(array[i]) === keyFn(element)) {
|
||
return true;
|
||
}
|
||
}
|
||
|
||
} else {
|
||
while (++i < index) {
|
||
if (array[i] === element) {
|
||
return true;
|
||
}
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* Swaps the elements at two specified positions of an array.
|
||
*
|
||
* @private
|
||
* @param {Array} array
|
||
* @param {number} i
|
||
* @param {number} j
|
||
*
|
||
* @examples
|
||
* var array = [1, 2, 3, 4, 5];
|
||
*
|
||
* swap(array, 2, 3) // array == [1, 2, 4, 3, 5]
|
||
*/
|
||
function swap(array, i, j) {
|
||
var temp = array[i];
|
||
array[i] = array[j];
|
||
array[j] = temp;
|
||
}
|
||
|
||
/**
|
||
* "Clones" a regular expression (but makes it always global).
|
||
*
|
||
* @private
|
||
* @param {RegExp|string} pattern
|
||
* @returns {RegExp}
|
||
*/
|
||
function cloneRegex(pattern) {
|
||
return eval("" + pattern + (!pattern.global ? "g" : ""));
|
||
};
|
||
|
||
/**
|
||
* A collection of unique elements.
|
||
*
|
||
* @private
|
||
* @constructor
|
||
*
|
||
* @examples
|
||
* var set = new Set(),
|
||
* obj1 = {},
|
||
* obj2 = {},
|
||
* fn1 = function fn1() {},
|
||
* fn2 = function fn2() {};
|
||
*
|
||
* set.add('foo') // => true
|
||
* set.add('foo') // => false
|
||
* set.add(1) // => true
|
||
* set.add(1) // => false
|
||
* set.add('1') // => true
|
||
* set.add('1') // => false
|
||
* set.add(obj1) // => true
|
||
* set.add(obj1) // => false
|
||
* set.add(obj2) // => true
|
||
* set.add(fn1) // => true
|
||
* set.add(fn2) // => true
|
||
* set.add(fn2) // => false
|
||
* set.contains('__proto__') // => false
|
||
* set.add('__proto__') // => true
|
||
* set.add('__proto__') // => false
|
||
* set.contains('add') // => false
|
||
* set.add('add') // => true
|
||
* set.add('add') // => false
|
||
* set.contains(undefined) // => false
|
||
* set.add(undefined) // => true
|
||
* set.contains(undefined) // => true
|
||
* set.contains('undefined') // => false
|
||
* set.add('undefined') // => true
|
||
* set.contains('undefined') // => true
|
||
* set.contains(NaN) // => false
|
||
* set.add(NaN) // => true
|
||
* set.contains(NaN) // => true
|
||
* set.contains('NaN') // => false
|
||
* set.add('NaN') // => true
|
||
* set.contains('NaN') // => true
|
||
* set.contains('@foo') // => false
|
||
* set.add('@foo') // => true
|
||
* set.contains('@foo') // => true
|
||
*/
|
||
function Set() {
|
||
this.table = {};
|
||
this.objects = [];
|
||
}
|
||
|
||
/**
|
||
* Attempts to add a unique value to the set.
|
||
*
|
||
* @param {*} value The value to add.
|
||
* @returns {boolean} True if the value was added to the set (meaning an equal
|
||
* value was not already present), or else false.
|
||
*/
|
||
Set.prototype.add = function add(value) {
|
||
var table = this.table,
|
||
type = typeof value,
|
||
|
||
// only applies for strings
|
||
firstChar,
|
||
|
||
// only applies for objects
|
||
objects;
|
||
|
||
switch (type) {
|
||
case "number":
|
||
case "boolean":
|
||
case "undefined":
|
||
if (!table[value]) {
|
||
table[value] = true;
|
||
return true;
|
||
}
|
||
return false;
|
||
|
||
case "string":
|
||
// Essentially, escape the first character if it could possibly collide
|
||
// with a number, boolean, or undefined (or a string that happens to start
|
||
// with the escape character!), OR if it could override a special property
|
||
// such as '__proto__' or 'constructor'.
|
||
switch (value.charAt(0)) {
|
||
case "_": // e.g., __proto__
|
||
case "f": // for 'false'
|
||
case "t": // for 'true'
|
||
case "c": // for 'constructor'
|
||
case "u": // for 'undefined'
|
||
case "@": // escaped
|
||
case "0":
|
||
case "1":
|
||
case "2":
|
||
case "3":
|
||
case "4":
|
||
case "5":
|
||
case "6":
|
||
case "7":
|
||
case "8":
|
||
case "9":
|
||
case "N": // for NaN
|
||
value = "@" + value;
|
||
}
|
||
if (!table[value]) {
|
||
table[value] = true;
|
||
return true;
|
||
}
|
||
return false;
|
||
|
||
default:
|
||
// For objects and functions, we can't really do anything other than store
|
||
// them in an array and do a linear search for reference equality.
|
||
objects = this.objects;
|
||
if (!arrayContains(objects, value)) {
|
||
objects.push(value);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
};
|
||
|
||
/**
|
||
* Checks whether the set contains a value.
|
||
*
|
||
* @param {*} value The value to check for.
|
||
* @returns {boolean} True if the set contains the value, or else false.
|
||
*/
|
||
Set.prototype.contains = function contains(value) {
|
||
var type = typeof value,
|
||
|
||
// only applies for strings
|
||
firstChar;
|
||
|
||
switch (type) {
|
||
case "number":
|
||
case "boolean":
|
||
case "undefined":
|
||
return !!this.table[value];
|
||
|
||
case "string":
|
||
// Essentially, escape the first character if it could possibly collide
|
||
// with a number, boolean, or undefined (or a string that happens to start
|
||
// with the escape character!), OR if it could override a special property
|
||
// such as '__proto__' or 'constructor'.
|
||
switch (value.charAt(0)) {
|
||
case "_": // e.g., __proto__
|
||
case "f": // for 'false'
|
||
case "t": // for 'true'
|
||
case "c": // for 'constructor'
|
||
case "u": // for 'undefined'
|
||
case "@": // escaped
|
||
case "0":
|
||
case "1":
|
||
case "2":
|
||
case "3":
|
||
case "4":
|
||
case "5":
|
||
case "6":
|
||
case "7":
|
||
case "8":
|
||
case "9":
|
||
case "N": // for NaN
|
||
value = "@" + value;
|
||
}
|
||
return !!this.table[value];
|
||
|
||
default:
|
||
// For objects and functions, we can't really do anything other than store
|
||
// them in an array and do a linear search for reference equality.
|
||
return arrayContains(this.objects, value);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* A "rolling" queue, with a fixed capacity. As items are added to the head,
|
||
* excess items are dropped from the tail.
|
||
*
|
||
* @private
|
||
* @constructor
|
||
*
|
||
* @examples
|
||
* var queue = new Queue(3);
|
||
*
|
||
* queue.add(1).toArray() // => [1]
|
||
* queue.add(2).toArray() // => [1, 2]
|
||
* queue.add(3).toArray() // => [1, 2, 3]
|
||
* queue.add(4).toArray() // => [2, 3, 4]
|
||
* queue.add(5).add(6).toArray() // => [4, 5, 6]
|
||
* queue.add(7).add(8).toArray() // => [6, 7, 8]
|
||
*
|
||
* // also want to check corner cases
|
||
* new Queue(1).add('foo').add('bar').toArray() // => ['bar']
|
||
* new Queue(0).add('foo').toArray() // => []
|
||
* new Queue(-1) // throws
|
||
*
|
||
* @benchmarks
|
||
* function populateQueue(count, capacity) {
|
||
* var q = new Queue(capacity);
|
||
* for (var i = 0; i < count; ++i) {
|
||
* q.add(i);
|
||
* }
|
||
* }
|
||
*
|
||
* function populateArray(count, capacity) {
|
||
* var arr = [];
|
||
* for (var i = 0; i < count; ++i) {
|
||
* if (arr.length === capacity) { arr.shift(); }
|
||
* arr.push(i);
|
||
* }
|
||
* }
|
||
*
|
||
* populateQueue(100, 10); // populating a Queue
|
||
* populateArray(100, 10); // populating an Array
|
||
*/
|
||
function Queue(capacity) {
|
||
this.contents = new Array(capacity);
|
||
this.start = 0;
|
||
this.count = 0;
|
||
}
|
||
|
||
/**
|
||
* Adds an item to the queue, and returns the queue.
|
||
*/
|
||
Queue.prototype.add = function add(element) {
|
||
var contents = this.contents,
|
||
capacity = contents.length,
|
||
start = this.start;
|
||
|
||
if (this.count === capacity) {
|
||
contents[start] = element;
|
||
this.start = (start + 1) % capacity;
|
||
|
||
} else {
|
||
contents[this.count++] = element;
|
||
}
|
||
|
||
return this;
|
||
};
|
||
|
||
/**
|
||
* Returns an array containing snapshot of the queue's contents.
|
||
*/
|
||
Queue.prototype.toArray = function toArray() {
|
||
var contents = this.contents,
|
||
start = this.start,
|
||
count = this.count;
|
||
|
||
var snapshot = contents.slice(start, start + count);
|
||
if (snapshot.length < count) {
|
||
snapshot = snapshot.concat(contents.slice(0, count - snapshot.length));
|
||
}
|
||
|
||
return snapshot;
|
||
};
|
||
|
||
/**
|
||
* Shared base method for defining new sequence types.
|
||
*/
|
||
function defineSequenceType(base, name, overrides) {
|
||
/** @constructor */
|
||
var ctor = function ctor() {};
|
||
|
||
// Make this type inherit from the specified base.
|
||
ctor.prototype = new base();
|
||
|
||
// Attach overrides to the new sequence type's prototype.
|
||
for (var override in overrides) {
|
||
ctor.prototype[override] = overrides[override];
|
||
}
|
||
|
||
// Define a factory method that sets the new sequence's parent to the caller
|
||
// and (optionally) applies any additional initialization logic.
|
||
// Expose this as a chainable method so that we can do:
|
||
// Lazy(...).map(...).filter(...).blah(...);
|
||
var factory = function factory() {
|
||
var sequence = new ctor();
|
||
|
||
// Every sequence needs a reference to its parent in order to work.
|
||
sequence.parent = this;
|
||
|
||
// If a custom init function was supplied, call it now.
|
||
if (sequence.init) {
|
||
sequence.init.apply(sequence, arguments);
|
||
}
|
||
|
||
return sequence;
|
||
};
|
||
|
||
var methodNames = typeof name === 'string' ? [name] : name;
|
||
for (var i = 0; i < methodNames.length; ++i) {
|
||
base.prototype[methodNames[i]] = factory;
|
||
}
|
||
|
||
return ctor;
|
||
}
|
||
|
||
return Lazy;
|
||
});
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(152).setImmediate, __webpack_require__(152).clearImmediate))
|
||
|
||
/***/ },
|
||
/* 152 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(setImmediate, clearImmediate) {var nextTick = __webpack_require__(153).nextTick;
|
||
var apply = Function.prototype.apply;
|
||
var slice = Array.prototype.slice;
|
||
var immediateIds = {};
|
||
var nextImmediateId = 0;
|
||
|
||
// DOM APIs, for completeness
|
||
|
||
exports.setTimeout = function() {
|
||
return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout);
|
||
};
|
||
exports.setInterval = function() {
|
||
return new Timeout(apply.call(setInterval, window, arguments), clearInterval);
|
||
};
|
||
exports.clearTimeout =
|
||
exports.clearInterval = function(timeout) { timeout.close(); };
|
||
|
||
function Timeout(id, clearFn) {
|
||
this._id = id;
|
||
this._clearFn = clearFn;
|
||
}
|
||
Timeout.prototype.unref = Timeout.prototype.ref = function() {};
|
||
Timeout.prototype.close = function() {
|
||
this._clearFn.call(window, this._id);
|
||
};
|
||
|
||
// Does not start the time, just sets up the members needed.
|
||
exports.enroll = function(item, msecs) {
|
||
clearTimeout(item._idleTimeoutId);
|
||
item._idleTimeout = msecs;
|
||
};
|
||
|
||
exports.unenroll = function(item) {
|
||
clearTimeout(item._idleTimeoutId);
|
||
item._idleTimeout = -1;
|
||
};
|
||
|
||
exports._unrefActive = exports.active = function(item) {
|
||
clearTimeout(item._idleTimeoutId);
|
||
|
||
var msecs = item._idleTimeout;
|
||
if (msecs >= 0) {
|
||
item._idleTimeoutId = setTimeout(function onTimeout() {
|
||
if (item._onTimeout)
|
||
item._onTimeout();
|
||
}, msecs);
|
||
}
|
||
};
|
||
|
||
// That's not how node.js implements it but the exposed api is the same.
|
||
exports.setImmediate = typeof setImmediate === "function" ? setImmediate : function(fn) {
|
||
var id = nextImmediateId++;
|
||
var args = arguments.length < 2 ? false : slice.call(arguments, 1);
|
||
|
||
immediateIds[id] = true;
|
||
|
||
nextTick(function onNextTick() {
|
||
if (immediateIds[id]) {
|
||
// fn.call() is faster so we optimize for the common use-case
|
||
// @see http://jsperf.com/call-apply-segu
|
||
if (args) {
|
||
fn.apply(null, args);
|
||
} else {
|
||
fn.call(null);
|
||
}
|
||
// Prevent ids from leaking
|
||
exports.clearImmediate(id);
|
||
}
|
||
});
|
||
|
||
return id;
|
||
};
|
||
|
||
exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate : function(id) {
|
||
delete immediateIds[id];
|
||
};
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(152).setImmediate, __webpack_require__(152).clearImmediate))
|
||
|
||
/***/ },
|
||
/* 153 */
|
||
/***/ function(module, exports) {
|
||
|
||
// shim for using process in browser
|
||
|
||
var process = module.exports = {};
|
||
var queue = [];
|
||
var draining = false;
|
||
var currentQueue;
|
||
var queueIndex = -1;
|
||
|
||
function cleanUpNextTick() {
|
||
draining = false;
|
||
if (currentQueue.length) {
|
||
queue = currentQueue.concat(queue);
|
||
} else {
|
||
queueIndex = -1;
|
||
}
|
||
if (queue.length) {
|
||
drainQueue();
|
||
}
|
||
}
|
||
|
||
function drainQueue() {
|
||
if (draining) {
|
||
return;
|
||
}
|
||
var timeout = setTimeout(cleanUpNextTick);
|
||
draining = true;
|
||
|
||
var len = queue.length;
|
||
while(len) {
|
||
currentQueue = queue;
|
||
queue = [];
|
||
while (++queueIndex < len) {
|
||
if (currentQueue) {
|
||
currentQueue[queueIndex].run();
|
||
}
|
||
}
|
||
queueIndex = -1;
|
||
len = queue.length;
|
||
}
|
||
currentQueue = null;
|
||
draining = false;
|
||
clearTimeout(timeout);
|
||
}
|
||
|
||
process.nextTick = function (fun) {
|
||
var args = new Array(arguments.length - 1);
|
||
if (arguments.length > 1) {
|
||
for (var i = 1; i < arguments.length; i++) {
|
||
args[i - 1] = arguments[i];
|
||
}
|
||
}
|
||
queue.push(new Item(fun, args));
|
||
if (queue.length === 1 && !draining) {
|
||
setTimeout(drainQueue, 0);
|
||
}
|
||
};
|
||
|
||
// v8 likes predictible objects
|
||
function Item(fun, array) {
|
||
this.fun = fun;
|
||
this.array = array;
|
||
}
|
||
Item.prototype.run = function () {
|
||
this.fun.apply(null, this.array);
|
||
};
|
||
process.title = 'browser';
|
||
process.browser = true;
|
||
process.env = {};
|
||
process.argv = [];
|
||
process.version = ''; // empty string to avoid regexp issues
|
||
process.versions = {};
|
||
|
||
function noop() {}
|
||
|
||
process.on = noop;
|
||
process.addListener = noop;
|
||
process.once = noop;
|
||
process.off = noop;
|
||
process.removeListener = noop;
|
||
process.removeAllListeners = noop;
|
||
process.emit = noop;
|
||
|
||
process.binding = function (name) {
|
||
throw new Error('process.binding is not supported');
|
||
};
|
||
|
||
process.cwd = function () { return '/' };
|
||
process.chdir = function (dir) {
|
||
throw new Error('process.chdir is not supported');
|
||
};
|
||
process.umask = function() { return 0; };
|
||
|
||
|
||
/***/ },
|
||
/* 154 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
/* WEBPACK VAR INJECTION */(function(Buffer, global) {/*!
|
||
* The buffer module from node.js, for the browser.
|
||
*
|
||
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
|
||
* @license MIT
|
||
*/
|
||
/* eslint-disable no-proto */
|
||
|
||
'use strict'
|
||
|
||
var base64 = __webpack_require__(155)
|
||
var ieee754 = __webpack_require__(156)
|
||
var isArray = __webpack_require__(157)
|
||
|
||
exports.Buffer = Buffer
|
||
exports.SlowBuffer = SlowBuffer
|
||
exports.INSPECT_MAX_BYTES = 50
|
||
Buffer.poolSize = 8192 // not used by this implementation
|
||
|
||
var rootParent = {}
|
||
|
||
/**
|
||
* If `Buffer.TYPED_ARRAY_SUPPORT`:
|
||
* === true Use Uint8Array implementation (fastest)
|
||
* === false Use Object implementation (most compatible, even IE6)
|
||
*
|
||
* Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+,
|
||
* Opera 11.6+, iOS 4.2+.
|
||
*
|
||
* Due to various browser bugs, sometimes the Object implementation will be used even
|
||
* when the browser supports typed arrays.
|
||
*
|
||
* Note:
|
||
*
|
||
* - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances,
|
||
* See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438.
|
||
*
|
||
* - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function.
|
||
*
|
||
* - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of
|
||
* incorrect length in some situations.
|
||
|
||
* We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they
|
||
* get the Object implementation, which is slower but behaves correctly.
|
||
*/
|
||
Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined
|
||
? global.TYPED_ARRAY_SUPPORT
|
||
: typedArraySupport()
|
||
|
||
function typedArraySupport () {
|
||
try {
|
||
var arr = new Uint8Array(1)
|
||
arr.foo = function () { return 42 }
|
||
return arr.foo() === 42 && // typed array instances can be augmented
|
||
typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray`
|
||
arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray`
|
||
} catch (e) {
|
||
return false
|
||
}
|
||
}
|
||
|
||
function kMaxLength () {
|
||
return Buffer.TYPED_ARRAY_SUPPORT
|
||
? 0x7fffffff
|
||
: 0x3fffffff
|
||
}
|
||
|
||
/**
|
||
* The Buffer constructor returns instances of `Uint8Array` that have their
|
||
* prototype changed to `Buffer.prototype`. Furthermore, `Buffer` is a subclass of
|
||
* `Uint8Array`, so the returned instances will have all the node `Buffer` methods
|
||
* and the `Uint8Array` methods. Square bracket notation works as expected -- it
|
||
* returns a single octet.
|
||
*
|
||
* The `Uint8Array` prototype remains unmodified.
|
||
*/
|
||
function Buffer (arg) {
|
||
if (!(this instanceof Buffer)) {
|
||
// Avoid going through an ArgumentsAdaptorTrampoline in the common case.
|
||
if (arguments.length > 1) return new Buffer(arg, arguments[1])
|
||
return new Buffer(arg)
|
||
}
|
||
|
||
if (!Buffer.TYPED_ARRAY_SUPPORT) {
|
||
this.length = 0
|
||
this.parent = undefined
|
||
}
|
||
|
||
// Common case.
|
||
if (typeof arg === 'number') {
|
||
return fromNumber(this, arg)
|
||
}
|
||
|
||
// Slightly less common case.
|
||
if (typeof arg === 'string') {
|
||
return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8')
|
||
}
|
||
|
||
// Unusual.
|
||
return fromObject(this, arg)
|
||
}
|
||
|
||
// TODO: Legacy, not needed anymore. Remove in next major version.
|
||
Buffer._augment = function (arr) {
|
||
arr.__proto__ = Buffer.prototype
|
||
return arr
|
||
}
|
||
|
||
function fromNumber (that, length) {
|
||
that = allocate(that, length < 0 ? 0 : checked(length) | 0)
|
||
if (!Buffer.TYPED_ARRAY_SUPPORT) {
|
||
for (var i = 0; i < length; i++) {
|
||
that[i] = 0
|
||
}
|
||
}
|
||
return that
|
||
}
|
||
|
||
function fromString (that, string, encoding) {
|
||
if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8'
|
||
|
||
// Assumption: byteLength() return value is always < kMaxLength.
|
||
var length = byteLength(string, encoding) | 0
|
||
that = allocate(that, length)
|
||
|
||
that.write(string, encoding)
|
||
return that
|
||
}
|
||
|
||
function fromObject (that, object) {
|
||
if (Buffer.isBuffer(object)) return fromBuffer(that, object)
|
||
|
||
if (isArray(object)) return fromArray(that, object)
|
||
|
||
if (object == null) {
|
||
throw new TypeError('must start with number, buffer, array or string')
|
||
}
|
||
|
||
if (typeof ArrayBuffer !== 'undefined') {
|
||
if (object.buffer instanceof ArrayBuffer) {
|
||
return fromTypedArray(that, object)
|
||
}
|
||
if (object instanceof ArrayBuffer) {
|
||
return fromArrayBuffer(that, object)
|
||
}
|
||
}
|
||
|
||
if (object.length) return fromArrayLike(that, object)
|
||
|
||
return fromJsonObject(that, object)
|
||
}
|
||
|
||
function fromBuffer (that, buffer) {
|
||
var length = checked(buffer.length) | 0
|
||
that = allocate(that, length)
|
||
buffer.copy(that, 0, 0, length)
|
||
return that
|
||
}
|
||
|
||
function fromArray (that, array) {
|
||
var length = checked(array.length) | 0
|
||
that = allocate(that, length)
|
||
for (var i = 0; i < length; i += 1) {
|
||
that[i] = array[i] & 255
|
||
}
|
||
return that
|
||
}
|
||
|
||
// Duplicate of fromArray() to keep fromArray() monomorphic.
|
||
function fromTypedArray (that, array) {
|
||
var length = checked(array.length) | 0
|
||
that = allocate(that, length)
|
||
// Truncating the elements is probably not what people expect from typed
|
||
// arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior
|
||
// of the old Buffer constructor.
|
||
for (var i = 0; i < length; i += 1) {
|
||
that[i] = array[i] & 255
|
||
}
|
||
return that
|
||
}
|
||
|
||
function fromArrayBuffer (that, array) {
|
||
array.byteLength // this throws if `array` is not a valid ArrayBuffer
|
||
|
||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||
// Return an augmented `Uint8Array` instance, for best performance
|
||
that = new Uint8Array(array)
|
||
that.__proto__ = Buffer.prototype
|
||
} else {
|
||
// Fallback: Return an object instance of the Buffer class
|
||
that = fromTypedArray(that, new Uint8Array(array))
|
||
}
|
||
return that
|
||
}
|
||
|
||
function fromArrayLike (that, array) {
|
||
var length = checked(array.length) | 0
|
||
that = allocate(that, length)
|
||
for (var i = 0; i < length; i += 1) {
|
||
that[i] = array[i] & 255
|
||
}
|
||
return that
|
||
}
|
||
|
||
// Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object.
|
||
// Returns a zero-length buffer for inputs that don't conform to the spec.
|
||
function fromJsonObject (that, object) {
|
||
var array
|
||
var length = 0
|
||
|
||
if (object.type === 'Buffer' && isArray(object.data)) {
|
||
array = object.data
|
||
length = checked(array.length) | 0
|
||
}
|
||
that = allocate(that, length)
|
||
|
||
for (var i = 0; i < length; i += 1) {
|
||
that[i] = array[i] & 255
|
||
}
|
||
return that
|
||
}
|
||
|
||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||
Buffer.prototype.__proto__ = Uint8Array.prototype
|
||
Buffer.__proto__ = Uint8Array
|
||
if (typeof Symbol !== 'undefined' && Symbol.species &&
|
||
Buffer[Symbol.species] === Buffer) {
|
||
// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97
|
||
Object.defineProperty(Buffer, Symbol.species, {
|
||
value: null,
|
||
configurable: true
|
||
})
|
||
}
|
||
} else {
|
||
// pre-set for values that may exist in the future
|
||
Buffer.prototype.length = undefined
|
||
Buffer.prototype.parent = undefined
|
||
}
|
||
|
||
function allocate (that, length) {
|
||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||
// Return an augmented `Uint8Array` instance, for best performance
|
||
that = new Uint8Array(length)
|
||
that.__proto__ = Buffer.prototype
|
||
} else {
|
||
// Fallback: Return an object instance of the Buffer class
|
||
that.length = length
|
||
}
|
||
|
||
var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1
|
||
if (fromPool) that.parent = rootParent
|
||
|
||
return that
|
||
}
|
||
|
||
function checked (length) {
|
||
// Note: cannot use `length < kMaxLength` here because that fails when
|
||
// length is NaN (which is otherwise coerced to zero.)
|
||
if (length >= kMaxLength()) {
|
||
throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
|
||
'size: 0x' + kMaxLength().toString(16) + ' bytes')
|
||
}
|
||
return length | 0
|
||
}
|
||
|
||
function SlowBuffer (subject, encoding) {
|
||
if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding)
|
||
|
||
var buf = new Buffer(subject, encoding)
|
||
delete buf.parent
|
||
return buf
|
||
}
|
||
|
||
Buffer.isBuffer = function isBuffer (b) {
|
||
return !!(b != null && b._isBuffer)
|
||
}
|
||
|
||
Buffer.compare = function compare (a, b) {
|
||
if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) {
|
||
throw new TypeError('Arguments must be Buffers')
|
||
}
|
||
|
||
if (a === b) return 0
|
||
|
||
var x = a.length
|
||
var y = b.length
|
||
|
||
for (var i = 0, len = Math.min(x, y); i < len; ++i) {
|
||
if (a[i] !== b[i]) {
|
||
x = a[i]
|
||
y = b[i]
|
||
break
|
||
}
|
||
}
|
||
|
||
if (x < y) return -1
|
||
if (y < x) return 1
|
||
return 0
|
||
}
|
||
|
||
Buffer.isEncoding = function isEncoding (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.concat = function concat (list, length) {
|
||
if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.')
|
||
|
||
if (list.length === 0) {
|
||
return new Buffer(0)
|
||
}
|
||
|
||
var i
|
||
if (length === undefined) {
|
||
length = 0
|
||
for (i = 0; i < list.length; i++) {
|
||
length += list[i].length
|
||
}
|
||
}
|
||
|
||
var buf = new Buffer(length)
|
||
var pos = 0
|
||
for (i = 0; i < list.length; i++) {
|
||
var item = list[i]
|
||
item.copy(buf, pos)
|
||
pos += item.length
|
||
}
|
||
return buf
|
||
}
|
||
|
||
function byteLength (string, encoding) {
|
||
if (typeof string !== 'string') string = '' + string
|
||
|
||
var len = string.length
|
||
if (len === 0) return 0
|
||
|
||
// Use a for loop to avoid recursion
|
||
var loweredCase = false
|
||
for (;;) {
|
||
switch (encoding) {
|
||
case 'ascii':
|
||
case 'binary':
|
||
// Deprecated
|
||
case 'raw':
|
||
case 'raws':
|
||
return len
|
||
case 'utf8':
|
||
case 'utf-8':
|
||
return utf8ToBytes(string).length
|
||
case 'ucs2':
|
||
case 'ucs-2':
|
||
case 'utf16le':
|
||
case 'utf-16le':
|
||
return len * 2
|
||
case 'hex':
|
||
return len >>> 1
|
||
case 'base64':
|
||
return base64ToBytes(string).length
|
||
default:
|
||
if (loweredCase) return utf8ToBytes(string).length // assume utf8
|
||
encoding = ('' + encoding).toLowerCase()
|
||
loweredCase = true
|
||
}
|
||
}
|
||
}
|
||
Buffer.byteLength = byteLength
|
||
|
||
function slowToString (encoding, start, end) {
|
||
var loweredCase = false
|
||
|
||
start = start | 0
|
||
end = end === undefined || end === Infinity ? this.length : end | 0
|
||
|
||
if (!encoding) encoding = 'utf8'
|
||
if (start < 0) start = 0
|
||
if (end > this.length) end = this.length
|
||
if (end <= start) return ''
|
||
|
||
while (true) {
|
||
switch (encoding) {
|
||
case 'hex':
|
||
return hexSlice(this, start, end)
|
||
|
||
case 'utf8':
|
||
case 'utf-8':
|
||
return utf8Slice(this, start, end)
|
||
|
||
case 'ascii':
|
||
return asciiSlice(this, start, end)
|
||
|
||
case 'binary':
|
||
return binarySlice(this, start, end)
|
||
|
||
case 'base64':
|
||
return base64Slice(this, start, end)
|
||
|
||
case 'ucs2':
|
||
case 'ucs-2':
|
||
case 'utf16le':
|
||
case 'utf-16le':
|
||
return utf16leSlice(this, start, end)
|
||
|
||
default:
|
||
if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
|
||
encoding = (encoding + '').toLowerCase()
|
||
loweredCase = true
|
||
}
|
||
}
|
||
}
|
||
|
||
// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect
|
||
// Buffer instances.
|
||
Buffer.prototype._isBuffer = true
|
||
|
||
Buffer.prototype.toString = function toString () {
|
||
var length = this.length | 0
|
||
if (length === 0) return ''
|
||
if (arguments.length === 0) return utf8Slice(this, 0, length)
|
||
return slowToString.apply(this, arguments)
|
||
}
|
||
|
||
Buffer.prototype.equals = function equals (b) {
|
||
if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
|
||
if (this === b) return true
|
||
return Buffer.compare(this, b) === 0
|
||
}
|
||
|
||
Buffer.prototype.inspect = function inspect () {
|
||
var str = ''
|
||
var max = exports.INSPECT_MAX_BYTES
|
||
if (this.length > 0) {
|
||
str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')
|
||
if (this.length > max) str += ' ... '
|
||
}
|
||
return '<Buffer ' + str + '>'
|
||
}
|
||
|
||
Buffer.prototype.compare = function compare (b) {
|
||
if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
|
||
return Buffer.compare(this, b)
|
||
}
|
||
|
||
Buffer.prototype.indexOf = function indexOf (val, byteOffset) {
|
||
if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff
|
||
else if (byteOffset < -0x80000000) byteOffset = -0x80000000
|
||
byteOffset >>= 0
|
||
|
||
if (this.length === 0) return -1
|
||
if (byteOffset >= this.length) return -1
|
||
|
||
// Negative offsets start from the end of the buffer
|
||
if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0)
|
||
|
||
if (typeof val === 'string') {
|
||
if (val.length === 0) return -1 // special case: looking for empty string always fails
|
||
return String.prototype.indexOf.call(this, val, byteOffset)
|
||
}
|
||
if (Buffer.isBuffer(val)) {
|
||
return arrayIndexOf(this, val, byteOffset)
|
||
}
|
||
if (typeof val === 'number') {
|
||
if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') {
|
||
return Uint8Array.prototype.indexOf.call(this, val, byteOffset)
|
||
}
|
||
return arrayIndexOf(this, [ val ], byteOffset)
|
||
}
|
||
|
||
function arrayIndexOf (arr, val, byteOffset) {
|
||
var foundIndex = -1
|
||
for (var i = 0; byteOffset + i < arr.length; i++) {
|
||
if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) {
|
||
if (foundIndex === -1) foundIndex = i
|
||
if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex
|
||
} else {
|
||
foundIndex = -1
|
||
}
|
||
}
|
||
return -1
|
||
}
|
||
|
||
throw new TypeError('val must be string, number or Buffer')
|
||
}
|
||
|
||
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
|
||
if (strLen % 2 !== 0) throw new Error('Invalid hex string')
|
||
|
||
if (length > strLen / 2) {
|
||
length = strLen / 2
|
||
}
|
||
for (var i = 0; i < length; i++) {
|
||
var parsed = parseInt(string.substr(i * 2, 2), 16)
|
||
if (isNaN(parsed)) throw new Error('Invalid hex string')
|
||
buf[offset + i] = parsed
|
||
}
|
||
return i
|
||
}
|
||
|
||
function utf8Write (buf, string, offset, length) {
|
||
return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length)
|
||
}
|
||
|
||
function asciiWrite (buf, string, offset, length) {
|
||
return blitBuffer(asciiToBytes(string), buf, offset, length)
|
||
}
|
||
|
||
function binaryWrite (buf, string, offset, length) {
|
||
return asciiWrite(buf, string, offset, length)
|
||
}
|
||
|
||
function base64Write (buf, string, offset, length) {
|
||
return blitBuffer(base64ToBytes(string), buf, offset, length)
|
||
}
|
||
|
||
function ucs2Write (buf, string, offset, length) {
|
||
return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length)
|
||
}
|
||
|
||
Buffer.prototype.write = function write (string, offset, length, encoding) {
|
||
// Buffer#write(string)
|
||
if (offset === undefined) {
|
||
encoding = 'utf8'
|
||
length = this.length
|
||
offset = 0
|
||
// Buffer#write(string, encoding)
|
||
} else if (length === undefined && typeof offset === 'string') {
|
||
encoding = offset
|
||
length = this.length
|
||
offset = 0
|
||
// Buffer#write(string, offset[, length][, encoding])
|
||
} else if (isFinite(offset)) {
|
||
offset = offset | 0
|
||
if (isFinite(length)) {
|
||
length = length | 0
|
||
if (encoding === undefined) encoding = 'utf8'
|
||
} else {
|
||
encoding = length
|
||
length = undefined
|
||
}
|
||
// legacy write(string, encoding, offset, length) - remove in v0.13
|
||
} else {
|
||
var swap = encoding
|
||
encoding = offset
|
||
offset = length | 0
|
||
length = swap
|
||
}
|
||
|
||
var remaining = this.length - offset
|
||
if (length === undefined || length > remaining) length = remaining
|
||
|
||
if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) {
|
||
throw new RangeError('attempt to write outside buffer bounds')
|
||
}
|
||
|
||
if (!encoding) encoding = 'utf8'
|
||
|
||
var loweredCase = false
|
||
for (;;) {
|
||
switch (encoding) {
|
||
case 'hex':
|
||
return hexWrite(this, string, offset, length)
|
||
|
||
case 'utf8':
|
||
case 'utf-8':
|
||
return utf8Write(this, string, offset, length)
|
||
|
||
case 'ascii':
|
||
return asciiWrite(this, string, offset, length)
|
||
|
||
case 'binary':
|
||
return binaryWrite(this, string, offset, length)
|
||
|
||
case 'base64':
|
||
// Warning: maxLength not taken into account in base64Write
|
||
return base64Write(this, string, offset, length)
|
||
|
||
case 'ucs2':
|
||
case 'ucs-2':
|
||
case 'utf16le':
|
||
case 'utf-16le':
|
||
return ucs2Write(this, string, offset, length)
|
||
|
||
default:
|
||
if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding)
|
||
encoding = ('' + encoding).toLowerCase()
|
||
loweredCase = true
|
||
}
|
||
}
|
||
}
|
||
|
||
Buffer.prototype.toJSON = function toJSON () {
|
||
return {
|
||
type: 'Buffer',
|
||
data: Array.prototype.slice.call(this._arr || this, 0)
|
||
}
|
||
}
|
||
|
||
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) {
|
||
end = Math.min(buf.length, end)
|
||
var res = []
|
||
|
||
var i = start
|
||
while (i < end) {
|
||
var firstByte = buf[i]
|
||
var codePoint = null
|
||
var bytesPerSequence = (firstByte > 0xEF) ? 4
|
||
: (firstByte > 0xDF) ? 3
|
||
: (firstByte > 0xBF) ? 2
|
||
: 1
|
||
|
||
if (i + bytesPerSequence <= end) {
|
||
var secondByte, thirdByte, fourthByte, tempCodePoint
|
||
|
||
switch (bytesPerSequence) {
|
||
case 1:
|
||
if (firstByte < 0x80) {
|
||
codePoint = firstByte
|
||
}
|
||
break
|
||
case 2:
|
||
secondByte = buf[i + 1]
|
||
if ((secondByte & 0xC0) === 0x80) {
|
||
tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F)
|
||
if (tempCodePoint > 0x7F) {
|
||
codePoint = tempCodePoint
|
||
}
|
||
}
|
||
break
|
||
case 3:
|
||
secondByte = buf[i + 1]
|
||
thirdByte = buf[i + 2]
|
||
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) {
|
||
tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F)
|
||
if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) {
|
||
codePoint = tempCodePoint
|
||
}
|
||
}
|
||
break
|
||
case 4:
|
||
secondByte = buf[i + 1]
|
||
thirdByte = buf[i + 2]
|
||
fourthByte = buf[i + 3]
|
||
if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) {
|
||
tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F)
|
||
if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) {
|
||
codePoint = tempCodePoint
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (codePoint === null) {
|
||
// we did not generate a valid codePoint so insert a
|
||
// replacement char (U+FFFD) and advance only 1 byte
|
||
codePoint = 0xFFFD
|
||
bytesPerSequence = 1
|
||
} else if (codePoint > 0xFFFF) {
|
||
// encode to utf16 (surrogate pair dance)
|
||
codePoint -= 0x10000
|
||
res.push(codePoint >>> 10 & 0x3FF | 0xD800)
|
||
codePoint = 0xDC00 | codePoint & 0x3FF
|
||
}
|
||
|
||
res.push(codePoint)
|
||
i += bytesPerSequence
|
||
}
|
||
|
||
return decodeCodePointsArray(res)
|
||
}
|
||
|
||
// Based on http://stackoverflow.com/a/22747272/680742, the browser with
|
||
// the lowest limit is Chrome, with 0x10000 args.
|
||
// We go 1 magnitude less, for safety
|
||
var MAX_ARGUMENTS_LENGTH = 0x1000
|
||
|
||
function decodeCodePointsArray (codePoints) {
|
||
var len = codePoints.length
|
||
if (len <= MAX_ARGUMENTS_LENGTH) {
|
||
return String.fromCharCode.apply(String, codePoints) // avoid extra slice()
|
||
}
|
||
|
||
// Decode in chunks to avoid "call stack size exceeded".
|
||
var res = ''
|
||
var i = 0
|
||
while (i < len) {
|
||
res += String.fromCharCode.apply(
|
||
String,
|
||
codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH)
|
||
)
|
||
}
|
||
return res
|
||
}
|
||
|
||
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] & 0x7F)
|
||
}
|
||
return ret
|
||
}
|
||
|
||
function binarySlice (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 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 slice (start, end) {
|
||
var len = this.length
|
||
start = ~~start
|
||
end = end === undefined ? len : ~~end
|
||
|
||
if (start < 0) {
|
||
start += len
|
||
if (start < 0) start = 0
|
||
} else if (start > len) {
|
||
start = len
|
||
}
|
||
|
||
if (end < 0) {
|
||
end += len
|
||
if (end < 0) end = 0
|
||
} else if (end > len) {
|
||
end = len
|
||
}
|
||
|
||
if (end < start) end = start
|
||
|
||
var newBuf
|
||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||
newBuf = this.subarray(start, end)
|
||
newBuf.__proto__ = Buffer.prototype
|
||
} else {
|
||
var sliceLen = end - start
|
||
newBuf = new Buffer(sliceLen, undefined)
|
||
for (var i = 0; i < sliceLen; i++) {
|
||
newBuf[i] = this[i + start]
|
||
}
|
||
}
|
||
|
||
if (newBuf.length) newBuf.parent = this.parent || this
|
||
|
||
return newBuf
|
||
}
|
||
|
||
/*
|
||
* Need to make sure that buffer isn't trying to write out of bounds.
|
||
*/
|
||
function checkOffset (offset, ext, length) {
|
||
if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint')
|
||
if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length')
|
||
}
|
||
|
||
Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) {
|
||
offset = offset | 0
|
||
byteLength = byteLength | 0
|
||
if (!noAssert) checkOffset(offset, byteLength, this.length)
|
||
|
||
var val = this[offset]
|
||
var mul = 1
|
||
var i = 0
|
||
while (++i < byteLength && (mul *= 0x100)) {
|
||
val += this[offset + i] * mul
|
||
}
|
||
|
||
return val
|
||
}
|
||
|
||
Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) {
|
||
offset = offset | 0
|
||
byteLength = byteLength | 0
|
||
if (!noAssert) {
|
||
checkOffset(offset, byteLength, this.length)
|
||
}
|
||
|
||
var val = this[offset + --byteLength]
|
||
var mul = 1
|
||
while (byteLength > 0 && (mul *= 0x100)) {
|
||
val += this[offset + --byteLength] * mul
|
||
}
|
||
|
||
return val
|
||
}
|
||
|
||
Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) {
|
||
if (!noAssert) checkOffset(offset, 1, this.length)
|
||
return this[offset]
|
||
}
|
||
|
||
Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) {
|
||
if (!noAssert) checkOffset(offset, 2, this.length)
|
||
return this[offset] | (this[offset + 1] << 8)
|
||
}
|
||
|
||
Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) {
|
||
if (!noAssert) checkOffset(offset, 2, this.length)
|
||
return (this[offset] << 8) | this[offset + 1]
|
||
}
|
||
|
||
Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) {
|
||
if (!noAssert) checkOffset(offset, 4, this.length)
|
||
|
||
return ((this[offset]) |
|
||
(this[offset + 1] << 8) |
|
||
(this[offset + 2] << 16)) +
|
||
(this[offset + 3] * 0x1000000)
|
||
}
|
||
|
||
Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) {
|
||
if (!noAssert) checkOffset(offset, 4, this.length)
|
||
|
||
return (this[offset] * 0x1000000) +
|
||
((this[offset + 1] << 16) |
|
||
(this[offset + 2] << 8) |
|
||
this[offset + 3])
|
||
}
|
||
|
||
Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) {
|
||
offset = offset | 0
|
||
byteLength = byteLength | 0
|
||
if (!noAssert) checkOffset(offset, byteLength, this.length)
|
||
|
||
var val = this[offset]
|
||
var mul = 1
|
||
var i = 0
|
||
while (++i < byteLength && (mul *= 0x100)) {
|
||
val += this[offset + i] * mul
|
||
}
|
||
mul *= 0x80
|
||
|
||
if (val >= mul) val -= Math.pow(2, 8 * byteLength)
|
||
|
||
return val
|
||
}
|
||
|
||
Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) {
|
||
offset = offset | 0
|
||
byteLength = byteLength | 0
|
||
if (!noAssert) checkOffset(offset, byteLength, this.length)
|
||
|
||
var i = byteLength
|
||
var mul = 1
|
||
var val = this[offset + --i]
|
||
while (i > 0 && (mul *= 0x100)) {
|
||
val += this[offset + --i] * mul
|
||
}
|
||
mul *= 0x80
|
||
|
||
if (val >= mul) val -= Math.pow(2, 8 * byteLength)
|
||
|
||
return val
|
||
}
|
||
|
||
Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) {
|
||
if (!noAssert) checkOffset(offset, 1, this.length)
|
||
if (!(this[offset] & 0x80)) return (this[offset])
|
||
return ((0xff - this[offset] + 1) * -1)
|
||
}
|
||
|
||
Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) {
|
||
if (!noAssert) checkOffset(offset, 2, this.length)
|
||
var val = this[offset] | (this[offset + 1] << 8)
|
||
return (val & 0x8000) ? val | 0xFFFF0000 : val
|
||
}
|
||
|
||
Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) {
|
||
if (!noAssert) checkOffset(offset, 2, this.length)
|
||
var val = this[offset + 1] | (this[offset] << 8)
|
||
return (val & 0x8000) ? val | 0xFFFF0000 : val
|
||
}
|
||
|
||
Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) {
|
||
if (!noAssert) checkOffset(offset, 4, this.length)
|
||
|
||
return (this[offset]) |
|
||
(this[offset + 1] << 8) |
|
||
(this[offset + 2] << 16) |
|
||
(this[offset + 3] << 24)
|
||
}
|
||
|
||
Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) {
|
||
if (!noAssert) checkOffset(offset, 4, this.length)
|
||
|
||
return (this[offset] << 24) |
|
||
(this[offset + 1] << 16) |
|
||
(this[offset + 2] << 8) |
|
||
(this[offset + 3])
|
||
}
|
||
|
||
Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) {
|
||
if (!noAssert) checkOffset(offset, 4, this.length)
|
||
return ieee754.read(this, offset, true, 23, 4)
|
||
}
|
||
|
||
Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) {
|
||
if (!noAssert) checkOffset(offset, 4, this.length)
|
||
return ieee754.read(this, offset, false, 23, 4)
|
||
}
|
||
|
||
Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) {
|
||
if (!noAssert) checkOffset(offset, 8, this.length)
|
||
return ieee754.read(this, offset, true, 52, 8)
|
||
}
|
||
|
||
Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) {
|
||
if (!noAssert) checkOffset(offset, 8, this.length)
|
||
return ieee754.read(this, offset, false, 52, 8)
|
||
}
|
||
|
||
function checkInt (buf, value, offset, ext, max, min) {
|
||
if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance')
|
||
if (value > max || value < min) throw new RangeError('value is out of bounds')
|
||
if (offset + ext > buf.length) throw new RangeError('index out of range')
|
||
}
|
||
|
||
Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) {
|
||
value = +value
|
||
offset = offset | 0
|
||
byteLength = byteLength | 0
|
||
if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)
|
||
|
||
var mul = 1
|
||
var i = 0
|
||
this[offset] = value & 0xFF
|
||
while (++i < byteLength && (mul *= 0x100)) {
|
||
this[offset + i] = (value / mul) & 0xFF
|
||
}
|
||
|
||
return offset + byteLength
|
||
}
|
||
|
||
Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) {
|
||
value = +value
|
||
offset = offset | 0
|
||
byteLength = byteLength | 0
|
||
if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0)
|
||
|
||
var i = byteLength - 1
|
||
var mul = 1
|
||
this[offset + i] = value & 0xFF
|
||
while (--i >= 0 && (mul *= 0x100)) {
|
||
this[offset + i] = (value / mul) & 0xFF
|
||
}
|
||
|
||
return offset + byteLength
|
||
}
|
||
|
||
Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) {
|
||
value = +value
|
||
offset = offset | 0
|
||
if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0)
|
||
if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
|
||
this[offset] = (value & 0xff)
|
||
return offset + 1
|
||
}
|
||
|
||
function objectWriteUInt16 (buf, value, offset, littleEndian) {
|
||
if (value < 0) value = 0xffff + value + 1
|
||
for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {
|
||
buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
|
||
(littleEndian ? i : 1 - i) * 8
|
||
}
|
||
}
|
||
|
||
Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) {
|
||
value = +value
|
||
offset = offset | 0
|
||
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
|
||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||
this[offset] = (value & 0xff)
|
||
this[offset + 1] = (value >>> 8)
|
||
} else {
|
||
objectWriteUInt16(this, value, offset, true)
|
||
}
|
||
return offset + 2
|
||
}
|
||
|
||
Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) {
|
||
value = +value
|
||
offset = offset | 0
|
||
if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0)
|
||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||
this[offset] = (value >>> 8)
|
||
this[offset + 1] = (value & 0xff)
|
||
} else {
|
||
objectWriteUInt16(this, value, offset, false)
|
||
}
|
||
return offset + 2
|
||
}
|
||
|
||
function objectWriteUInt32 (buf, value, offset, littleEndian) {
|
||
if (value < 0) value = 0xffffffff + value + 1
|
||
for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {
|
||
buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
|
||
}
|
||
}
|
||
|
||
Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) {
|
||
value = +value
|
||
offset = offset | 0
|
||
if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
|
||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||
this[offset + 3] = (value >>> 24)
|
||
this[offset + 2] = (value >>> 16)
|
||
this[offset + 1] = (value >>> 8)
|
||
this[offset] = (value & 0xff)
|
||
} else {
|
||
objectWriteUInt32(this, value, offset, true)
|
||
}
|
||
return offset + 4
|
||
}
|
||
|
||
Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) {
|
||
value = +value
|
||
offset = offset | 0
|
||
if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0)
|
||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||
this[offset] = (value >>> 24)
|
||
this[offset + 1] = (value >>> 16)
|
||
this[offset + 2] = (value >>> 8)
|
||
this[offset + 3] = (value & 0xff)
|
||
} else {
|
||
objectWriteUInt32(this, value, offset, false)
|
||
}
|
||
return offset + 4
|
||
}
|
||
|
||
Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) {
|
||
value = +value
|
||
offset = offset | 0
|
||
if (!noAssert) {
|
||
var limit = Math.pow(2, 8 * byteLength - 1)
|
||
|
||
checkInt(this, value, offset, byteLength, limit - 1, -limit)
|
||
}
|
||
|
||
var i = 0
|
||
var mul = 1
|
||
var sub = value < 0 ? 1 : 0
|
||
this[offset] = value & 0xFF
|
||
while (++i < byteLength && (mul *= 0x100)) {
|
||
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
|
||
}
|
||
|
||
return offset + byteLength
|
||
}
|
||
|
||
Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) {
|
||
value = +value
|
||
offset = offset | 0
|
||
if (!noAssert) {
|
||
var limit = Math.pow(2, 8 * byteLength - 1)
|
||
|
||
checkInt(this, value, offset, byteLength, limit - 1, -limit)
|
||
}
|
||
|
||
var i = byteLength - 1
|
||
var mul = 1
|
||
var sub = value < 0 ? 1 : 0
|
||
this[offset + i] = value & 0xFF
|
||
while (--i >= 0 && (mul *= 0x100)) {
|
||
this[offset + i] = ((value / mul) >> 0) - sub & 0xFF
|
||
}
|
||
|
||
return offset + byteLength
|
||
}
|
||
|
||
Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) {
|
||
value = +value
|
||
offset = offset | 0
|
||
if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80)
|
||
if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
|
||
if (value < 0) value = 0xff + value + 1
|
||
this[offset] = (value & 0xff)
|
||
return offset + 1
|
||
}
|
||
|
||
Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) {
|
||
value = +value
|
||
offset = offset | 0
|
||
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
|
||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||
this[offset] = (value & 0xff)
|
||
this[offset + 1] = (value >>> 8)
|
||
} else {
|
||
objectWriteUInt16(this, value, offset, true)
|
||
}
|
||
return offset + 2
|
||
}
|
||
|
||
Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) {
|
||
value = +value
|
||
offset = offset | 0
|
||
if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000)
|
||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||
this[offset] = (value >>> 8)
|
||
this[offset + 1] = (value & 0xff)
|
||
} else {
|
||
objectWriteUInt16(this, value, offset, false)
|
||
}
|
||
return offset + 2
|
||
}
|
||
|
||
Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) {
|
||
value = +value
|
||
offset = offset | 0
|
||
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
|
||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||
this[offset] = (value & 0xff)
|
||
this[offset + 1] = (value >>> 8)
|
||
this[offset + 2] = (value >>> 16)
|
||
this[offset + 3] = (value >>> 24)
|
||
} else {
|
||
objectWriteUInt32(this, value, offset, true)
|
||
}
|
||
return offset + 4
|
||
}
|
||
|
||
Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) {
|
||
value = +value
|
||
offset = offset | 0
|
||
if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
|
||
if (value < 0) value = 0xffffffff + value + 1
|
||
if (Buffer.TYPED_ARRAY_SUPPORT) {
|
||
this[offset] = (value >>> 24)
|
||
this[offset + 1] = (value >>> 16)
|
||
this[offset + 2] = (value >>> 8)
|
||
this[offset + 3] = (value & 0xff)
|
||
} else {
|
||
objectWriteUInt32(this, value, offset, false)
|
||
}
|
||
return offset + 4
|
||
}
|
||
|
||
function checkIEEE754 (buf, value, offset, ext, max, min) {
|
||
if (offset + ext > buf.length) throw new RangeError('index out of range')
|
||
if (offset < 0) throw new RangeError('index out of range')
|
||
}
|
||
|
||
function writeFloat (buf, value, offset, littleEndian, noAssert) {
|
||
if (!noAssert) {
|
||
checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)
|
||
}
|
||
ieee754.write(buf, value, offset, littleEndian, 23, 4)
|
||
return offset + 4
|
||
}
|
||
|
||
Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) {
|
||
return writeFloat(this, value, offset, true, noAssert)
|
||
}
|
||
|
||
Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) {
|
||
return writeFloat(this, value, offset, false, noAssert)
|
||
}
|
||
|
||
function writeDouble (buf, value, offset, littleEndian, noAssert) {
|
||
if (!noAssert) {
|
||
checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)
|
||
}
|
||
ieee754.write(buf, value, offset, littleEndian, 52, 8)
|
||
return offset + 8
|
||
}
|
||
|
||
Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) {
|
||
return writeDouble(this, value, offset, true, noAssert)
|
||
}
|
||
|
||
Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) {
|
||
return writeDouble(this, value, offset, false, noAssert)
|
||
}
|
||
|
||
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
|
||
Buffer.prototype.copy = function copy (target, targetStart, start, end) {
|
||
if (!start) start = 0
|
||
if (!end && end !== 0) end = this.length
|
||
if (targetStart >= target.length) targetStart = target.length
|
||
if (!targetStart) targetStart = 0
|
||
if (end > 0 && end < start) end = start
|
||
|
||
// Copy 0 bytes; we're done
|
||
if (end === start) return 0
|
||
if (target.length === 0 || this.length === 0) return 0
|
||
|
||
// Fatal error conditions
|
||
if (targetStart < 0) {
|
||
throw new RangeError('targetStart out of bounds')
|
||
}
|
||
if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds')
|
||
if (end < 0) throw new RangeError('sourceEnd out of bounds')
|
||
|
||
// Are we oob?
|
||
if (end > this.length) end = this.length
|
||
if (target.length - targetStart < end - start) {
|
||
end = target.length - targetStart + start
|
||
}
|
||
|
||
var len = end - start
|
||
var i
|
||
|
||
if (this === target && start < targetStart && targetStart < end) {
|
||
// descending copy from end
|
||
for (i = len - 1; i >= 0; i--) {
|
||
target[i + targetStart] = this[i + start]
|
||
}
|
||
} else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) {
|
||
// ascending copy from start
|
||
for (i = 0; i < len; i++) {
|
||
target[i + targetStart] = this[i + start]
|
||
}
|
||
} else {
|
||
Uint8Array.prototype.set.call(
|
||
target,
|
||
this.subarray(start, start + len),
|
||
targetStart
|
||
)
|
||
}
|
||
|
||
return len
|
||
}
|
||
|
||
// fill(value, start=0, end=buffer.length)
|
||
Buffer.prototype.fill = function fill (value, start, end) {
|
||
if (!value) value = 0
|
||
if (!start) start = 0
|
||
if (!end) end = this.length
|
||
|
||
if (end < start) throw new RangeError('end < start')
|
||
|
||
// Fill 0 bytes; we're done
|
||
if (end === start) return
|
||
if (this.length === 0) return
|
||
|
||
if (start < 0 || start >= this.length) throw new RangeError('start out of bounds')
|
||
if (end < 0 || end > this.length) throw new RangeError('end out of bounds')
|
||
|
||
var i
|
||
if (typeof value === 'number') {
|
||
for (i = start; i < end; i++) {
|
||
this[i] = value
|
||
}
|
||
} else {
|
||
var bytes = utf8ToBytes(value.toString())
|
||
var len = bytes.length
|
||
for (i = start; i < end; i++) {
|
||
this[i] = bytes[i % len]
|
||
}
|
||
}
|
||
|
||
return this
|
||
}
|
||
|
||
// HELPER FUNCTIONS
|
||
// ================
|
||
|
||
var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g
|
||
|
||
function base64clean (str) {
|
||
// Node strips out invalid characters like \n and \t from the string, base64-js does not
|
||
str = stringtrim(str).replace(INVALID_BASE64_RE, '')
|
||
// Node converts strings with length < 2 to ''
|
||
if (str.length < 2) return ''
|
||
// Node allows for non-padded base64 strings (missing trailing ===), base64-js does not
|
||
while (str.length % 4 !== 0) {
|
||
str = str + '='
|
||
}
|
||
return str
|
||
}
|
||
|
||
function stringtrim (str) {
|
||
if (str.trim) return str.trim()
|
||
return str.replace(/^\s+|\s+$/g, '')
|
||
}
|
||
|
||
function toHex (n) {
|
||
if (n < 16) return '0' + n.toString(16)
|
||
return n.toString(16)
|
||
}
|
||
|
||
function utf8ToBytes (string, units) {
|
||
units = units || Infinity
|
||
var codePoint
|
||
var length = string.length
|
||
var leadSurrogate = null
|
||
var bytes = []
|
||
|
||
for (var i = 0; i < length; i++) {
|
||
codePoint = string.charCodeAt(i)
|
||
|
||
// is surrogate component
|
||
if (codePoint > 0xD7FF && codePoint < 0xE000) {
|
||
// last char was a lead
|
||
if (!leadSurrogate) {
|
||
// no lead yet
|
||
if (codePoint > 0xDBFF) {
|
||
// unexpected trail
|
||
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
||
continue
|
||
} else if (i + 1 === length) {
|
||
// unpaired lead
|
||
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
||
continue
|
||
}
|
||
|
||
// valid lead
|
||
leadSurrogate = codePoint
|
||
|
||
continue
|
||
}
|
||
|
||
// 2 leads in a row
|
||
if (codePoint < 0xDC00) {
|
||
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
||
leadSurrogate = codePoint
|
||
continue
|
||
}
|
||
|
||
// valid surrogate pair
|
||
codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000
|
||
} else if (leadSurrogate) {
|
||
// valid bmp char, but last char was a lead
|
||
if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD)
|
||
}
|
||
|
||
leadSurrogate = null
|
||
|
||
// encode utf8
|
||
if (codePoint < 0x80) {
|
||
if ((units -= 1) < 0) break
|
||
bytes.push(codePoint)
|
||
} else if (codePoint < 0x800) {
|
||
if ((units -= 2) < 0) break
|
||
bytes.push(
|
||
codePoint >> 0x6 | 0xC0,
|
||
codePoint & 0x3F | 0x80
|
||
)
|
||
} else if (codePoint < 0x10000) {
|
||
if ((units -= 3) < 0) break
|
||
bytes.push(
|
||
codePoint >> 0xC | 0xE0,
|
||
codePoint >> 0x6 & 0x3F | 0x80,
|
||
codePoint & 0x3F | 0x80
|
||
)
|
||
} else if (codePoint < 0x110000) {
|
||
if ((units -= 4) < 0) break
|
||
bytes.push(
|
||
codePoint >> 0x12 | 0xF0,
|
||
codePoint >> 0xC & 0x3F | 0x80,
|
||
codePoint >> 0x6 & 0x3F | 0x80,
|
||
codePoint & 0x3F | 0x80
|
||
)
|
||
} else {
|
||
throw new Error('Invalid code point')
|
||
}
|
||
}
|
||
|
||
return bytes
|
||
}
|
||
|
||
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, units) {
|
||
var c, hi, lo
|
||
var byteArray = []
|
||
for (var i = 0; i < str.length; i++) {
|
||
if ((units -= 2) < 0) break
|
||
|
||
c = str.charCodeAt(i)
|
||
hi = c >> 8
|
||
lo = c % 256
|
||
byteArray.push(lo)
|
||
byteArray.push(hi)
|
||
}
|
||
|
||
return byteArray
|
||
}
|
||
|
||
function base64ToBytes (str) {
|
||
return base64.toByteArray(base64clean(str))
|
||
}
|
||
|
||
function blitBuffer (src, dst, offset, length) {
|
||
for (var i = 0; i < length; i++) {
|
||
if ((i + offset >= dst.length) || (i >= src.length)) break
|
||
dst[i + offset] = src[i]
|
||
}
|
||
return i
|
||
}
|
||
|
||
/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(154).Buffer, (function() { return this; }())))
|
||
|
||
/***/ },
|
||
/* 155 */
|
||
/***/ function(module, exports) {
|
||
|
||
'use strict'
|
||
|
||
exports.toByteArray = toByteArray
|
||
exports.fromByteArray = fromByteArray
|
||
|
||
var lookup = []
|
||
var revLookup = []
|
||
var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array
|
||
|
||
function init () {
|
||
var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
|
||
for (var i = 0, len = code.length; i < len; ++i) {
|
||
lookup[i] = code[i]
|
||
revLookup[code.charCodeAt(i)] = i
|
||
}
|
||
|
||
revLookup['-'.charCodeAt(0)] = 62
|
||
revLookup['_'.charCodeAt(0)] = 63
|
||
}
|
||
|
||
init()
|
||
|
||
function toByteArray (b64) {
|
||
var i, j, l, tmp, placeHolders, arr
|
||
var len = b64.length
|
||
|
||
if (len % 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
|
||
placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0
|
||
|
||
// base64 is 4/3 + up to two characters of the original data
|
||
arr = new Arr(len * 3 / 4 - placeHolders)
|
||
|
||
// if there are placeholders, only get up to the last complete 4 chars
|
||
l = placeHolders > 0 ? len - 4 : len
|
||
|
||
var L = 0
|
||
|
||
for (i = 0, j = 0; i < l; i += 4, j += 3) {
|
||
tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)]
|
||
arr[L++] = (tmp >> 16) & 0xFF
|
||
arr[L++] = (tmp >> 8) & 0xFF
|
||
arr[L++] = tmp & 0xFF
|
||
}
|
||
|
||
if (placeHolders === 2) {
|
||
tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4)
|
||
arr[L++] = tmp & 0xFF
|
||
} else if (placeHolders === 1) {
|
||
tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2)
|
||
arr[L++] = (tmp >> 8) & 0xFF
|
||
arr[L++] = tmp & 0xFF
|
||
}
|
||
|
||
return arr
|
||
}
|
||
|
||
function tripletToBase64 (num) {
|
||
return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]
|
||
}
|
||
|
||
function encodeChunk (uint8, start, end) {
|
||
var tmp
|
||
var output = []
|
||
for (var i = start; i < end; i += 3) {
|
||
tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2])
|
||
output.push(tripletToBase64(tmp))
|
||
}
|
||
return output.join('')
|
||
}
|
||
|
||
function fromByteArray (uint8) {
|
||
var tmp
|
||
var len = uint8.length
|
||
var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes
|
||
var output = ''
|
||
var parts = []
|
||
var maxChunkLength = 16383 // must be multiple of 3
|
||
|
||
// go through the array every three bytes, we'll deal with trailing stuff later
|
||
for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) {
|
||
parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength)))
|
||
}
|
||
|
||
// pad the end with zeros, but make sure to not forget the extra bytes
|
||
if (extraBytes === 1) {
|
||
tmp = uint8[len - 1]
|
||
output += lookup[tmp >> 2]
|
||
output += lookup[(tmp << 4) & 0x3F]
|
||
output += '=='
|
||
} else if (extraBytes === 2) {
|
||
tmp = (uint8[len - 2] << 8) + (uint8[len - 1])
|
||
output += lookup[tmp >> 10]
|
||
output += lookup[(tmp >> 4) & 0x3F]
|
||
output += lookup[(tmp << 2) & 0x3F]
|
||
output += '='
|
||
}
|
||
|
||
parts.push(output)
|
||
|
||
return parts.join('')
|
||
}
|
||
|
||
|
||
/***/ },
|
||
/* 156 */
|
||
/***/ function(module, exports) {
|
||
|
||
exports.read = function (buffer, offset, isLE, mLen, nBytes) {
|
||
var e, m
|
||
var eLen = nBytes * 8 - mLen - 1
|
||
var eMax = (1 << eLen) - 1
|
||
var eBias = eMax >> 1
|
||
var nBits = -7
|
||
var i = isLE ? (nBytes - 1) : 0
|
||
var d = isLE ? -1 : 1
|
||
var 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
|
||
var eLen = nBytes * 8 - mLen - 1
|
||
var eMax = (1 << eLen) - 1
|
||
var eBias = eMax >> 1
|
||
var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0)
|
||
var i = isLE ? 0 : (nBytes - 1)
|
||
var d = isLE ? 1 : -1
|
||
var 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
|
||
}
|
||
|
||
|
||
/***/ },
|
||
/* 157 */
|
||
/***/ function(module, exports) {
|
||
|
||
var toString = {}.toString;
|
||
|
||
module.exports = Array.isArray || function (arr) {
|
||
return toString.call(arr) == '[object Array]';
|
||
};
|
||
|
||
|
||
/***/ },
|
||
/* 158 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
const Buffer = __webpack_require__(154).Buffer
|
||
|
||
class Node {
|
||
constructor(payload, next) {
|
||
this.payload = payload || null;
|
||
this.hash = null;
|
||
this.next = next ? (next instanceof Array ? next : [next]) : [];
|
||
|
||
// Convert instances of Node to its hash
|
||
this.next = this.next.map((f) => {
|
||
if(f instanceof Node)
|
||
return f.hash;
|
||
return f;
|
||
})
|
||
}
|
||
|
||
get asJson() {
|
||
let res = { payload: this.payload }
|
||
let next = this.next.map((f) => {
|
||
if(f instanceof Node)
|
||
return f.hash
|
||
return f;
|
||
});
|
||
Object.assign(res, { next: next });
|
||
return res;
|
||
}
|
||
|
||
hasChild(a) {
|
||
for(let i = 0; i < this.next.length; i++) {
|
||
if(this.next[i] === a.hash)
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
static create(ipfs, data, next) {
|
||
if(!ipfs) throw new Error("Node requires ipfs instance")
|
||
return new Promise((resolve, reject) => {
|
||
const node = new Node(data, next);
|
||
Node.getIpfsHash(ipfs, node)
|
||
.then((hash) => {
|
||
node.hash = hash;
|
||
resolve(node);
|
||
}).catch(reject)
|
||
});
|
||
}
|
||
|
||
static fromIpfsHash(ipfs, hash) {
|
||
if(!ipfs) throw new Error("Node requires ipfs instance")
|
||
if(!hash) throw new Error("Invalid hash: " + hash)
|
||
return new Promise((resolve, reject) => {
|
||
ipfs.object.get(hash)
|
||
.then((obj) => {
|
||
const f = JSON.parse(obj.Data)
|
||
Node.create(ipfs, f.payload, f.next).then(resolve).catch(reject);
|
||
}).catch(reject);
|
||
});
|
||
}
|
||
|
||
static getIpfsHash(ipfs, node) {
|
||
if(!ipfs) throw new Error("Node requires ipfs instance")
|
||
return new Promise((resolve, reject) => {
|
||
ipfs.object.put(new Buffer(JSON.stringify({ Data: JSON.stringify(node.asJson) })))
|
||
.then((res) => resolve(res.Hash))
|
||
.catch(reject);
|
||
});
|
||
}
|
||
|
||
static equals(a, b) {
|
||
return a.hash === b.hash;
|
||
}
|
||
}
|
||
|
||
module.exports = Node;
|
||
|
||
|
||
/***/ },
|
||
/* 159 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _stringify = __webpack_require__(66);
|
||
|
||
var _stringify2 = _interopRequireDefault(_stringify);
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _createClass2 = __webpack_require__(57);
|
||
|
||
var _createClass3 = _interopRequireDefault(_createClass2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var fs = __webpack_require__(64);
|
||
var path = __webpack_require__(63);
|
||
var logger = __webpack_require__(61).create("orbit-db.Cache");
|
||
|
||
// const defaultFilepath = path.resolve('./orbit-db-cache.json');
|
||
// let filePath = defaultFilepath;
|
||
var filePath = void 0;
|
||
var cache = {};
|
||
|
||
var Cache = function () {
|
||
function Cache() {
|
||
(0, _classCallCheck3.default)(this, Cache);
|
||
}
|
||
|
||
(0, _createClass3.default)(Cache, null, [{
|
||
key: 'set',
|
||
value: function set(key, value) {
|
||
cache[key] = value;
|
||
if (filePath) fs.writeFileSync(filePath, (0, _stringify2.default)(cache, null, 2) + "\n");
|
||
}
|
||
}, {
|
||
key: 'get',
|
||
value: function get(key) {
|
||
return cache[key];
|
||
}
|
||
}, {
|
||
key: 'loadCache',
|
||
value: function loadCache(cacheFile) {
|
||
// filePath = cacheFile ? cacheFile : defaultFilepath;
|
||
if (cacheFile && fs.existsSync(cacheFile)) {
|
||
filePath = cacheFile;
|
||
logger.debug('Load cache from ' + cacheFile);
|
||
cache = JSON.parse(fs.readFileSync(cacheFile));
|
||
}
|
||
}
|
||
}]);
|
||
return Cache;
|
||
}();
|
||
|
||
module.exports = Cache;
|
||
|
||
/***/ },
|
||
/* 160 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _createClass2 = __webpack_require__(57);
|
||
|
||
var _createClass3 = _interopRequireDefault(_createClass2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var OpTypes = __webpack_require__(161);
|
||
var OrbitDBItem = __webpack_require__(162);
|
||
var Post = __webpack_require__(164);
|
||
|
||
var Operation = function () {
|
||
function Operation() {
|
||
(0, _classCallCheck3.default)(this, Operation);
|
||
}
|
||
|
||
(0, _createClass3.default)(Operation, null, [{
|
||
key: 'create',
|
||
value: function create(ipfs, operation, key, value) {
|
||
var data = {
|
||
operation: operation,
|
||
key: key,
|
||
value: value
|
||
};
|
||
return Post.create(ipfs, Post.Types.OrbitDBItem, data);
|
||
}
|
||
}, {
|
||
key: 'Types',
|
||
get: function get() {
|
||
return OpTypes;
|
||
}
|
||
}]);
|
||
return Operation;
|
||
}();
|
||
|
||
module.exports = Operation;
|
||
|
||
/***/ },
|
||
/* 161 */
|
||
/***/ function(module, exports) {
|
||
|
||
'use strict';
|
||
|
||
var OpTypes = {
|
||
Add: "ADD",
|
||
Put: "PUT",
|
||
Delete: "DELETE",
|
||
Inc: "INC",
|
||
isInsert: function isInsert(op) {
|
||
return op === "ADD" || op === "PUT";
|
||
},
|
||
isDelete: function isDelete(op) {
|
||
return op === "DELETE";
|
||
}
|
||
};
|
||
|
||
module.exports = OpTypes;
|
||
|
||
/***/ },
|
||
/* 162 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _getPrototypeOf = __webpack_require__(119);
|
||
|
||
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _possibleConstructorReturn2 = __webpack_require__(124);
|
||
|
||
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
|
||
|
||
var _inherits2 = __webpack_require__(137);
|
||
|
||
var _inherits3 = _interopRequireDefault(_inherits2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var Post = __webpack_require__(163);
|
||
|
||
var OrbitDBItem = function (_Post) {
|
||
(0, _inherits3.default)(OrbitDBItem, _Post);
|
||
|
||
function OrbitDBItem(operation, key, value) {
|
||
(0, _classCallCheck3.default)(this, OrbitDBItem);
|
||
|
||
var _this = (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(OrbitDBItem).call(this, "orbit-db-op"));
|
||
|
||
_this.op = operation;
|
||
_this.key = key;
|
||
_this.value = value;
|
||
return _this;
|
||
}
|
||
|
||
return OrbitDBItem;
|
||
}(Post);
|
||
|
||
/*
|
||
class HashCacheItem {
|
||
constructor(operation, key, sequenceNumber, targetHash, metaInfo, next) {
|
||
this.op = operation;
|
||
this.seq = sequenceNumber;
|
||
this.key = key;
|
||
this.target = targetHash;
|
||
this.meta = metaInfo;
|
||
this.next = next;
|
||
}
|
||
}
|
||
|
||
class EncryptedHashCacheItem extends HashCacheItem {
|
||
constructor(operation, key, sequenceNumber, targetHash, metaInfo, next, publicKey, privateKey, salt) {
|
||
if(key)
|
||
key = Encryption.encrypt(key, privateKey, publicKey);
|
||
|
||
super(operation, key, sequenceNumber, targetHash, metaInfo, next);
|
||
|
||
try {
|
||
this.pubkey = publicKey;
|
||
this.target = Encryption.encrypt(targetHash, privateKey, publicKey);
|
||
this.meta = Encryption.encrypt(JSON.stringify(metaInfo), privateKey, publicKey);
|
||
this.sig = Encryption.sign(this.target, privateKey, this.seq, salt || "");
|
||
} catch(e) {
|
||
console.log("Failed to create HashCacheItem:", e);
|
||
}
|
||
}
|
||
|
||
static fromEncrypted(encryptedItem, publicKey, privateKey, salt) {
|
||
let data = JSON.parse(encryptedItem.Data);
|
||
|
||
// verify signature
|
||
const verified = Encryption.verify(data.target, data.pubkey, data.sig, data.seq, salt);
|
||
if(!verified) throw "Invalid signature"
|
||
|
||
// link to the next item
|
||
const next = encryptedItem.Links[0] ? encryptedItem.Links[0].Hash : null;
|
||
|
||
// decrypt data structure
|
||
const targetDec = Encryption.decrypt(data.target, privateKey, 'TODO: pubkey');
|
||
const metaDec = Encryption.decrypt(data.meta, privateKey, 'TODO: pubkey');
|
||
data.target = targetDec;
|
||
data.meta = JSON.parse(metaDec);
|
||
|
||
if(data.key)
|
||
data.key = Encryption.decrypt(data.key, privateKey, 'TODO: pubkey');
|
||
|
||
const item = new HashCacheItem(data.op, data.key, data.seq, data.target, data.meta, next, publicKey, privateKey, salt);
|
||
return item;
|
||
}
|
||
}
|
||
*/
|
||
|
||
|
||
module.exports = OrbitDBItem;
|
||
|
||
/***/ },
|
||
/* 163 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
// Base class
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var Post = function Post(type) {
|
||
(0, _classCallCheck3.default)(this, Post);
|
||
|
||
this.type = type;
|
||
};
|
||
|
||
module.exports = Post;
|
||
|
||
/***/ },
|
||
/* 164 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _stringify = __webpack_require__(66);
|
||
|
||
var _stringify2 = _interopRequireDefault(_stringify);
|
||
|
||
var _promise = __webpack_require__(1);
|
||
|
||
var _promise2 = _interopRequireDefault(_promise);
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _createClass2 = __webpack_require__(57);
|
||
|
||
var _createClass3 = _interopRequireDefault(_createClass2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var Buffer = __webpack_require__(154).Buffer;
|
||
var Post = __webpack_require__(163);
|
||
var TextPost = __webpack_require__(165);
|
||
var FilePost = __webpack_require__(166);
|
||
var DirectoryPost = __webpack_require__(167);
|
||
var OrbitDBItem = __webpack_require__(162);
|
||
var MetaInfo = __webpack_require__(168);
|
||
var Poll = __webpack_require__(169);
|
||
|
||
var PostTypes = {
|
||
Message: TextPost,
|
||
Snippet: "snippet",
|
||
File: FilePost,
|
||
Directory: DirectoryPost,
|
||
Link: "link",
|
||
OrbitDBItem: OrbitDBItem,
|
||
Poll: Poll
|
||
};
|
||
|
||
// Factory
|
||
|
||
var Posts = function () {
|
||
function Posts() {
|
||
(0, _classCallCheck3.default)(this, Posts);
|
||
}
|
||
|
||
(0, _createClass3.default)(Posts, null, [{
|
||
key: 'create',
|
||
value: function create(ipfs, type, data) {
|
||
return new _promise2.default(function (resolve, reject) {
|
||
var post = void 0;
|
||
|
||
if (type === PostTypes.Message) {
|
||
post = new PostTypes.Message(data.content);
|
||
} else if (type === PostTypes.File) {
|
||
post = new PostTypes.File(data.name, data.hash, data.size);
|
||
} else if (type == PostTypes.Directory) {
|
||
post = new PostTypes.Directory(data.name, data.hash, data.size);
|
||
} else if (type == PostTypes.OrbitDBItem) {
|
||
post = new PostTypes.OrbitDBItem(data.operation, data.key, data.value);
|
||
} else if (type == PostTypes.Poll) {
|
||
post = new PostTypes.Poll(data.question, data.options);
|
||
}
|
||
|
||
var size = data.size ? data.size : Buffer.byteLength(data, 'utf8');
|
||
post.meta = new MetaInfo(post.type, size, new Date().getTime(), data.from);
|
||
if (post.type) delete post.type;
|
||
ipfs.object.put(new Buffer((0, _stringify2.default)({ Data: (0, _stringify2.default)(post) })), "json").then(function (res) {
|
||
return resolve({ Post: post, Hash: res.Hash });
|
||
}).catch(reject);
|
||
});
|
||
}
|
||
}, {
|
||
key: 'Types',
|
||
get: function get() {
|
||
return PostTypes;
|
||
}
|
||
}]);
|
||
return Posts;
|
||
}();
|
||
|
||
module.exports = Posts;
|
||
|
||
/***/ },
|
||
/* 165 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _getPrototypeOf = __webpack_require__(119);
|
||
|
||
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _possibleConstructorReturn2 = __webpack_require__(124);
|
||
|
||
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
|
||
|
||
var _inherits2 = __webpack_require__(137);
|
||
|
||
var _inherits3 = _interopRequireDefault(_inherits2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var Post = __webpack_require__(163);
|
||
// const Encryption = require('orbit-common/lib/Encryption');
|
||
|
||
// Simplest type of post: a string
|
||
|
||
var TextPost = function (_Post) {
|
||
(0, _inherits3.default)(TextPost, _Post);
|
||
|
||
function TextPost(content) {
|
||
(0, _classCallCheck3.default)(this, TextPost);
|
||
|
||
var _this = (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(TextPost).call(this, "text"));
|
||
|
||
_this.content = content;
|
||
return _this;
|
||
}
|
||
|
||
// encrypt(privkey, pubkey) {
|
||
// this.content = Encryption.encrypt(this.content, privkey, pubkey);
|
||
// }
|
||
|
||
|
||
return TextPost;
|
||
}(Post);
|
||
|
||
module.exports = TextPost;
|
||
|
||
/***/ },
|
||
/* 166 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _getPrototypeOf = __webpack_require__(119);
|
||
|
||
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _possibleConstructorReturn2 = __webpack_require__(124);
|
||
|
||
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
|
||
|
||
var _inherits2 = __webpack_require__(137);
|
||
|
||
var _inherits3 = _interopRequireDefault(_inherits2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var Post = __webpack_require__(163);
|
||
|
||
// A reference to a file
|
||
|
||
var FilePost = function (_Post) {
|
||
(0, _inherits3.default)(FilePost, _Post);
|
||
|
||
function FilePost(name, hash, size) {
|
||
(0, _classCallCheck3.default)(this, FilePost);
|
||
|
||
var _this = (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(FilePost).call(this, "file"));
|
||
|
||
_this.name = name;
|
||
_this.hash = hash;
|
||
_this.size = size;
|
||
return _this;
|
||
}
|
||
|
||
return FilePost;
|
||
}(Post);
|
||
|
||
module.exports = FilePost;
|
||
|
||
/***/ },
|
||
/* 167 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _getPrototypeOf = __webpack_require__(119);
|
||
|
||
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _possibleConstructorReturn2 = __webpack_require__(124);
|
||
|
||
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
|
||
|
||
var _inherits2 = __webpack_require__(137);
|
||
|
||
var _inherits3 = _interopRequireDefault(_inherits2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var Post = __webpack_require__(163);
|
||
|
||
// A reference to a file
|
||
|
||
var DirectoryPost = function (_Post) {
|
||
(0, _inherits3.default)(DirectoryPost, _Post);
|
||
|
||
function DirectoryPost(name, hash, size) {
|
||
(0, _classCallCheck3.default)(this, DirectoryPost);
|
||
|
||
var _this = (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(DirectoryPost).call(this, "directory"));
|
||
|
||
_this.name = name;
|
||
_this.hash = hash;
|
||
_this.size = size;
|
||
return _this;
|
||
}
|
||
|
||
return DirectoryPost;
|
||
}(Post);
|
||
|
||
module.exports = DirectoryPost;
|
||
|
||
/***/ },
|
||
/* 168 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var MetaInfo = function MetaInfo(type, size, ts, from) {
|
||
(0, _classCallCheck3.default)(this, MetaInfo);
|
||
|
||
this.type = type;
|
||
this.size = size;
|
||
this.ts = ts;
|
||
this.from = from || '';
|
||
};
|
||
|
||
module.exports = MetaInfo;
|
||
|
||
/***/ },
|
||
/* 169 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _getPrototypeOf = __webpack_require__(119);
|
||
|
||
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _possibleConstructorReturn2 = __webpack_require__(124);
|
||
|
||
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
|
||
|
||
var _inherits2 = __webpack_require__(137);
|
||
|
||
var _inherits3 = _interopRequireDefault(_inherits2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var Post = __webpack_require__(163);
|
||
|
||
// A poll / vote
|
||
|
||
var Poll = function (_Post) {
|
||
(0, _inherits3.default)(Poll, _Post);
|
||
|
||
function Poll(question, options) {
|
||
(0, _classCallCheck3.default)(this, Poll);
|
||
|
||
var _this = (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(Poll).call(this, "poll"));
|
||
|
||
_this.question = question;
|
||
_this.options = options;
|
||
return _this;
|
||
}
|
||
|
||
return Poll;
|
||
}(Post);
|
||
|
||
module.exports = Poll;
|
||
|
||
/***/ },
|
||
/* 170 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _createClass2 = __webpack_require__(57);
|
||
|
||
var _createClass3 = _interopRequireDefault(_createClass2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var DefaultIndex = function () {
|
||
function DefaultIndex() {
|
||
(0, _classCallCheck3.default)(this, DefaultIndex);
|
||
|
||
this._index = [];
|
||
}
|
||
|
||
(0, _createClass3.default)(DefaultIndex, [{
|
||
key: 'get',
|
||
value: function get() {
|
||
return this._index;
|
||
}
|
||
}, {
|
||
key: 'updateIndex',
|
||
value: function updateIndex(oplog) {
|
||
this._index = oplog.ops;
|
||
}
|
||
}]);
|
||
return DefaultIndex;
|
||
}();
|
||
|
||
module.exports = DefaultIndex;
|
||
|
||
/***/ },
|
||
/* 171 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _createClass2 = __webpack_require__(57);
|
||
|
||
var _createClass3 = _interopRequireDefault(_createClass2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var Counter = __webpack_require__(172);
|
||
|
||
var CounterIndex = function () {
|
||
function CounterIndex() {
|
||
(0, _classCallCheck3.default)(this, CounterIndex);
|
||
|
||
this._index = {};
|
||
}
|
||
|
||
(0, _createClass3.default)(CounterIndex, [{
|
||
key: 'createCounter',
|
||
value: function createCounter(key, id) {
|
||
this._index[key] = new Counter(id);
|
||
}
|
||
}, {
|
||
key: 'get',
|
||
value: function get(key) {
|
||
return this._index[key];
|
||
}
|
||
}, {
|
||
key: 'updateIndex',
|
||
value: function updateIndex(oplog) {
|
||
var counter = this._index[oplog.dbname];
|
||
if (counter) {
|
||
oplog.ops.filter(function (f) {
|
||
return f !== undefined;
|
||
}).map(function (f) {
|
||
return Counter.from(f.value);
|
||
}).forEach(function (f) {
|
||
return counter.merge(f);
|
||
});
|
||
|
||
this._index[oplog.dbname] = counter;
|
||
}
|
||
}
|
||
}]);
|
||
return CounterIndex;
|
||
}();
|
||
|
||
module.exports = CounterIndex;
|
||
|
||
/***/ },
|
||
/* 172 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _keys = __webpack_require__(173);
|
||
|
||
var _keys2 = _interopRequireDefault(_keys);
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _createClass2 = __webpack_require__(57);
|
||
|
||
var _createClass3 = _interopRequireDefault(_createClass2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var isEqual = __webpack_require__(176).isEqual;
|
||
|
||
var GCounter = function () {
|
||
function GCounter(id, payload) {
|
||
(0, _classCallCheck3.default)(this, GCounter);
|
||
|
||
this.id = id;
|
||
this._counters = payload ? payload : {};
|
||
this._counters[this.id] = this._counters[this.id] ? this._counters[this.id] : 0;
|
||
}
|
||
|
||
(0, _createClass3.default)(GCounter, [{
|
||
key: 'increment',
|
||
value: function increment(amount) {
|
||
if (!amount) amount = 1;
|
||
this._counters[this.id] = this._counters[this.id] + amount;
|
||
}
|
||
}, {
|
||
key: 'compare',
|
||
value: function compare(other) {
|
||
if (other.id !== this.id) return false;
|
||
|
||
return isEqual(other._counters, this._counters);
|
||
}
|
||
}, {
|
||
key: 'merge',
|
||
value: function merge(other) {
|
||
var _this = this;
|
||
|
||
(0, _keys2.default)(other._counters).forEach(function (f) {
|
||
_this._counters[f] = Math.max(_this._counters[f] ? _this._counters[f] : 0, other._counters[f]);
|
||
});
|
||
}
|
||
}, {
|
||
key: 'value',
|
||
get: function get() {
|
||
var _this2 = this;
|
||
|
||
return (0, _keys2.default)(this._counters).map(function (f) {
|
||
return _this2._counters[f];
|
||
}).reduce(function (previousValue, currentValue) {
|
||
return previousValue + currentValue;
|
||
}, 0);
|
||
}
|
||
}, {
|
||
key: 'payload',
|
||
get: function get() {
|
||
return { id: this.id, counters: this._counters };
|
||
}
|
||
}], [{
|
||
key: 'from',
|
||
value: function from(payload) {
|
||
return new GCounter(payload.id, payload.counters);
|
||
}
|
||
}]);
|
||
return GCounter;
|
||
}();
|
||
|
||
module.exports = GCounter;
|
||
|
||
/***/ },
|
||
/* 173 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = { "default": __webpack_require__(174), __esModule: true };
|
||
|
||
/***/ },
|
||
/* 174 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
__webpack_require__(175);
|
||
module.exports = __webpack_require__(12).Object.keys;
|
||
|
||
/***/ },
|
||
/* 175 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// 19.1.2.14 Object.keys(O)
|
||
var toObject = __webpack_require__(122);
|
||
|
||
__webpack_require__(123)('keys', function($keys){
|
||
return function keys(it){
|
||
return $keys(toObject(it));
|
||
};
|
||
});
|
||
|
||
/***/ },
|
||
/* 176 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _getOwnPropertyNames = __webpack_require__(177);
|
||
|
||
var _getOwnPropertyNames2 = _interopRequireDefault(_getOwnPropertyNames);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
exports.isEqual = function (a, b) {
|
||
var propsA = (0, _getOwnPropertyNames2.default)(a);
|
||
var propsB = (0, _getOwnPropertyNames2.default)(b);
|
||
|
||
if (propsA.length !== propsB.length) return false;
|
||
|
||
for (var i = 0; i < propsA.length; i++) {
|
||
var prop = propsA[i];
|
||
if (a[prop] !== b[prop]) return false;
|
||
}
|
||
|
||
return true;
|
||
};
|
||
|
||
/***/ },
|
||
/* 177 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = { "default": __webpack_require__(178), __esModule: true };
|
||
|
||
/***/ },
|
||
/* 178 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
var $ = __webpack_require__(17);
|
||
__webpack_require__(179);
|
||
module.exports = function getOwnPropertyNames(it){
|
||
return $.getNames(it);
|
||
};
|
||
|
||
/***/ },
|
||
/* 179 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
// 19.1.2.7 Object.getOwnPropertyNames(O)
|
||
__webpack_require__(123)('getOwnPropertyNames', function(){
|
||
return __webpack_require__(130).get;
|
||
});
|
||
|
||
/***/ },
|
||
/* 180 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _getPrototypeOf = __webpack_require__(119);
|
||
|
||
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _createClass2 = __webpack_require__(57);
|
||
|
||
var _createClass3 = _interopRequireDefault(_createClass2);
|
||
|
||
var _possibleConstructorReturn2 = __webpack_require__(124);
|
||
|
||
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
|
||
|
||
var _get2 = __webpack_require__(133);
|
||
|
||
var _get3 = _interopRequireDefault(_get2);
|
||
|
||
var _inherits2 = __webpack_require__(137);
|
||
|
||
var _inherits3 = _interopRequireDefault(_inherits2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var Store = __webpack_require__(143);
|
||
var KVIndex = __webpack_require__(181);
|
||
var OpTypes = __webpack_require__(160).Types;
|
||
|
||
var KeyValueStore = function (_Store) {
|
||
(0, _inherits3.default)(KeyValueStore, _Store);
|
||
|
||
function KeyValueStore(ipfs, options) {
|
||
(0, _classCallCheck3.default)(this, KeyValueStore);
|
||
|
||
var _this = (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(KeyValueStore).call(this, ipfs, options));
|
||
|
||
_this._index = new KVIndex();
|
||
return _this;
|
||
}
|
||
|
||
(0, _createClass3.default)(KeyValueStore, [{
|
||
key: 'delete',
|
||
value: function _delete(dbname) {
|
||
(0, _get3.default)((0, _getPrototypeOf2.default)(KeyValueStore.prototype), 'delete', this).call(this, dbname);
|
||
this._index = new KVIndex();
|
||
}
|
||
}, {
|
||
key: 'get',
|
||
value: function get(dbname, key) {
|
||
return this._index.get(key);
|
||
}
|
||
}, {
|
||
key: 'set',
|
||
value: function set(dbname, key, data) {
|
||
this.put(dbname, key, data);
|
||
}
|
||
}, {
|
||
key: 'put',
|
||
value: function put(dbname, key, data) {
|
||
return this._addOperation(dbname, OpTypes.Put, key, data);
|
||
}
|
||
}, {
|
||
key: 'del',
|
||
value: function del(dbname, key) {
|
||
return this._addOperation(dbname, OpTypes.Delete, key);
|
||
}
|
||
}]);
|
||
return KeyValueStore;
|
||
}(Store);
|
||
|
||
module.exports = KeyValueStore;
|
||
|
||
/***/ },
|
||
/* 181 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _createClass2 = __webpack_require__(57);
|
||
|
||
var _createClass3 = _interopRequireDefault(_createClass2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var OpTypes = __webpack_require__(160).Types;
|
||
|
||
var KeyValueIndex = function () {
|
||
function KeyValueIndex() {
|
||
(0, _classCallCheck3.default)(this, KeyValueIndex);
|
||
|
||
this._index = {};
|
||
}
|
||
|
||
(0, _createClass3.default)(KeyValueIndex, [{
|
||
key: 'get',
|
||
value: function get(key) {
|
||
return this._index[key];
|
||
}
|
||
}, {
|
||
key: 'updateIndex',
|
||
value: function updateIndex(oplog) {
|
||
var _this = this;
|
||
|
||
var handled = [];
|
||
var _createLWWSet = function _createLWWSet(item) {
|
||
if (handled.indexOf(item.key) === -1) {
|
||
handled.push(item.key);
|
||
if (OpTypes.isInsert(item.op)) return item;
|
||
}
|
||
return null;
|
||
};
|
||
|
||
this._index = {};
|
||
oplog.ops.reverse().map(_createLWWSet).filter(function (f) {
|
||
return f !== null;
|
||
}).forEach(function (f) {
|
||
return _this._index[f.key] = f.value;
|
||
});
|
||
}
|
||
}]);
|
||
return KeyValueIndex;
|
||
}();
|
||
|
||
module.exports = KeyValueIndex;
|
||
|
||
/***/ },
|
||
/* 182 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _defineProperty2 = __webpack_require__(183);
|
||
|
||
var _defineProperty3 = _interopRequireDefault(_defineProperty2);
|
||
|
||
var _iterator2 = __webpack_require__(184);
|
||
|
||
var _iterator3 = _interopRequireDefault(_iterator2);
|
||
|
||
var _getPrototypeOf = __webpack_require__(119);
|
||
|
||
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _createClass2 = __webpack_require__(57);
|
||
|
||
var _createClass3 = _interopRequireDefault(_createClass2);
|
||
|
||
var _possibleConstructorReturn2 = __webpack_require__(124);
|
||
|
||
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
|
||
|
||
var _get2 = __webpack_require__(133);
|
||
|
||
var _get3 = _interopRequireDefault(_get2);
|
||
|
||
var _inherits2 = __webpack_require__(137);
|
||
|
||
var _inherits3 = _interopRequireDefault(_inherits2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var Lazy = __webpack_require__(151);
|
||
var Store = __webpack_require__(143);
|
||
var OpTypes = __webpack_require__(160).Types;
|
||
var EventLogIndex = __webpack_require__(186);
|
||
|
||
var EventStore = function (_Store) {
|
||
(0, _inherits3.default)(EventStore, _Store);
|
||
|
||
function EventStore(ipfs, options) {
|
||
(0, _classCallCheck3.default)(this, EventStore);
|
||
|
||
var _this = (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(EventStore).call(this, ipfs, options));
|
||
|
||
_this._index = new EventLogIndex();
|
||
return _this;
|
||
}
|
||
|
||
(0, _createClass3.default)(EventStore, [{
|
||
key: 'delete',
|
||
value: function _delete(dbname) {
|
||
(0, _get3.default)((0, _getPrototypeOf2.default)(EventStore.prototype), 'delete', this).call(this, dbname);
|
||
this._index = new EventLogIndex();
|
||
}
|
||
}, {
|
||
key: 'add',
|
||
value: function add(dbname, data) {
|
||
return this._addOperation(dbname, OpTypes.Add, null, data);
|
||
}
|
||
}, {
|
||
key: 'remove',
|
||
value: function remove(dbname, hash) {
|
||
return this._addOperation(dbname, OpTypes.Delete, hash);
|
||
}
|
||
}, {
|
||
key: 'iterator',
|
||
value: function iterator(dbname, options) {
|
||
var _iterator;
|
||
|
||
var messages = this._query(dbname, options);
|
||
var currentIndex = 0;
|
||
var iterator = (_iterator = {}, (0, _defineProperty3.default)(_iterator, _iterator3.default, function () {
|
||
return this;
|
||
}), (0, _defineProperty3.default)(_iterator, 'next', function next() {
|
||
var item = { value: null, done: true };
|
||
if (currentIndex < messages.length) {
|
||
item = { value: messages[currentIndex], done: false };
|
||
currentIndex++;
|
||
}
|
||
return item;
|
||
}), (0, _defineProperty3.default)(_iterator, 'collect', function collect() {
|
||
return messages;
|
||
}), _iterator);
|
||
|
||
return iterator;
|
||
}
|
||
}, {
|
||
key: '_query',
|
||
value: function _query(dbname, opts) {
|
||
if (!opts) opts = {};
|
||
|
||
var amount = opts.limit ? opts.limit > -1 ? opts.limit : this._index.get().length : 1; // Return 1 if no limit is provided
|
||
var result = [];
|
||
|
||
if (opts.gt || opts.gte) {
|
||
// Greater than case
|
||
result = this._read(this._index.get().reverse(), opts.gt ? opts.gt : opts.gte, amount, opts.gte ? true : false);
|
||
} else {
|
||
// Lower than and lastN case, search latest first by reversing the sequence
|
||
result = this._read(this._index.get(), opts.lt ? opts.lt : opts.lte, amount, opts.lte || !opts.lt).reverse();
|
||
}
|
||
|
||
if (opts.reverse) result.reverse();
|
||
|
||
return result.toArray();
|
||
}
|
||
}, {
|
||
key: '_read',
|
||
value: function _read(ops, key, amount, inclusive) {
|
||
return Lazy(ops).skipWhile(function (f) {
|
||
return key && f.key !== key;
|
||
}).drop(inclusive ? 0 : 1).take(amount);
|
||
}
|
||
}]);
|
||
return EventStore;
|
||
}(Store);
|
||
|
||
module.exports = EventStore;
|
||
|
||
/***/ },
|
||
/* 183 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
"use strict";
|
||
|
||
exports.__esModule = true;
|
||
|
||
var _defineProperty = __webpack_require__(58);
|
||
|
||
var _defineProperty2 = _interopRequireDefault(_defineProperty);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
exports.default = function (obj, key, value) {
|
||
if (key in obj) {
|
||
(0, _defineProperty2.default)(obj, key, {
|
||
value: value,
|
||
enumerable: true,
|
||
configurable: true,
|
||
writable: true
|
||
});
|
||
} else {
|
||
obj[key] = value;
|
||
}
|
||
|
||
return obj;
|
||
};
|
||
|
||
/***/ },
|
||
/* 184 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
module.exports = { "default": __webpack_require__(185), __esModule: true };
|
||
|
||
/***/ },
|
||
/* 185 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
__webpack_require__(4);
|
||
__webpack_require__(28);
|
||
module.exports = __webpack_require__(25)('iterator');
|
||
|
||
/***/ },
|
||
/* 186 */
|
||
/***/ function(module, exports, __webpack_require__) {
|
||
|
||
'use strict';
|
||
|
||
var _classCallCheck2 = __webpack_require__(56);
|
||
|
||
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
||
|
||
var _createClass2 = __webpack_require__(57);
|
||
|
||
var _createClass3 = _interopRequireDefault(_createClass2);
|
||
|
||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
||
var OpTypes = __webpack_require__(160).Types;
|
||
|
||
var EventLogIndex = function () {
|
||
function EventLogIndex() {
|
||
(0, _classCallCheck3.default)(this, EventLogIndex);
|
||
|
||
this._index = [];
|
||
}
|
||
|
||
(0, _createClass3.default)(EventLogIndex, [{
|
||
key: 'get',
|
||
value: function get() {
|
||
return this._index;
|
||
}
|
||
}, {
|
||
key: 'updateIndex',
|
||
value: function updateIndex(oplog) {
|
||
var handled = [];
|
||
var _createLWWSet = function _createLWWSet(item) {
|
||
if (handled.indexOf(item.key) === -1) {
|
||
handled.push(item.key);
|
||
if (OpTypes.isInsert(item.op)) return item;
|
||
}
|
||
return null;
|
||
};
|
||
|
||
this._index = oplog.ops.reverse().map(_createLWWSet).filter(function (f) {
|
||
return f !== null;
|
||
});
|
||
}
|
||
}]);
|
||
return EventLogIndex;
|
||
}();
|
||
|
||
module.exports = EventLogIndex;
|
||
|
||
/***/ }
|
||
/******/ ]); |