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 _assign = __webpack_require__(69);
var _assign2 = _interopRequireDefault(_assign);
var _classCallCheck2 = __webpack_require__(74);
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = __webpack_require__(75);
var _createClass3 = _interopRequireDefault(_createClass2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var EventEmitter = __webpack_require__(79).EventEmitter;
var logger = __webpack_require__(80).create("orbit-db.Client");
var EventStore = __webpack_require__(87);
var FeedStore = __webpack_require__(103);
var KeyValueStore = __webpack_require__(105);
var CounterStore = __webpack_require__(107);
var PubSub = __webpack_require__(111);
var OrbitDB = function () {
function OrbitDB(ipfs) {
(0, _classCallCheck3.default)(this, OrbitDB);
this._ipfs = ipfs;
this._pubsub = null;
this.user = null;
this.network = null;
this.events = new EventEmitter();
this.stores = {};
}
/* Databases */
(0, _createClass3.default)(OrbitDB, [{
key: 'feed',
value: function feed(dbname, options) {
return this._createStore(FeedStore, dbname, options);
}
}, {
key: 'eventlog',
value: function eventlog(dbname, options) {
return this._createStore(EventStore, dbname, options);
}
}, {
key: 'kvstore',
value: function kvstore(dbname, options) {
return this._createStore(KeyValueStore, dbname, options);
}
}, {
key: 'counter',
value: function counter(dbname, options) {
return this._createStore(CounterStore, dbname, options);
}
}, {
key: 'disconnect',
value: function disconnect() {
this._pubsub.disconnect();
this.stores = {};
this.user = null;
this.network = null;
}
}, {
key: '_createStore',
value: function _createStore(Store, dbname, options) {
var _this = this;
if (!options) options = {};
if (options.subscribe === undefined) (0, _assign2.default)(options, { subscribe: true });
var store = new Store(this._ipfs, this.user.username, dbname, options);
return this._subscribe(store, dbname, options.subscribe).then(function () {
return _this.stores[dbname] = store;
}).then(function () {
return store;
});
}
}, {
key: '_subscribe',
value: function _subscribe(store, dbname, subscribe, callback) {
var _this2 = this;
if (subscribe === undefined) subscribe = true;
return store.use(this.user.username).then(function (events) {
events.on('readable', _this2._onSync.bind(_this2));
events.on('data', _this2._onWrite.bind(_this2));
events.on('load', _this2._onLoad.bind(_this2));
events.on('close', _this2._onClose.bind(_this2));
if (subscribe) _this2._pubsub.subscribe(dbname, '', _this2._onMessage.bind(_this2));
return;
});
}
}, {
key: '_onMessage',
value: function _onMessage(dbname, message) {
var store = this.stores[dbname];
store.sync(message).catch(function (e) {
return logger.error(e.stack);
});
}
}, {
key: '_onWrite',
value: function _onWrite(dbname, hash) {
if (!hash) throw new Error("Hash can't be null!");
this._pubsub.publish(dbname, hash);
this.events.emit('data', dbname, hash);
}
}, {
key: '_onSync',
value: function _onSync(dbname, hash) {
this.events.emit('readable', dbname, hash);
}
}, {
key: '_onLoad',
value: function _onLoad(dbname, hash) {
this.events.emit('load', dbname, hash);
}
}, {
key: '_onClose',
value: function _onClose(dbname) {
this._pubsub.unsubscribe(dbname);
delete this.stores[dbname];
this.events.emit('closed', dbname);
}
}, {
key: '_connect',
value: function _connect(hash, username, password, allowOffline) {
var _this3 = this;
if (allowOffline === undefined) allowOffline = false;
var readNetworkInfo = function readNetworkInfo(hash) {
return new _promise2.default(function (resolve, reject) {
_this3._ipfs.cat(hash).then(function (res) {
var buf = '';
res.on('error', function (err) {
return reject(err);
}).on('data', function (data) {
return buf += data;
}).on('end', function () {
return resolve(buf);
});
});
});
};
var host = void 0,
port = void 0,
name = void 0;
return readNetworkInfo(hash).then(function (network) {
return JSON.parse(network);
}).then(function (network) {
_this3.network = network;
name = network.name;
host = network.publishers[0].split(":")[0];
port = network.publishers[0].split(":")[1];
}).then(function () {
_this3._pubsub = new PubSub();
return _this3._pubsub.connect(host, port, username, password);
}).then(function () {
logger.debug('Connected to Pubsub at \'' + host + ':' + port + '\'');
_this3.user = { username: username, id: username }; // TODO: user id from ipfs hash
return;
}).catch(function (e) {
logger.warn("Couldn't connect to Pubsub: " + e.message);
if (!allowOffline) {
logger.debug("'allowOffline' set to false, terminating");
_this3._pubsub.disconnect();
throw e;
}
_this3.user = { username: username, id: username }; // TODO: user id from ipfs hash
return;
});
}
}]);
return OrbitDB;
}();
var OrbitClientFactory = function () {
function OrbitClientFactory() {
(0, _classCallCheck3.default)(this, OrbitClientFactory);
}
(0, _createClass3.default)(OrbitClientFactory, null, [{
key: 'connect',
value: function connect(network, username, password, ipfs, options) {
if (!options) options = { allowOffline: false };
if (!ipfs) {
logger.error("IPFS instance not provided");
throw new Error("IPFS instance not provided");
}
var client = new OrbitDB(ipfs);
return client._connect(network, username, password, options.allowOffline).then(function () {
return client;
});
}
}]);
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__(48);
__webpack_require__(52);
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__(25)
, hide = __webpack_require__(15)
, has = __webpack_require__(26)
, Iterators = __webpack_require__(27)
, $iterCreate = __webpack_require__(28)
, setToStringTag = __webpack_require__(44)
, getPrototypeOf = __webpack_require__(46)
, ITERATOR = __webpack_require__(45)('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)
, $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined
, $anyNative = NAME == 'Array' ? proto.entries || $native : $native
, methods, key, IteratorPrototype;
// Fix native
if($anyNative){
IteratorPrototype = getPrototypeOf($anyNative.call(new Base));
if(IteratorPrototype !== Object.prototype){
// Set @@toStringTag to native iterators
setToStringTag(IteratorPrototype, TAG, true);
// fix for some old engines
if(!LIBRARY && !has(IteratorPrototype, ITERATOR))hide(IteratorPrototype, ITERATOR, returnThis);
}
}
// fix Array#{values, @@iterator}.name in V8 / FF
if(DEF_VALUES && $native && $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: $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)
, hide = __webpack_require__(15)
, 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] = {})
, expProto = exports[PROTOTYPE]
, 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 && target[key] !== undefined;
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(a, b, c){
if(this instanceof C){
switch(arguments.length){
case 0: return new C;
case 1: return new C(a);
case 2: return new C(a, b);
} return new C(a, b, c);
} return C.apply(this, arguments);
};
F[PROTOTYPE] = C[PROTOTYPE];
return F;
// make static versions for prototype methods
})(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out;
// export proto methods to core.%CONSTRUCTOR%.methods.%NAME%
if(IS_PROTO){
(exports.virtual || (exports.virtual = {}))[key] = out;
// export proto methods to core.%CONSTRUCTOR%.prototype.%NAME%
if(type & $export.R && expProto && !expProto[key])hide(expProto, 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
$export.U = 64; // safe
$export.R = 128; // real proto method for `library`
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: '2.4.0'};
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__) {
var dP = __webpack_require__(16)
, createDesc = __webpack_require__(24);
module.exports = __webpack_require__(20) ? function(object, key, value){
return dP.f(object, key, createDesc(1, value));
} : function(object, key, value){
object[key] = value;
return object;
};
/***/ },
/* 16 */
/***/ function(module, exports, __webpack_require__) {
var anObject = __webpack_require__(17)
, IE8_DOM_DEFINE = __webpack_require__(19)
, toPrimitive = __webpack_require__(23)
, dP = Object.defineProperty;
exports.f = __webpack_require__(20) ? Object.defineProperty : function defineProperty(O, P, Attributes){
anObject(O);
P = toPrimitive(P, true);
anObject(Attributes);
if(IE8_DOM_DEFINE)try {
return dP(O, P, Attributes);
} catch(e){ /* empty */ }
if('get' in Attributes || 'set' in Attributes)throw TypeError('Accessors not supported!');
if('value' in Attributes)O[P] = Attributes.value;
return O;
};
/***/ },
/* 17 */
/***/ function(module, exports, __webpack_require__) {
var isObject = __webpack_require__(18);
module.exports = function(it){
if(!isObject(it))throw TypeError(it + ' is not an object!');
return it;
};
/***/ },
/* 18 */
/***/ function(module, exports) {
module.exports = function(it){
return typeof it === 'object' ? it !== null : typeof it === 'function';
};
/***/ },
/* 19 */
/***/ function(module, exports, __webpack_require__) {
module.exports = !__webpack_require__(20) && !__webpack_require__(21)(function(){
return Object.defineProperty(__webpack_require__(22)('div'), 'a', {get: function(){ return 7; }}).a != 7;
});
/***/ },
/* 20 */
/***/ function(module, exports, __webpack_require__) {
// Thank's IE8 for his funny defineProperty
module.exports = !__webpack_require__(21)(function(){
return Object.defineProperty({}, 'a', {get: function(){ return 7; }}).a != 7;
});
/***/ },
/* 21 */
/***/ function(module, exports) {
module.exports = function(exec){
try {
return !!exec();
} catch(e){
return true;
}
};
/***/ },
/* 22 */
/***/ function(module, exports, __webpack_require__) {
var isObject = __webpack_require__(18)
, 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) : {};
};
/***/ },
/* 23 */
/***/ function(module, exports, __webpack_require__) {
// 7.1.1 ToPrimitive(input [, PreferredType])
var isObject = __webpack_require__(18);
// instead of the ES6 spec version, we didn't implement @@toPrimitive case
// and the second argument - flag - preferred type is a string
module.exports = function(it, S){
if(!isObject(it))return it;
var fn, val;
if(S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val;
if(typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it)))return val;
if(!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val;
throw TypeError("Can't convert object to primitive value");
};
/***/ },
/* 24 */
/***/ function(module, exports) {
module.exports = function(bitmap, value){
return {
enumerable : !(bitmap & 1),
configurable: !(bitmap & 2),
writable : !(bitmap & 4),
value : value
};
};
/***/ },
/* 25 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(15);
/***/ },
/* 26 */
/***/ function(module, exports) {
var hasOwnProperty = {}.hasOwnProperty;
module.exports = function(it, key){
return hasOwnProperty.call(it, key);
};
/***/ },
/* 27 */
/***/ function(module, exports) {
module.exports = {};
/***/ },
/* 28 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
var create = __webpack_require__(29)
, descriptor = __webpack_require__(24)
, setToStringTag = __webpack_require__(44)
, IteratorPrototype = {};
// 25.1.2.1.1 %IteratorPrototype%[@@iterator]()
__webpack_require__(15)(IteratorPrototype, __webpack_require__(45)('iterator'), function(){ return this; });
module.exports = function(Constructor, NAME, next){
Constructor.prototype = create(IteratorPrototype, {next: descriptor(1, next)});
setToStringTag(Constructor, NAME + ' Iterator');
};
/***/ },
/* 29 */
/***/ function(module, exports, __webpack_require__) {
// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])
var anObject = __webpack_require__(17)
, dPs = __webpack_require__(30)
, enumBugKeys = __webpack_require__(42)
, IE_PROTO = __webpack_require__(39)('IE_PROTO')
, Empty = function(){ /* empty */ }
, PROTOTYPE = 'prototype';
// Create object with fake `null` prototype: use iframe Object with cleared prototype
var createDict = function(){
// Thrash, waste and sodomy: IE GC bug
var iframe = __webpack_require__(22)('iframe')
, i = enumBugKeys.length
, gt = '>'
, iframeDocument;
iframe.style.display = 'none';
__webpack_require__(43).appendChild(iframe);
iframe.src = 'javascript:'; // eslint-disable-line no-script-url
// createDict = iframe.contentWindow.Object;
// html.removeChild(iframe);
iframeDocument = iframe.contentWindow.document;
iframeDocument.open();
iframeDocument.write(' i)dP.f(O, P = keys[i++], Properties[P]);
return O;
};
/***/ },
/* 31 */
/***/ function(module, exports, __webpack_require__) {
// 19.1.2.14 / 15.2.3.14 Object.keys(O)
var $keys = __webpack_require__(32)
, enumBugKeys = __webpack_require__(42);
module.exports = Object.keys || function keys(O){
return $keys(O, enumBugKeys);
};
/***/ },
/* 32 */
/***/ function(module, exports, __webpack_require__) {
var has = __webpack_require__(26)
, toIObject = __webpack_require__(33)
, arrayIndexOf = __webpack_require__(36)(false)
, IE_PROTO = __webpack_require__(39)('IE_PROTO');
module.exports = function(object, names){
var O = toIObject(object)
, i = 0
, result = []
, key;
for(key in O)if(key != IE_PROTO)has(O, key) && result.push(key);
// Don't enum bug & hidden keys
while(names.length > i)if(has(O, key = names[i++])){
~arrayIndexOf(result, key) || result.push(key);
}
return result;
};
/***/ },
/* 33 */
/***/ function(module, exports, __webpack_require__) {
// to indexed object, toObject with fallback for non-array-like ES3 strings
var IObject = __webpack_require__(34)
, defined = __webpack_require__(7);
module.exports = function(it){
return IObject(defined(it));
};
/***/ },
/* 34 */
/***/ function(module, exports, __webpack_require__) {
// fallback for non-array-like ES3 and non-enumerable old V8 strings
var cof = __webpack_require__(35);
module.exports = Object('z').propertyIsEnumerable(0) ? Object : function(it){
return cof(it) == 'String' ? it.split('') : Object(it);
};
/***/ },
/* 35 */
/***/ function(module, exports) {
var toString = {}.toString;
module.exports = function(it){
return toString.call(it).slice(8, -1);
};
/***/ },
/* 36 */
/***/ function(module, exports, __webpack_require__) {
// false -> Array#indexOf
// true -> Array#includes
var toIObject = __webpack_require__(33)
, toLength = __webpack_require__(37)
, toIndex = __webpack_require__(38);
module.exports = function(IS_INCLUDES){
return function($this, el, fromIndex){
var O = toIObject($this)
, length = toLength(O.length)
, index = toIndex(fromIndex, length)
, value;
// Array#includes uses SameValueZero equality algorithm
if(IS_INCLUDES && el != el)while(length > index){
value = O[index++];
if(value != value)return true;
// Array#toIndex ignores holes, Array#includes - not
} else for(;length > index; index++)if(IS_INCLUDES || index in O){
if(O[index] === el)return IS_INCLUDES || index || 0;
} return !IS_INCLUDES && -1;
};
};
/***/ },
/* 37 */
/***/ 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
};
/***/ },
/* 38 */
/***/ function(module, exports, __webpack_require__) {
var toInteger = __webpack_require__(6)
, max = Math.max
, min = Math.min;
module.exports = function(index, length){
index = toInteger(index);
return index < 0 ? max(index + length, 0) : min(index, length);
};
/***/ },
/* 39 */
/***/ function(module, exports, __webpack_require__) {
var shared = __webpack_require__(40)('keys')
, uid = __webpack_require__(41);
module.exports = function(key){
return shared[key] || (shared[key] = uid(key));
};
/***/ },
/* 40 */
/***/ 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] = {});
};
/***/ },
/* 41 */
/***/ function(module, exports) {
var id = 0
, px = Math.random();
module.exports = function(key){
return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36));
};
/***/ },
/* 42 */
/***/ function(module, exports) {
// IE 8- don't enum bug keys
module.exports = (
'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf'
).split(',');
/***/ },
/* 43 */
/***/ function(module, exports, __webpack_require__) {
module.exports = __webpack_require__(11).document && document.documentElement;
/***/ },
/* 44 */
/***/ function(module, exports, __webpack_require__) {
var def = __webpack_require__(16).f
, has = __webpack_require__(26)
, TAG = __webpack_require__(45)('toStringTag');
module.exports = function(it, tag, stat){
if(it && !has(it = stat ? it : it.prototype, TAG))def(it, TAG, {configurable: true, value: tag});
};
/***/ },
/* 45 */
/***/ function(module, exports, __webpack_require__) {
var store = __webpack_require__(40)('wks')
, uid = __webpack_require__(41)
, Symbol = __webpack_require__(11).Symbol
, USE_SYMBOL = typeof Symbol == 'function';
var $exports = module.exports = function(name){
return store[name] || (store[name] =
USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name));
};
$exports.store = store;
/***/ },
/* 46 */
/***/ function(module, exports, __webpack_require__) {
// 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O)
var has = __webpack_require__(26)
, toObject = __webpack_require__(47)
, IE_PROTO = __webpack_require__(39)('IE_PROTO')
, ObjectProto = Object.prototype;
module.exports = Object.getPrototypeOf || function(O){
O = toObject(O);
if(has(O, IE_PROTO))return O[IE_PROTO];
if(typeof O.constructor == 'function' && O instanceof O.constructor){
return O.constructor.prototype;
} return O instanceof Object ? ObjectProto : null;
};
/***/ },
/* 47 */
/***/ function(module, exports, __webpack_require__) {
// 7.1.13 ToObject(argument)
var defined = __webpack_require__(7);
module.exports = function(it){
return Object(defined(it));
};
/***/ },
/* 48 */
/***/ function(module, exports, __webpack_require__) {
__webpack_require__(49);
var global = __webpack_require__(11)
, hide = __webpack_require__(15)
, Iterators = __webpack_require__(27)
, TO_STRING_TAG = __webpack_require__(45)('toStringTag');
for(var collections = ['NodeList', 'DOMTokenList', 'MediaList', 'StyleSheetList', 'CSSRuleList'], i = 0; i < 5; i++){
var NAME = collections[i]
, Collection = global[NAME]
, proto = Collection && Collection.prototype;
if(proto && !proto[TO_STRING_TAG])hide(proto, TO_STRING_TAG, NAME);
Iterators[NAME] = Iterators.Array;
}
/***/ },
/* 49 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
var addToUnscopables = __webpack_require__(50)
, step = __webpack_require__(51)
, Iterators = __webpack_require__(27)
, toIObject = __webpack_require__(33);
// 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');
/***/ },
/* 50 */
/***/ function(module, exports) {
module.exports = function(){ /* empty */ };
/***/ },
/* 51 */
/***/ function(module, exports) {
module.exports = function(done, value){
return {value: value, done: !!done};
};
/***/ },
/* 52 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
var LIBRARY = __webpack_require__(9)
, global = __webpack_require__(11)
, ctx = __webpack_require__(13)
, classof = __webpack_require__(53)
, $export = __webpack_require__(10)
, isObject = __webpack_require__(18)
, anObject = __webpack_require__(17)
, aFunction = __webpack_require__(14)
, anInstance = __webpack_require__(54)
, forOf = __webpack_require__(55)
, setProto = __webpack_require__(59).set
, speciesConstructor = __webpack_require__(62)
, task = __webpack_require__(63).set
, microtask = __webpack_require__(65)()
, PROMISE = 'Promise'
, TypeError = global.TypeError
, process = global.process
, $Promise = global[PROMISE]
, process = global.process
, isNode = classof(process) == 'process'
, empty = function(){ /* empty */ }
, Internal, GenericPromiseCapability, Wrapper;
var USE_NATIVE = !!function(){
try {
// correct subclassing with @@species support
var promise = $Promise.resolve(1)
, FakePromise = (promise.constructor = {})[__webpack_require__(45)('species')] = function(exec){ exec(empty, empty); };
// unhandled rejections tracking support, NodeJS Promise without it fails @@species test
return (isNode || typeof PromiseRejectionEvent == 'function') && promise.then(empty) instanceof FakePromise;
} catch(e){ /* empty */ }
}();
// helpers
var sameConstructor = function(a, b){
// with library wrapper special case
return a === b || a === $Promise && b === Wrapper;
};
var isThenable = function(it){
var then;
return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
};
var newPromiseCapability = function(C){
return sameConstructor($Promise, C)
? new PromiseCapability(C)
: new GenericPromiseCapability(C);
};
var PromiseCapability = GenericPromiseCapability = 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(promise, isReject){
if(promise._n)return;
promise._n = true;
var chain = promise._c;
microtask(function(){
var value = promise._v
, ok = promise._s == 1
, i = 0;
var run = function(reaction){
var handler = ok ? reaction.ok : reaction.fail
, resolve = reaction.resolve
, reject = reaction.reject
, domain = reaction.domain
, result, then;
try {
if(handler){
if(!ok){
if(promise._h == 2)onHandleUnhandled(promise);
promise._h = 1;
}
if(handler === true)result = value;
else {
if(domain)domain.enter();
result = handler(value);
if(domain)domain.exit();
}
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
promise._c = [];
promise._n = false;
if(isReject && !promise._h)onUnhandled(promise);
});
};
var onUnhandled = function(promise){
task.call(global, function(){
var value = promise._v
, abrupt, handler, console;
if(isUnhandled(promise)){
abrupt = perform(function(){
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);
}
});
// Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
promise._h = isNode || isUnhandled(promise) ? 2 : 1;
} promise._a = undefined;
if(abrupt)throw abrupt.error;
});
};
var isUnhandled = function(promise){
if(promise._h == 1)return false;
var chain = promise._a || promise._c
, i = 0
, reaction;
while(chain.length > i){
reaction = chain[i++];
if(reaction.fail || !isUnhandled(reaction.promise))return false;
} return true;
};
var onHandleUnhandled = function(promise){
task.call(global, function(){
var handler;
if(isNode){
process.emit('rejectionHandled', promise);
} else if(handler = global.onrejectionhandled){
handler({promise: promise, reason: promise._v});
}
});
};
var $reject = function(value){
var promise = this;
if(promise._d)return;
promise._d = true;
promise = promise._w || promise; // unwrap
promise._v = value;
promise._s = 2;
if(!promise._a)promise._a = promise._c.slice();
notify(promise, true);
};
var $resolve = function(value){
var promise = this
, then;
if(promise._d)return;
promise._d = true;
promise = promise._w || promise; // unwrap
try {
if(promise === value)throw TypeError("Promise can't be resolved itself");
if(then = isThenable(value)){
microtask(function(){
var wrapper = {_w: promise, _d: false}; // wrap
try {
then.call(value, ctx($resolve, wrapper, 1), ctx($reject, wrapper, 1));
} catch(e){
$reject.call(wrapper, e);
}
});
} else {
promise._v = value;
promise._s = 1;
notify(promise, false);
}
} catch(e){
$reject.call({_w: promise, _d: false}, e); // wrap
}
};
// constructor polyfill
if(!USE_NATIVE){
// 25.4.3.1 Promise(executor)
$Promise = function Promise(executor){
anInstance(this, $Promise, PROMISE, '_h');
aFunction(executor);
Internal.call(this);
try {
executor(ctx($resolve, this, 1), ctx($reject, this, 1));
} catch(err){
$reject.call(this, err);
}
};
Internal = function Promise(executor){
this._c = []; // <- awaiting reactions
this._a = undefined; // <- checked in isUnhandled reactions
this._s = 0; // <- state
this._d = false; // <- done
this._v = undefined; // <- value
this._h = 0; // <- rejection state, 0 - default, 1 - handled, 2 - unhandled
this._n = false; // <- notify
};
Internal.prototype = __webpack_require__(66)($Promise.prototype, {
// 25.4.5.3 Promise.prototype.then(onFulfilled, onRejected)
then: function then(onFulfilled, onRejected){
var reaction = newPromiseCapability(speciesConstructor(this, $Promise));
reaction.ok = typeof onFulfilled == 'function' ? onFulfilled : true;
reaction.fail = typeof onRejected == 'function' && onRejected;
reaction.domain = isNode ? process.domain : undefined;
this._c.push(reaction);
if(this._a)this._a.push(reaction);
if(this._s)notify(this, false);
return reaction.promise;
},
// 25.4.5.1 Promise.prototype.catch(onRejected)
'catch': function(onRejected){
return this.then(undefined, onRejected);
}
});
PromiseCapability = function(){
var promise = new Internal;
this.promise = promise;
this.resolve = ctx($resolve, promise, 1);
this.reject = ctx($reject, promise, 1);
};
}
$export($export.G + $export.W + $export.F * !USE_NATIVE, {Promise: $Promise});
__webpack_require__(44)($Promise, PROMISE);
__webpack_require__(67)(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 = newPromiseCapability(this)
, $$reject = capability.reject;
$$reject(r);
return capability.promise;
}
});
$export($export.S + $export.F * (LIBRARY || !USE_NATIVE), 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 $Promise && sameConstructor(x.constructor, this))return x;
var capability = newPromiseCapability(this)
, $$resolve = capability.resolve;
$$resolve(x);
return capability.promise;
}
});
$export($export.S + $export.F * !(USE_NATIVE && __webpack_require__(68)(function(iter){
$Promise.all(iter)['catch'](empty);
})), PROMISE, {
// 25.4.4.1 Promise.all(iterable)
all: function all(iterable){
var C = this
, capability = newPromiseCapability(C)
, resolve = capability.resolve
, reject = capability.reject;
var abrupt = perform(function(){
var values = []
, index = 0
, remaining = 1;
forOf(iterable, false, function(promise){
var $index = index++
, alreadyCalled = false;
values.push(undefined);
remaining++;
C.resolve(promise).then(function(value){
if(alreadyCalled)return;
alreadyCalled = true;
values[$index] = value;
--remaining || resolve(values);
}, reject);
});
--remaining || resolve(values);
});
if(abrupt)reject(abrupt.error);
return capability.promise;
},
// 25.4.4.4 Promise.race(iterable)
race: function race(iterable){
var C = this
, capability = newPromiseCapability(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;
}
});
/***/ },
/* 53 */
/***/ function(module, exports, __webpack_require__) {
// getting tag from 19.1.3.6 Object.prototype.toString()
var cof = __webpack_require__(35)
, TAG = __webpack_require__(45)('toStringTag')
// ES3 wrong here
, ARG = cof(function(){ return arguments; }()) == 'Arguments';
// fallback for IE11 Script Access Denied error
var tryGet = function(it, key){
try {
return it[key];
} catch(e){ /* empty */ }
};
module.exports = function(it){
var O, T, B;
return it === undefined ? 'Undefined' : it === null ? 'Null'
// @@toStringTag case
: typeof (T = tryGet(O = Object(it), TAG)) == 'string' ? T
// builtinTag case
: ARG ? cof(O)
// ES3 arguments fallback
: (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B;
};
/***/ },
/* 54 */
/***/ function(module, exports) {
module.exports = function(it, Constructor, name, forbiddenField){
if(!(it instanceof Constructor) || (forbiddenField !== undefined && forbiddenField in it)){
throw TypeError(name + ': incorrect invocation!');
} return it;
};
/***/ },
/* 55 */
/***/ function(module, exports, __webpack_require__) {
var ctx = __webpack_require__(13)
, call = __webpack_require__(56)
, isArrayIter = __webpack_require__(57)
, anObject = __webpack_require__(17)
, toLength = __webpack_require__(37)
, getIterFn = __webpack_require__(58)
, BREAK = {}
, RETURN = {};
var exports = module.exports = function(iterable, entries, fn, that, ITERATOR){
var iterFn = ITERATOR ? function(){ return iterable; } : getIterFn(iterable)
, f = ctx(fn, that, entries ? 2 : 1)
, index = 0
, length, step, iterator, result;
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++){
result = entries ? f(anObject(step = iterable[index])[0], step[1]) : f(iterable[index]);
if(result === BREAK || result === RETURN)return result;
} else for(iterator = iterFn.call(iterable); !(step = iterator.next()).done; ){
result = call(iterator, f, step.value, entries);
if(result === BREAK || result === RETURN)return result;
}
};
exports.BREAK = BREAK;
exports.RETURN = RETURN;
/***/ },
/* 56 */
/***/ function(module, exports, __webpack_require__) {
// call something on iterator step with safe closing on error
var anObject = __webpack_require__(17);
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;
}
};
/***/ },
/* 57 */
/***/ function(module, exports, __webpack_require__) {
// check on default Array iterator
var Iterators = __webpack_require__(27)
, ITERATOR = __webpack_require__(45)('iterator')
, ArrayProto = Array.prototype;
module.exports = function(it){
return it !== undefined && (Iterators.Array === it || ArrayProto[ITERATOR] === it);
};
/***/ },
/* 58 */
/***/ function(module, exports, __webpack_require__) {
var classof = __webpack_require__(53)
, ITERATOR = __webpack_require__(45)('iterator')
, Iterators = __webpack_require__(27);
module.exports = __webpack_require__(12).getIteratorMethod = function(it){
if(it != undefined)return it[ITERATOR]
|| it['@@iterator']
|| Iterators[classof(it)];
};
/***/ },
/* 59 */
/***/ function(module, exports, __webpack_require__) {
// Works with __proto__ only. Old v8 can't work with null proto objects.
/* eslint-disable no-proto */
var isObject = __webpack_require__(18)
, anObject = __webpack_require__(17);
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, __webpack_require__(60).f(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
};
/***/ },
/* 60 */
/***/ function(module, exports, __webpack_require__) {
var pIE = __webpack_require__(61)
, createDesc = __webpack_require__(24)
, toIObject = __webpack_require__(33)
, toPrimitive = __webpack_require__(23)
, has = __webpack_require__(26)
, IE8_DOM_DEFINE = __webpack_require__(19)
, gOPD = Object.getOwnPropertyDescriptor;
exports.f = __webpack_require__(20) ? gOPD : function getOwnPropertyDescriptor(O, P){
O = toIObject(O);
P = toPrimitive(P, true);
if(IE8_DOM_DEFINE)try {
return gOPD(O, P);
} catch(e){ /* empty */ }
if(has(O, P))return createDesc(!pIE.f.call(O, P), O[P]);
};
/***/ },
/* 61 */
/***/ function(module, exports) {
exports.f = {}.propertyIsEnumerable;
/***/ },
/* 62 */
/***/ function(module, exports, __webpack_require__) {
// 7.3.20 SpeciesConstructor(O, defaultConstructor)
var anObject = __webpack_require__(17)
, aFunction = __webpack_require__(14)
, SPECIES = __webpack_require__(45)('species');
module.exports = function(O, D){
var C = anObject(O).constructor, S;
return C === undefined || (S = anObject(C)[SPECIES]) == undefined ? D : aFunction(S);
};
/***/ },
/* 63 */
/***/ function(module, exports, __webpack_require__) {
var ctx = __webpack_require__(13)
, invoke = __webpack_require__(64)
, html = __webpack_require__(43)
, cel = __webpack_require__(22)
, 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 listener = 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__(35)(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 = listener;
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', listener, 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
};
/***/ },
/* 64 */
/***/ 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);
};
/***/ },
/* 65 */
/***/ function(module, exports, __webpack_require__) {
var global = __webpack_require__(11)
, macrotask = __webpack_require__(63).set
, Observer = global.MutationObserver || global.WebKitMutationObserver
, process = global.process
, Promise = global.Promise
, isNode = __webpack_require__(35)(process) == 'process';
module.exports = function(){
var head, last, notify;
var flush = function(){
var parent, fn;
if(isNode && (parent = process.domain))parent.exit();
while(head){
fn = head.fn;
head = head.next;
try {
fn();
} catch(e){
if(head)notify();
else last = undefined;
throw e;
}
} last = undefined;
if(parent)parent.enter();
};
// Node.js
if(isNode){
notify = function(){
process.nextTick(flush);
};
// browsers with MutationObserver
} else if(Observer){
var toggle = true
, 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){
var promise = Promise.resolve();
notify = function(){
promise.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);
};
}
return function(fn){
var task = {fn: fn, next: undefined};
if(last)last.next = task;
if(!head){
head = task;
notify();
} last = task;
};
};
/***/ },
/* 66 */
/***/ function(module, exports, __webpack_require__) {
var hide = __webpack_require__(15);
module.exports = function(target, src, safe){
for(var key in src){
if(safe && target[key])target[key] = src[key];
else hide(target, key, src[key]);
} return target;
};
/***/ },
/* 67 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
var global = __webpack_require__(11)
, core = __webpack_require__(12)
, dP = __webpack_require__(16)
, DESCRIPTORS = __webpack_require__(20)
, SPECIES = __webpack_require__(45)('species');
module.exports = function(KEY){
var C = typeof core[KEY] == 'function' ? core[KEY] : global[KEY];
if(DESCRIPTORS && C && !C[SPECIES])dP.f(C, SPECIES, {
configurable: true,
get: function(){ return this; }
});
};
/***/ },
/* 68 */
/***/ function(module, exports, __webpack_require__) {
var ITERATOR = __webpack_require__(45)('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(){ return {done: safe = true}; };
arr[ITERATOR] = function(){ return iter; };
exec(arr);
} catch(e){ /* empty */ }
return safe;
};
/***/ },
/* 69 */
/***/ function(module, exports, __webpack_require__) {
module.exports = { "default": __webpack_require__(70), __esModule: true };
/***/ },
/* 70 */
/***/ function(module, exports, __webpack_require__) {
__webpack_require__(71);
module.exports = __webpack_require__(12).Object.assign;
/***/ },
/* 71 */
/***/ 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__(72)});
/***/ },
/* 72 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
// 19.1.2.1 Object.assign(target, source, ...)
var getKeys = __webpack_require__(31)
, gOPS = __webpack_require__(73)
, pIE = __webpack_require__(61)
, toObject = __webpack_require__(47)
, IObject = __webpack_require__(34)
, $assign = Object.assign;
// should work with symbols and should have deterministic property order (V8 bug)
module.exports = !$assign || __webpack_require__(21)(function(){
var A = {}
, B = {}
, S = Symbol()
, K = 'abcdefghijklmnopqrst';
A[S] = 7;
K.split('').forEach(function(k){ B[k] = k; });
return $assign({}, A)[S] != 7 || Object.keys($assign({}, B)).join('') != K;
}) ? function assign(target, source){ // eslint-disable-line no-unused-vars
var T = toObject(target)
, aLen = arguments.length
, index = 1
, getSymbols = gOPS.f
, isEnum = pIE.f;
while(aLen > index){
var S = IObject(arguments[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;
} : $assign;
/***/ },
/* 73 */
/***/ function(module, exports) {
exports.f = Object.getOwnPropertySymbols;
/***/ },
/* 74 */
/***/ 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");
}
};
/***/ },
/* 75 */
/***/ function(module, exports, __webpack_require__) {
"use strict";
exports.__esModule = true;
var _defineProperty = __webpack_require__(76);
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;
};
}();
/***/ },
/* 76 */
/***/ function(module, exports, __webpack_require__) {
module.exports = { "default": __webpack_require__(77), __esModule: true };
/***/ },
/* 77 */
/***/ function(module, exports, __webpack_require__) {
__webpack_require__(78);
var $Object = __webpack_require__(12).Object;
module.exports = function defineProperty(it, key, desc){
return $Object.defineProperty(it, key, desc);
};
/***/ },
/* 78 */
/***/ function(module, exports, __webpack_require__) {
var $export = __webpack_require__(10);
// 19.1.2.4 / 15.2.3.6 Object.defineProperty(O, P, Attributes)
$export($export.S + $export.F * !__webpack_require__(20), 'Object', {defineProperty: __webpack_require__(16).f});
/***/ },
/* 79 */
/***/ 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;
}
/***/ },
/* 80 */
/***/ function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(process) {'use strict';
const fs = __webpack_require__(83);
const format = __webpack_require__(84).format;
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() {
this._write(LogLevels.DEBUG, format.apply(null, arguments));
}
log() {
this.debug.apply(this, arguments);
}
info() {
this._write(LogLevels.INFO, format.apply(null, arguments));
}
warn() {
this._write(LogLevels.WARN, format.apply(null, arguments));
}
error() {
this._write(LogLevels.ERROR, format.apply(null, arguments));
}
_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__(81)))
/***/ },
/* 81 */
/***/ 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__(82);
cwd = path.resolve(dir, cwd);
};
})();
exports.exit = exports.kill =
exports.umask = exports.dlopen =
exports.uptime = exports.memoryUsage =
exports.uvCounters = function() {};
exports.features = {};
/***/ },
/* 82 */
/***/ 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__(81)))
/***/ },
/* 83 */
/***/ function(module, exports) {
'use strict';
module.exports = {
createWriteStream: function(filename, options) {
return;
},
writeFileSync: function() {
return;
},
openSync: function() {
return;
},
writeSync: function() {
return;
}
}
/***/ },
/* 84 */
/***/ function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(global, 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.
var formatRegExp = /%[sdj%]/g;
exports.format = function(f) {
if (!isString(f)) {
var objects = [];
for (var i = 0; i < arguments.length; i++) {
objects.push(inspect(arguments[i]));
}
return objects.join(' ');
}
var i = 1;
var args = arguments;
var len = args.length;
var str = String(f).replace(formatRegExp, function(x) {
if (x === '%%') return '%';
if (i >= len) return x;
switch (x) {
case '%s': return String(args[i++]);
case '%d': return Number(args[i++]);
case '%j':
try {
return JSON.stringify(args[i++]);
} catch (_) {
return '[Circular]';
}
default:
return x;
}
});
for (var x = args[i]; i < len; x = args[++i]) {
if (isNull(x) || !isObject(x)) {
str += ' ' + x;
} else {
str += ' ' + inspect(x);
}
}
return str;
};
// Mark that a method should not be used.
// Returns a modified function which warns once by default.
// If --no-deprecation is set, then it is a no-op.
exports.deprecate = function(fn, msg) {
// Allow for deprecating things in the process of starting up.
if (isUndefined(global.process)) {
return function() {
return exports.deprecate(fn, msg).apply(this, arguments);
};
}
if (process.noDeprecation === true) {
return fn;
}
var warned = false;
function deprecated() {
if (!warned) {
if (process.throwDeprecation) {
throw new Error(msg);
} else if (process.traceDeprecation) {
console.trace(msg);
} else {
console.error(msg);
}
warned = true;
}
return fn.apply(this, arguments);
}
return deprecated;
};
var debugs = {};
var debugEnviron;
exports.debuglog = function(set) {
if (isUndefined(debugEnviron))
debugEnviron = process.env.NODE_DEBUG || '';
set = set.toUpperCase();
if (!debugs[set]) {
if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) {
var pid = process.pid;
debugs[set] = function() {
var msg = exports.format.apply(exports, arguments);
console.error('%s %d: %s', set, pid, msg);
};
} else {
debugs[set] = function() {};
}
}
return debugs[set];
};
/**
* Echos the value of a value. Trys to print the value out
* in the best way possible given the different types.
*
* @param {Object} obj The object to print out.
* @param {Object} opts Optional options object that alters the output.
*/
/* legacy: obj, showHidden, depth, colors*/
function inspect(obj, opts) {
// default options
var ctx = {
seen: [],
stylize: stylizeNoColor
};
// legacy...
if (arguments.length >= 3) ctx.depth = arguments[2];
if (arguments.length >= 4) ctx.colors = arguments[3];
if (isBoolean(opts)) {
// legacy...
ctx.showHidden = opts;
} else if (opts) {
// got an "options" object
exports._extend(ctx, opts);
}
// set default options
if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
if (isUndefined(ctx.depth)) ctx.depth = 2;
if (isUndefined(ctx.colors)) ctx.colors = false;
if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
if (ctx.colors) ctx.stylize = stylizeWithColor;
return formatValue(ctx, obj, ctx.depth);
}
exports.inspect = inspect;
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
inspect.colors = {
'bold' : [1, 22],
'italic' : [3, 23],
'underline' : [4, 24],
'inverse' : [7, 27],
'white' : [37, 39],
'grey' : [90, 39],
'black' : [30, 39],
'blue' : [34, 39],
'cyan' : [36, 39],
'green' : [32, 39],
'magenta' : [35, 39],
'red' : [31, 39],
'yellow' : [33, 39]
};
// Don't use 'blue' not visible on cmd.exe
inspect.styles = {
'special': 'cyan',
'number': 'yellow',
'boolean': 'yellow',
'undefined': 'grey',
'null': 'bold',
'string': 'green',
'date': 'magenta',
// "name": intentionally not styling
'regexp': 'red'
};
function stylizeWithColor(str, styleType) {
var style = inspect.styles[styleType];
if (style) {
return '\u001b[' + inspect.colors[style][0] + 'm' + str +
'\u001b[' + inspect.colors[style][1] + 'm';
} else {
return str;
}
}
function stylizeNoColor(str, styleType) {
return str;
}
function arrayToHash(array) {
var hash = {};
array.forEach(function(val, idx) {
hash[val] = true;
});
return hash;
}
function formatValue(ctx, value, recurseTimes) {
// Provide a hook for user-specified inspect functions.
// Check that value is an object with an inspect function on it
if (ctx.customInspect &&
value &&
isFunction(value.inspect) &&
// Filter out the util module, it's inspect function is special
value.inspect !== exports.inspect &&
// Also filter out any prototype objects using the circular check.
!(value.constructor && value.constructor.prototype === value)) {
var ret = value.inspect(recurseTimes, ctx);
if (!isString(ret)) {
ret = formatValue(ctx, ret, recurseTimes);
}
return ret;
}
// Primitive types cannot have properties
var primitive = formatPrimitive(ctx, value);
if (primitive) {
return primitive;
}
// Look up the keys of the object.
var keys = Object.keys(value);
var visibleKeys = arrayToHash(keys);
if (ctx.showHidden) {
keys = Object.getOwnPropertyNames(value);
}
// IE doesn't make error fields non-enumerable
// http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx
if (isError(value)
&& (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) {
return formatError(value);
}
// Some type of object without properties can be shortcutted.
if (keys.length === 0) {
if (isFunction(value)) {
var name = value.name ? ': ' + value.name : '';
return ctx.stylize('[Function' + name + ']', 'special');
}
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
}
if (isDate(value)) {
return ctx.stylize(Date.prototype.toString.call(value), 'date');
}
if (isError(value)) {
return formatError(value);
}
}
var base = '', array = false, braces = ['{', '}'];
// Make Array say that they are Array
if (isArray(value)) {
array = true;
braces = ['[', ']'];
}
// Make functions say that they are functions
if (isFunction(value)) {
var n = value.name ? ': ' + value.name : '';
base = ' [Function' + n + ']';
}
// Make RegExps say that they are RegExps
if (isRegExp(value)) {
base = ' ' + RegExp.prototype.toString.call(value);
}
// Make dates with properties first say the date
if (isDate(value)) {
base = ' ' + Date.prototype.toUTCString.call(value);
}
// Make error with message first say the error
if (isError(value)) {
base = ' ' + formatError(value);
}
if (keys.length === 0 && (!array || value.length == 0)) {
return braces[0] + base + braces[1];
}
if (recurseTimes < 0) {
if (isRegExp(value)) {
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
} else {
return ctx.stylize('[Object]', 'special');
}
}
ctx.seen.push(value);
var output;
if (array) {
output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
} else {
output = keys.map(function(key) {
return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
});
}
ctx.seen.pop();
return reduceToSingleString(output, base, braces);
}
function formatPrimitive(ctx, value) {
if (isUndefined(value))
return ctx.stylize('undefined', 'undefined');
if (isString(value)) {
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
.replace(/'/g, "\\'")
.replace(/\\"/g, '"') + '\'';
return ctx.stylize(simple, 'string');
}
if (isNumber(value))
return ctx.stylize('' + value, 'number');
if (isBoolean(value))
return ctx.stylize('' + value, 'boolean');
// For some reason typeof null is "object", so special case here.
if (isNull(value))
return ctx.stylize('null', 'null');
}
function formatError(value) {
return '[' + Error.prototype.toString.call(value) + ']';
}
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
var output = [];
for (var i = 0, l = value.length; i < l; ++i) {
if (hasOwnProperty(value, String(i))) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
String(i), true));
} else {
output.push('');
}
}
keys.forEach(function(key) {
if (!key.match(/^\d+$/)) {
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
key, true));
}
});
return output;
}
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
var name, str, desc;
desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] };
if (desc.get) {
if (desc.set) {
str = ctx.stylize('[Getter/Setter]', 'special');
} else {
str = ctx.stylize('[Getter]', 'special');
}
} else {
if (desc.set) {
str = ctx.stylize('[Setter]', 'special');
}
}
if (!hasOwnProperty(visibleKeys, key)) {
name = '[' + key + ']';
}
if (!str) {
if (ctx.seen.indexOf(desc.value) < 0) {
if (isNull(recurseTimes)) {
str = formatValue(ctx, desc.value, null);
} else {
str = formatValue(ctx, desc.value, recurseTimes - 1);
}
if (str.indexOf('\n') > -1) {
if (array) {
str = str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n').substr(2);
} else {
str = '\n' + str.split('\n').map(function(line) {
return ' ' + line;
}).join('\n');
}
}
} else {
str = ctx.stylize('[Circular]', 'special');
}
}
if (isUndefined(name)) {
if (array && key.match(/^\d+$/)) {
return str;
}
name = JSON.stringify('' + key);
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
name = name.substr(1, name.length - 2);
name = ctx.stylize(name, 'name');
} else {
name = name.replace(/'/g, "\\'")
.replace(/\\"/g, '"')
.replace(/(^"|"$)/g, "'");
name = ctx.stylize(name, 'string');
}
}
return name + ': ' + str;
}
function reduceToSingleString(output, base, braces) {
var numLinesEst = 0;
var length = output.reduce(function(prev, cur) {
numLinesEst++;
if (cur.indexOf('\n') >= 0) numLinesEst++;
return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
}, 0);
if (length > 60) {
return braces[0] +
(base === '' ? '' : base + '\n ') +
' ' +
output.join(',\n ') +
' ' +
braces[1];
}
return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
}
// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isArray(ar) {
return Array.isArray(ar);
}
exports.isArray = isArray;
function isBoolean(arg) {
return typeof arg === 'boolean';
}
exports.isBoolean = isBoolean;
function isNull(arg) {
return arg === null;
}
exports.isNull = isNull;
function isNullOrUndefined(arg) {
return arg == null;
}
exports.isNullOrUndefined = isNullOrUndefined;
function isNumber(arg) {
return typeof arg === 'number';
}
exports.isNumber = isNumber;
function isString(arg) {
return typeof arg === 'string';
}
exports.isString = isString;
function isSymbol(arg) {
return typeof arg === 'symbol';
}
exports.isSymbol = isSymbol;
function isUndefined(arg) {
return arg === void 0;
}
exports.isUndefined = isUndefined;
function isRegExp(re) {
return isObject(re) && objectToString(re) === '[object RegExp]';
}
exports.isRegExp = isRegExp;
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
exports.isObject = isObject;
function isDate(d) {
return isObject(d) && objectToString(d) === '[object Date]';
}
exports.isDate = isDate;
function isError(e) {
return isObject(e) &&
(objectToString(e) === '[object Error]' || e instanceof Error);
}
exports.isError = isError;
function isFunction(arg) {
return typeof arg === 'function';
}
exports.isFunction = isFunction;
function isPrimitive(arg) {
return arg === null ||
typeof arg === 'boolean' ||
typeof arg === 'number' ||
typeof arg === 'string' ||
typeof arg === 'symbol' || // ES6 symbol
typeof arg === 'undefined';
}
exports.isPrimitive = isPrimitive;
exports.isBuffer = __webpack_require__(85);
function objectToString(o) {
return Object.prototype.toString.call(o);
}
function pad(n) {
return n < 10 ? '0' + n.toString(10) : n.toString(10);
}
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
'Oct', 'Nov', 'Dec'];
// 26 Feb 16:19:34
function timestamp() {
var d = new Date();
var time = [pad(d.getHours()),
pad(d.getMinutes()),
pad(d.getSeconds())].join(':');
return [d.getDate(), months[d.getMonth()], time].join(' ');
}
// log is just a thin wrapper to console.log that prepends a timestamp
exports.log = function() {
console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
};
/**
* Inherit the prototype methods from one constructor into another.
*
* The Function.prototype.inherits from lang.js rewritten as a standalone
* function (not on Function.prototype). NOTE: If this file is to be loaded
* during bootstrapping this function needs to be rewritten using some native
* functions as prototype setup using normal JavaScript does not work as
* expected during bootstrapping (see mirror.js in r114903).
*
* @param {function} ctor Constructor function which needs to inherit the
* prototype.
* @param {function} superCtor Constructor function to inherit prototype from.
*/
exports.inherits = __webpack_require__(86);
exports._extend = function(origin, add) {
// Don't do anything if add isn't an object
if (!add || !isObject(add)) return origin;
var keys = Object.keys(add);
var i = keys.length;
while (i--) {
origin[keys[i]] = add[keys[i]];
}
return origin;
};
function hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }()), __webpack_require__(81)))
/***/ },
/* 85 */
/***/ function(module, exports) {
module.exports = function isBuffer(arg) {
return arg && typeof arg === 'object'
&& typeof arg.copy === 'function'
&& typeof arg.fill === 'function'
&& typeof arg.readUInt8 === 'function';
}
/***/ },
/* 86 */
/***/ function(module, exports) {
if (typeof Object.create === 'function') {
// implementation from standard node.js 'util' module
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
}
});
};
} else {
// old school shim for old browsers
module.exports = function inherits(ctor, superCtor) {
ctor.super_ = superCtor
var TempCtor = function () {}
TempCtor.prototype = superCtor.prototype
ctor.prototype = new TempCtor()
ctor.prototype.constructor = ctor
}
}
/***/ },
/* 87 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
const Lazy = __webpack_require__(88);
const Store = __webpack_require__(91);
const EventIndex = __webpack_require__(102);
class EventStore extends Store {
constructor(ipfs, id, dbname, options) {
if(!options) Object.assign({}, { Index: EventIndex });
if(!options.Index) Object.assign(options, { Index: EventIndex });
super(ipfs, id, dbname, options)
}
add(data) {
const operation = {
op: 'ADD',
key: null,
value: data,
meta: {
ts: new Date().getTime()
}
};
return this._addOperation(operation);
}
iterator(options) {
const messages = this._query(this.dbname, options);
let currentIndex = 0;
let iterator = {
[Symbol.iterator]() {
return this;
},
next() {
let item = { value: null, done: true };
if(currentIndex < messages.length) {
item = { value: messages[currentIndex], done: false };
currentIndex ++;
}
return item;
},
collect: () => messages
}
return iterator;
}
_query(dbname, opts) {
if(!opts) opts = {};
const amount = opts.limit ? (opts.limit > -1 ? opts.limit : this._index.get().length) : 1; // Return 1 if no limit is provided
const operations = this._index.get();
let result = [];
if(opts.gt || opts.gte) {
// Greater than case
result = this._read(operations, 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(operations.reverse(), opts.lt ? opts.lt : opts.lte, amount, opts.lte || !opts.lt).reverse()
}
if(opts.reverse) result.reverse();
return result.toArray();
}
_read(ops, hash, amount, inclusive) {
return Lazy(ops)
.skipWhile((f) => hash && f.hash !== hash)
.drop(inclusive ? 0 : 1)
.take(amount);
}
}
module.exports = EventStore;
/***/ },
/* 88 */
/***/ 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.} 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.} 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.} 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.} 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__(89).setImmediate, __webpack_require__(89).clearImmediate))
/***/ },
/* 89 */
/***/ function(module, exports, __webpack_require__) {
/* WEBPACK VAR INJECTION */(function(setImmediate, clearImmediate) {var nextTick = __webpack_require__(90).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__(89).setImmediate, __webpack_require__(89).clearImmediate))
/***/ },
/* 90 */
/***/ 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() {
if (!draining || !currentQueue) {
return;
}
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; };
/***/ },
/* 91 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
const EventEmitter = __webpack_require__(79).EventEmitter;
const Log = __webpack_require__(92);
const Index = __webpack_require__(100);
const Cache = __webpack_require__(101);
class Store {
constructor(ipfs, id, dbname, options) {
this.id = id;
this.dbname = dbname;
this.events = new EventEmitter();
if(!options) options = {};
if(!options.Index) Object.assign(options, { Index: Index });
if(!options.cacheFile) Object.assign(options, { cacheFile: null });
this.options = options;
this._index = new this.options.Index(this.id);
this._oplog = null;
this._ipfs = ipfs;
this._lastWrite = null;
}
use() {
this.events.emit('load', this.dbname);
this._oplog = new Log(this._ipfs, this.id, this.dbname, this.options);
return Cache.loadCache(this.options.cacheFile).then(() => {
const cached = Cache.get(this.dbname);
if(cached) {
return Log.fromIpfsHash(this._ipfs, cached)
.then((log) => this._oplog.join(log))
.then((merged) => this._index.updateIndex(this._oplog, merged))
.then(() => this.events.emit('readable', this.dbname))
.then(() => this.events);
}
return Promise.resolve(this.events);
});
}
close() {
this.events.emit('close', this.dbname);
}
sync(hash) {
if(!hash || hash === this._lastWrite)
return Promise.resolve([]);
const oldCount = this._oplog.items.length;
let newItems = [];
this.events.emit('load', this.dbname);
return Log.fromIpfsHash(this._ipfs, hash)
.then((log) => this._oplog.join(log))
.then((merged) => newItems = merged)
.then(() => Log.getIpfsHash(this._ipfs, this._oplog))
.then((hash) => Cache.set(this.dbname, hash))
.then(() => this._index.updateIndex(this._oplog, newItems))
.then(() => {
if(newItems.length > 0)
this.events.emit('readable', this.dbname);
})
.then(() => newItems)
}
delete() {
this._index = new this.options.Index(this.id);
if(this._oplog)
this._oplog.clear();
}
_addOperation(data) {
let result, logHash;
if(this._oplog) {
return this._oplog.add(data)
.then((res) => {
result = res;
Object.assign(result.payload, { hash: res.hash })
return result;
})
.then(() => Log.getIpfsHash(this._ipfs, this._oplog))
.then((hash) => logHash = hash)
.then(() => this._lastWrite = logHash)
.then(() => Cache.set(this.dbname, logHash))
.then(() => this._index.updateIndex(this._oplog, [result]))
.then(() => this.events.emit('data', this.dbname, logHash))
.then(() => result.hash);
}
}
}
module.exports = Store;
/***/ },
/* 92 */
/***/ function(module, exports, __webpack_require__) {
'use strict';
const _ = __webpack_require__(93);
const Lazy = __webpack_require__(88);
const Buffer = __webpack_require__(95).Buffer
const EventEmitter = __webpack_require__(79).EventEmitter;
const Node = __webpack_require__(99);
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, name, opts) {
this.id = id;
this.name = name;
this._ipfs = ipfs;
this._items = opts && opts.items ? opts.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();
const heads = Log.findHeads(this);
return Node.create(this._ipfs, data, heads)
.then((node) => {
this._currentBatch.push(node);
return node;
});
}
join(other) {
const current = Lazy(this._currentBatch).difference(this._items).toArray();
const diff = _.differenceWith(other.items, current, Node.equals);
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;
});
});
return Promise.all(promises).then((r) => _.flatten(r.concat(diff)))
}
clear() {
this._items = [];
this._currentBatch = [];
}
// Returns entrie after initialization
load() {
return Promise.resolve([]);
}
_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;
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)
return Promise.resolve(result);
// Create the node and add it to the result
return 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));
return Promise.all(promises).then((res) => _.flatten(res.concat(result)));
});
}
// static create(ipfs, id, name, items) {
// if(!ipfs) throw new Error("Ipfs instance not defined")
// if(!id) throw new Error("id is not defined")
// const log = new Log(ipfs, id, name, items);
// return Promise.resolve(log);
// }
static getIpfsHash(ipfs, log) {
if(!ipfs) throw new Error("Ipfs instance not defined")
const data = new Buffer(JSON.stringify({ Data: JSON.stringify(log.snapshot) }));
// console.log("DATA", log, log.snapshot);
return ipfs.object.put(data)
.then((res) => {
// console.log("RES", res)
return res.Hash;
})
}
static fromJson(ipfs, json) {
return Promise.all(json.items.map((f) => Node.fromIpfsHash(ipfs, f)))
.then((items) => new Log(ipfs, json.id, '', { items: items }));
}
static fromIpfsHash(ipfs, hash) {
if(!ipfs) throw new Error("Ipfs instance not defined")
if(!hash) throw new Error("Invalid hash: " + hash)
return ipfs.object.get(hash)
.then((res) => Log.fromJson(ipfs, JSON.parse(res.Data)));
}
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;
/***/ },
/* 93 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(module, global) {/**
* @license
* lodash 4.11.2 (Custom Build)
* Build: `lodash -d -o ./foo/lodash.js`
* Copyright jQuery Foundation and other contributors
* Released under MIT license
* Based on Underscore.js 1.8.3
* 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.2';
/** 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',
rsPunctuationRange = '\\u2000-\\u206f',
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 + rsPunctuationRange + 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 `_.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;
}
/**
* 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;
}
/**
* 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;
}
/**
* 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;
value = (comparator || value !== 0) ? value : 0;
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 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 && !isSymbol(current))
: comparator(current, computed)
)) {
var computed = current,
result = value;
}
}
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[toKey(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 `_.gt` which doesn't coerce arguments to numbers.
*
* @private
* @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`.
*/
function baseGt(value, other) {
return value > other;
}
/**
* 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;
value = (comparator || value !== 0) ? value : 0;
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[toKey(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 `_.lt` which doesn't coerce arguments to numbers.
*
* @private
* @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`.
*/
function baseLt(value, other) {
return value < other;
}
/**
* 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(toKey(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 (length == lastIndex || 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[toKey(last(path))];
}
}
else {
delete array[toKey(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 = toKey(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 (computed !== null && !isSymbol(computed) &&
(retHighest ? (computed <= value) : (computed < value))) {
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,
valIsSymbol = isSymbol(value),
valIsUndefined = value === undefined;
while (low < high) {
var mid = nativeFloor((low + high) / 2),
computed = iteratee(array[mid]),
othIsDefined = computed !== undefined,
othIsNull = computed === null,
othIsReflexive = computed === computed,
othIsSymbol = isSymbol(computed);
if (valIsNaN) {
var setLow = retHighest || othIsReflexive;
} else if (valIsUndefined) {
setLow = othIsReflexive && (retHighest || othIsDefined);
} else if (valIsNull) {
setLow = othIsReflexive && othIsDefined && (retHighest || !othIsNull);
} else if (valIsSymbol) {
setLow = othIsReflexive && othIsDefined && !othIsNull && (retHighest || !othIsSymbol);
} else if (othIsNull || othIsSymbol) {
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` and `_.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 baseSortedUniq(array, iteratee) {
var index = -1,
length = array.length,
resIndex = 0,
result = [];
while (++index < length) {
var value = array[index],
computed = iteratee ? iteratee(value) : value;
if (!index || !eq(computed, seen)) {
var seen = computed;
result[resIndex++] = value === 0 ? 0 : value;
}
}
return result;
}
/**
* The base implementation of `_.toNumber` which doesn't ensure correct
* conversions of binary, hexadecimal, or octal string values.
*
* @private
* @param {*} value The value to process.
* @returns {number} Returns the number.
*/
function baseToNumber(value) {
if (typeof value == 'number') {
return value;
}
if (isSymbol(value)) {
return NAN;
}
return +value;
}
/**
* The base implementation of `_.toString` which doesn't convert nullish
* values to empty strings.
*
* @private
* @param {*} value The value to process.
* @returns {string} Returns the string.
*/
function baseToString(value) {
// Exit early for strings to avoid a performance hit in some environments.
if (typeof value == 'string') {
return value;
}
if (isSymbol(value)) {
return symbolToString ? symbolToString.call(value) : '';
}
var result = (value + '');
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : 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;
value = (comparator || value !== 0) ? value : 0;
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 = toKey(last(path));
return !(object != null && baseHas(object, key)) || delete object[key];
}
/**
* 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);
}
/**
* 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 valIsDefined = value !== undefined,
valIsNull = value === null,
valIsReflexive = value === value,
valIsSymbol = isSymbol(value);
var othIsDefined = other !== undefined,
othIsNull = other === null,
othIsReflexive = other === other,
othIsSymbol = isSymbol(other);
if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) ||
(valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) ||
(valIsNull && othIsDefined && othIsReflexive) ||
(!valIsDefined && othIsReflexive) ||
!valIsReflexive) {
return 1;
}
if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) ||
(othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) ||
(othIsNull && valIsDefined && valIsReflexive) ||
(!othIsDefined && valIsReflexive) ||
!othIsReflexive) {
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;
}
/**
* 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 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) {
if (result === undefined) {
return other;
}
if (typeof value == 'string' || typeof other == 'string') {
value = baseToString(value);
other = baseToString(other);
} else {
value = baseToNumber(value);
other = baseToNumber(other);
}
result = operator(value, other);
}
return result;
};
}
/**
* 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 ? ' ' : baseToString(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 performs a relational operation on two values.
*
* @private
* @param {Function} operator The function to perform the operation.
* @returns {Function} Returns the new relational operation function.
*/
function createRelationalOperation(operator) {
return function(value, other) {
if (!(typeof value == 'string' && typeof other == 'string')) {
value = toNumber(value);
other = toNumber(other);
}
return operator(value, other);
};
}
/**
* 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 && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? 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 = toKey(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 `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) {
length = length == null ? MAX_SAFE_INTEGER : length;
return !!length &&
(typeof value == 'number' || reIsUint.test(value)) &&
(value > -1 && value % 1 == 0 && value < length);
}
/**
* 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) {
if (isArray(value)) {
return false;
}
var type = typeof value;
if (type == 'number' || type == 'symbol' || type == 'boolean' ||
value == null || isSymbol(value)) {
return true;
}
return 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 == 'string' || type == 'number' || type == 'symbol' || type == 'boolean')
? (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(value) {
if (typeof value == 'string' || isSymbol(value)) {
return value;
}
var result = (value + '');
return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result;
}
/**
* 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.
* @see _.without, _.xor
* @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 = baseFlatten(indexes, 1);
var length = array ? array.length : 0,
result = baseAt(array, indexes);
basePullAt(array, arrayMap(indexes, function(index) {
return isIndex(index, length) ? +index : index;
}).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)
? baseSortedUniq(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.
* @see _.difference, _.xor
* @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.
* @see _.difference, _.without
* @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.
* @see _.reject
* @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`.
* @see _.forEachRight
* @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`.
* @see _.forEach
* @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.
* @see _.reduceRight
* @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.
* @see _.reduce
* @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.
* @see _.filter
* @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 '' + func(text) + '
';
* });
*
* p('fred, barney, & pebbles');
* // => 'fred, barney, & pebbles
'
*/
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.
* @see _.cloneDeep
* @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.
* @see _.cloneDeepWith
* @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.
* @see _.clone
* @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.
* @see _.cloneWith
* @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`.
* @see _.lt
* @example
*
* _.gt(3, 1);
* // => true
*
* _.gt(3, 3);
* // => false
*
* _.gt(1, 3);
* // => false
*/
var gt = createRelationalOperation(baseGt);
/**
* 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`.
* @see _.lte
* @example
*
* _.gte(3, 1);
* // => true
*
* _.gte(3, 3);
* // => true
*
* _.gte(1, 3);
* // => false
*/
var gte = createRelationalOperation(function(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('');
* // => 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`.
* @see _.gt
* @example
*
* _.lt(1, 3);
* // => true
*
* _.lt(3, 3);
* // => false
*
* _.lt(3, 1);
* // => false
*/
var lt = createRelationalOperation(baseLt);
/**
* 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`.
* @see _.gte
* @example
*
* _.lte(1, 3);
* // => true
*
* _.lte(3, 3);
* // => true
*
* _.lte(3, 1);
* // => false
*/
var lte = createRelationalOperation(function(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) {
return value == null ? '' : baseToString(value);
}
/*------------------------------------------------------------------------*/
/**
* 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`.
* @see _.assignIn
* @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`.
* @see _.assign
* @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`.
* @see _.assignWith
* @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`.
* @see _.assignInWith
* @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`.
* @see _.defaultsDeep
* @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`.
* @see _.defaults
* @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`.
* @see _.forInRight
* @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`.
* @see _.forIn
* @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`.
* @see _.forOwnRight
* @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`.
* @see _.forOwn
* @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.
* @see _.functionsIn
* @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.
* @see _.functions
* @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.
* @see _.mapValues
* @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.
* @see _.mapKeys
* @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, arrayMap(baseFlatten(props, 1), toKey));
});
/**
* 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[toKey(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`.
* @see _.range, _.rangeRight
* @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 = baseToString(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 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 = baseToString(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(baseToString(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('<%- value %>');
* compiled({ 'value': '