From 8b9b6d766f4c8d10b403338147dd6aa1080c3b19 Mon Sep 17 00:00:00 2001 From: KonghaYao <20192831006@m.scnu.edu.cn> Date: Mon, 19 Jul 2021 20:40:41 +0800 Subject: [PATCH] =?UTF-8?q?feat(controlpanel=20stop):=20control=20Panel=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=20stop=20=E5=8A=9F=E8=83=BD=E5=AE=8C?= =?UTF-8?q?=E6=88=90=EF=BC=8C=E5=85=B7=E4=BD=93=E5=8A=9F=E8=83=BD=E5=B0=9A?= =?UTF-8?q?=E6=9C=AA=E5=AE=8C=E5=85=A8=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.js | 4 + VERSION.md | 20 +- dist/JSpider.esm.min.js | 4015 ++++++++++++----------- dist/JSpider.min.js | 4015 ++++++++++++----------- src/ControlPanel/ControlPanel.js | 29 +- src/ControlPanel/Mirror.js | 12 +- src/ControlPanel/StaticEvent.js | 19 +- src/Spider/index.js | 15 +- src/TaskSystem/Task.js | 2 +- src/{ControlPanel => utils}/EventHub.js | 2 + src/utils/pauseToggle.js | 35 + src/utils/pauseWhile.js | 15 - test/Request.js | 17 +- test/ZipTest.js | 34 - test/test.js | 64 +- 15 files changed, 4190 insertions(+), 4108 deletions(-) rename src/{ControlPanel => utils}/EventHub.js (98%) create mode 100644 src/utils/pauseToggle.js delete mode 100644 src/utils/pauseWhile.js delete mode 100644 test/ZipTest.js diff --git a/.eslintrc.js b/.eslintrc.js index c7e1d36..03cb6bf 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -13,6 +13,10 @@ module.exports = { sourceType: 'module', requireConfigFile: false, }, + globals: { + __version__: true, + __buildDate__: true, + }, rules: { 'prettier/prettier': ['error'], 'no-console': 0, diff --git a/VERSION.md b/VERSION.md index af15a63..6f8c0c4 100644 --- a/VERSION.md +++ b/VERSION.md @@ -6,12 +6,24 @@ - [ ] 关于 UI 界面的更新 -### 3.2 版本更新 +### 3.2 - Paimon 版本更新 -- [x] 完整的 JSpider 编程逻辑框架出图 +- 完整的 JSpider 编程逻辑框架出图 -- [ ] 重构所有的核心代码 + - [ ] JSpider 中的数据流系统 -- [ ] 重构 plugins + - [ ] JSpider 中的事件系统 + + - [ ] JSpider 需要实现 MVVM 模型来实现爬虫系统的可视化 + +- 重构所有的核心代码 + + - [ ] Control Panel 暂停功能 + + - [ ] Control Panel 重试功能(非流内自动重试) + +- 重构 plugins + - [ ] plugins 分包导入 + - [ ] Request 多平台 > 因为是 3.2 版本才更新这个文件,所以以前的版本都丢失了。 diff --git a/dist/JSpider.esm.min.js b/dist/JSpider.esm.min.js index 87d9675..63bb7d1 100644 --- a/dist/JSpider.esm.min.js +++ b/dist/JSpider.esm.min.js @@ -1636,1469 +1636,1332 @@ function dispatch(state) { this.schedule(state, period); } -class EventHub { - all = new Map(); - constructor(eventMap = {}, bindThis = null) { - this.bindThis = bindThis || globalThis; - this.on(eventMap); - } - #on(type, handler) { - const handlers = this.all.get(type); - // ! 注意,栈的结构,这里要使用 unshift 将元素插入到头部,这样触发的时候才会最后执行最先声明的函数作为默认函数 - // 栈的结构可以保证 在 destroy 事件的时候,首先定义的 destroy 可以最后执行,保证后面绑定 destroy 事件的函数可以先触发,而在 destroy 的定义函数中可以最后 off('*') 解除事件 - handlers ? handlers.unshift(handler) : this.all.set(type, [handler]); - } - on(type, handler) { - // 函数重载 - if (typeof type === 'string') { - this.#on(type, handler); - } else if (type instanceof Object) { - // 在直接赋值为一个 - Object.entries(type).forEach(([key, value]) => { - if (value instanceof Array) { - value.forEach((item) => this.#on(key, item)); - } else { - this.#on(key, value); - } - }); - } - } - off(type, handler) { - if (type === '*') { - return this.all.clear(); - } else { - const handlers = this.all.get(type); - if (handlers) { - return handler ? handlers.splice(handlers.indexOf(handler) >>> 0, 1) : this.all.set(type, []); - } - return false; - } - } - emit(type, ...eventParams) { - const handlers = this.all.get(type); - return handlers - ? handlers.map((handler) => { - return handler.apply(this.bindThis, eventParams); - }) - : []; - } - // 创建一个 rxjs 流源头 - createSource$(eventName) { - return fromEventPattern( - (handle) => this.on(eventName, handle), - (handle) => this.off(eventName, handle), - ); - } -} - -const staticEvent$2 = {}; +/** Detect free variable `global` from Node.js. */ +var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; -// Unique ID creation requires a high quality random # generator. In the browser we therefore -// require the crypto API and do not support built-in fallback to lower quality random number -// generators (like Math.random()). -var getRandomValues; -var rnds8 = new Uint8Array(16); -function rng() { - // lazy load so that environments that need to polyfill have a chance to do so - if (!getRandomValues) { - // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also, - // find the complete implementation of crypto (msCrypto) on IE11. - getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto); +/** Detect free variable `self`. */ +var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - if (!getRandomValues) { - throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); - } - } +/** Used as a reference to the global object. */ +var root = freeGlobal || freeSelf || Function('return this')(); - return getRandomValues(rnds8); -} +/** Built-in value references. */ +var Symbol$1 = root.Symbol; -var REGEX = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; +/** Used for built-in method references. */ +var objectProto$6 = Object.prototype; -function validate(uuid) { - return typeof uuid === 'string' && REGEX.test(uuid); -} +/** Used to check objects for own properties. */ +var hasOwnProperty$5 = objectProto$6.hasOwnProperty; /** - * Convert array of 16 byte values to UUID string format of the form: - * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. */ +var nativeObjectToString$1 = objectProto$6.toString; -var byteToHex = []; +/** Built-in value references. */ +var symToStringTag$1 = Symbol$1 ? Symbol$1.toStringTag : undefined; -for (var i = 0; i < 256; ++i) { - byteToHex.push((i + 0x100).toString(16).substr(1)); -} +/** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ +function getRawTag(value) { + var isOwn = hasOwnProperty$5.call(value, symToStringTag$1), + tag = value[symToStringTag$1]; -function stringify(arr) { - var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - // Note: Be careful editing this code! It's been tuned for performance - // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 - var uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one - // of the following: - // - One or more input array values don't map to a hex octet (leading to - // "undefined" in the uuid) - // - Invalid input values for the RFC `version` or `variant` fields + try { + value[symToStringTag$1] = undefined; + var unmasked = true; + } catch (e) {} - if (!validate(uuid)) { - throw TypeError('Stringified UUID is invalid'); + var result = nativeObjectToString$1.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag$1] = tag; + } else { + delete value[symToStringTag$1]; + } } - - return uuid; + return result; } -function parse(uuid) { - if (!validate(uuid)) { - throw TypeError('Invalid UUID'); - } - - var v; - var arr = new Uint8Array(16); // Parse ########-....-....-....-............ - - arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; - arr[1] = v >>> 16 & 0xff; - arr[2] = v >>> 8 & 0xff; - arr[3] = v & 0xff; // Parse ........-####-....-....-............ - - arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; - arr[5] = v & 0xff; // Parse ........-....-####-....-............ - - arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; - arr[7] = v & 0xff; // Parse ........-....-....-####-............ +/** Used for built-in method references. */ +var objectProto$5 = Object.prototype; - arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; - arr[9] = v & 0xff; // Parse ........-....-....-....-############ - // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes) +/** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ +var nativeObjectToString = objectProto$5.toString; - arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff; - arr[11] = v / 0x100000000 & 0xff; - arr[12] = v >>> 24 & 0xff; - arr[13] = v >>> 16 & 0xff; - arr[14] = v >>> 8 & 0xff; - arr[15] = v & 0xff; - return arr; +/** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ +function objectToString(value) { + return nativeObjectToString.call(value); } -function stringToBytes(str) { - str = unescape(encodeURIComponent(str)); // UTF8 escape +/** `Object#toString` result references. */ +var nullTag = '[object Null]', + undefinedTag = '[object Undefined]'; - var bytes = []; +/** Built-in value references. */ +var symToStringTag = Symbol$1 ? Symbol$1.toStringTag : undefined; - for (var i = 0; i < str.length; ++i) { - bytes.push(str.charCodeAt(i)); +/** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ +function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; } - - return bytes; + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); } -var DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; -var URL$1 = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; -function v35 (name, version, hashfunc) { - function generateUUID(value, namespace, buf, offset) { - if (typeof value === 'string') { - value = stringToBytes(value); - } - - if (typeof namespace === 'string') { - namespace = parse(namespace); - } - - if (namespace.length !== 16) { - throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); - } // Compute hash of namespace and value, Per 4.3 - // Future: Use spread syntax when supported on all platforms, e.g. `bytes = - // hashfunc([...namespace, ... value])` - +/** + * 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 != null && typeof value == 'object'; +} - var bytes = new Uint8Array(16 + value.length); - bytes.set(namespace); - bytes.set(value, namespace.length); - bytes = hashfunc(bytes); - bytes[6] = bytes[6] & 0x0f | version; - bytes[8] = bytes[8] & 0x3f | 0x80; +/** `Object#toString` result references. */ +var symbolTag = '[object Symbol]'; - if (buf) { - offset = offset || 0; - - for (var i = 0; i < 16; ++i) { - buf[offset + i] = bytes[i]; - } - - return buf; - } - - return stringify(bytes); - } // Function#name is not settable on some platforms (#270) - - - try { - generateUUID.name = name; // eslint-disable-next-line no-empty - } catch (err) {} // For CommonJS default export support - - - generateUUID.DNS = DNS; - generateUUID.URL = URL$1; - return generateUUID; +/** + * 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 a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ +function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && baseGetTag(value) == symbolTag); } -function v4(options, buf, offset) { - options = options || {}; - var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` - - rnds[6] = rnds[6] & 0x0f | 0x40; - rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided - - if (buf) { - offset = offset || 0; - - for (var i = 0; i < 16; ++i) { - buf[offset + i] = rnds[i]; - } +/** + * 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 == null ? 0 : array.length, + result = Array(length); - return buf; + while (++index < length) { + result[index] = iteratee(array[index], index, array); } - - return stringify(rnds); + return result; } -// Adapted from Chris Veness' SHA1 code at -// http://www.movable-type.co.uk/scripts/sha1.html -function f(s, x, y, z) { - switch (s) { - case 0: - return x & y ^ ~x & z; +/** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ +var isArray = Array.isArray; - case 1: - return x ^ y ^ z; +/** Used as references for various `Number` constants. */ +var INFINITY$1 = 1 / 0; - case 2: - return x & y ^ x & z ^ y & z; +/** Used to convert symbols to primitives and strings. */ +var symbolProto = Symbol$1 ? Symbol$1.prototype : undefined, + symbolToString = symbolProto ? symbolProto.toString : undefined; - case 3: - return x ^ y ^ z; +/** + * 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 (isArray(value)) { + // Recursively convert values (susceptible to call stack limits). + return arrayMap(value, baseToString) + ''; + } + if (isSymbol(value)) { + return symbolToString ? symbolToString.call(value) : ''; } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY$1) ? '-0' : result; } -function ROTL(x, n) { - return x << n | x >>> 32 - n; +/** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.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 != null && (type == 'object' || type == 'function'); } -function sha1(bytes) { - var K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]; - var H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; - - if (typeof bytes === 'string') { - var msg = unescape(encodeURIComponent(bytes)); // UTF8 escape +/** + * This method returns the first argument it receives. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Util + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'a': 1 }; + * + * console.log(_.identity(object) === object); + * // => true + */ +function identity(value) { + return value; +} - bytes = []; +/** `Object#toString` result references. */ +var asyncTag = '[object AsyncFunction]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + proxyTag = '[object Proxy]'; - for (var i = 0; i < msg.length; ++i) { - bytes.push(msg.charCodeAt(i)); - } - } else if (!Array.isArray(bytes)) { - // Convert Array-like to Array - bytes = Array.prototype.slice.call(bytes); +/** + * 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 a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ +function isFunction(value) { + if (!isObject(value)) { + return false; } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; +} - bytes.push(0x80); - var l = bytes.length / 4 + 2; - var N = Math.ceil(l / 16); - var M = new Array(N); +/** Used to detect overreaching core-js shims. */ +var coreJsData = root['__core-js_shared__']; - for (var _i = 0; _i < N; ++_i) { - var arr = new Uint32Array(16); +/** Used to detect methods masquerading as native. */ +var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; +}()); - for (var j = 0; j < 16; ++j) { - arr[j] = bytes[_i * 64 + j * 4] << 24 | bytes[_i * 64 + j * 4 + 1] << 16 | bytes[_i * 64 + j * 4 + 2] << 8 | bytes[_i * 64 + j * 4 + 3]; - } +/** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ +function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); +} - M[_i] = arr; - } +/** Used for built-in method references. */ +var funcProto$1 = Function.prototype; - M[N - 1][14] = (bytes.length - 1) * 8 / Math.pow(2, 32); - M[N - 1][14] = Math.floor(M[N - 1][14]); - M[N - 1][15] = (bytes.length - 1) * 8 & 0xffffffff; - - for (var _i2 = 0; _i2 < N; ++_i2) { - var W = new Uint32Array(80); - - for (var t = 0; t < 16; ++t) { - W[t] = M[_i2][t]; - } - - for (var _t = 16; _t < 80; ++_t) { - W[_t] = ROTL(W[_t - 3] ^ W[_t - 8] ^ W[_t - 14] ^ W[_t - 16], 1); - } - - var a = H[0]; - var b = H[1]; - var c = H[2]; - var d = H[3]; - var e = H[4]; - - for (var _t2 = 0; _t2 < 80; ++_t2) { - var s = Math.floor(_t2 / 20); - var T = ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[_t2] >>> 0; - e = d; - d = c; - c = ROTL(b, 30) >>> 0; - b = a; - a = T; - } - - H[0] = H[0] + a >>> 0; - H[1] = H[1] + b >>> 0; - H[2] = H[2] + c >>> 0; - H[3] = H[3] + d >>> 0; - H[4] = H[4] + e >>> 0; - } - - return [H[0] >> 24 & 0xff, H[0] >> 16 & 0xff, H[0] >> 8 & 0xff, H[0] & 0xff, H[1] >> 24 & 0xff, H[1] >> 16 & 0xff, H[1] >> 8 & 0xff, H[1] & 0xff, H[2] >> 24 & 0xff, H[2] >> 16 & 0xff, H[2] >> 8 & 0xff, H[2] & 0xff, H[3] >> 24 & 0xff, H[3] >> 16 & 0xff, H[3] >> 8 & 0xff, H[3] & 0xff, H[4] >> 24 & 0xff, H[4] >> 16 & 0xff, H[4] >> 8 & 0xff, H[4] & 0xff]; -} - -var v5 = v35('v5', 0x50, sha1); +/** Used to resolve the decompiled source of functions. */ +var funcToString$1 = funcProto$1.toString; -/* - * @Author: KonghaYao - * @Date: 2021-06-28 21:07:01 - * @Last Modified by: KonghaYao - * @Last Modified time: 2021-06-28 21:07:01 +/** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. */ - -function createUUID(string) { - return v5(string, v5.URL); +function toSource(func) { + if (func != null) { + try { + return funcToString$1.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; } /** - * 函数用途描述 - * 这个是用于 async 函数队列 连续执行的函数,只要 enQueue 之后就会连续执行,直至停止 + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). */ +var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; -class functionQueue { - QueuePromise = Promise.resolve(); - constructor() {} - enQueue(...args) { - this.QueuePromise = args.reduce((promise, current) => { - return promise.then(current); - }, this.QueuePromise); - } -} - -// Pipeline 是组合 Plugin 实例的工具类,用于创建一个可以不断提供 source 进行固定操作的功能对象。 -class Pipeline { - constructor(Plugins) { - this.Plugins = Plugins; - } - UUID = null; // 唯一的标识 - operator = null; // 主要被引用的 operator - - #PluginQueue = new functionQueue(); // 准备 Plugin 中的异步 init 事件 - preparePipeline() { - let uuidString = ''; - // ! 一次遍历实现取出 operator 和 导出 plugin init 函数的 promise 链,并延长 uuidString 用于创建 UUID - const pipeline = this.Plugins.map((plugin) => { - uuidString += plugin.operator.toString(); - - if (plugin.init instanceof Function) { - this.#PluginQueue.enQueue(plugin.init); - } - // 将 plugin 中的 operator 注入 pipeline 中 - return plugin.operator(this); - }); - this.operator = pipe(...pipeline); - - this.UUID = createUUID(uuidString); - - return this.#PluginQueue.QueuePromise; - } -} - -// 每个 Task 拥有的静态事件 -// 这些事件一般通过 $commit(eventName,payload) 进行执行 -// ! this 被绑定为 Task 的实例 -const staticEvent$1 = { - start(UUID) { - this._status = 'busy'; - // ! 这里会有一个清空这个 key 的 value 的情况,这是因为 start 是强制的 - this._progress.set(UUID, { process: 'start' }); - - return this._output || this._originData; - }, - success(output, UUID) { - this._status = 'free'; - this._progress.set(UUID, { process: 'success', output }); - this._output = output; - }, - complete(UUID) { - this._status = 'complete'; - }, - error(err, UUID) { - this._status = 'error'; - this._progress.set(UUID, { process: 'error', err }); - }, - destroy() { - this._process = []; - this._output = null; - this._belongTo = null; - this._originData = null; - this.$off('*'); - }, -}; - -/** Detect free variable `global` from Node.js. */ -var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - -/** Detect free variable `self`. */ -var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - -/** Used as a reference to the global object. */ -var root = freeGlobal || freeSelf || Function('return this')(); - -/** Built-in value references. */ -var Symbol$1 = root.Symbol; +/** Used to detect host constructors (Safari). */ +var reIsHostCtor = /^\[object .+?Constructor\]$/; /** Used for built-in method references. */ -var objectProto$6 = Object.prototype; +var funcProto = Function.prototype, + objectProto$4 = Object.prototype; -/** Used to check objects for own properties. */ -var hasOwnProperty$5 = objectProto$6.hasOwnProperty; +/** Used to resolve the decompiled source of functions. */ +var funcToString = funcProto.toString; -/** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ -var nativeObjectToString$1 = objectProto$6.toString; +/** Used to check objects for own properties. */ +var hasOwnProperty$4 = objectProto$4.hasOwnProperty; -/** Built-in value references. */ -var symToStringTag$1 = Symbol$1 ? Symbol$1.toStringTag : undefined; +/** Used to detect if a method is native. */ +var reIsNative = RegExp('^' + + funcToString.call(hasOwnProperty$4).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' +); /** - * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * The base implementation of `_.isNative` without bad shim checks. * * @private - * @param {*} value The value to query. - * @returns {string} Returns the raw `toStringTag`. + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. */ -function getRawTag(value) { - var isOwn = hasOwnProperty$5.call(value, symToStringTag$1), - tag = value[symToStringTag$1]; - - try { - value[symToStringTag$1] = undefined; - var unmasked = true; - } catch (e) {} - - var result = nativeObjectToString$1.call(value); - if (unmasked) { - if (isOwn) { - value[symToStringTag$1] = tag; - } else { - delete value[symToStringTag$1]; - } +function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; } - return result; + var pattern = isFunction(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); } -/** Used for built-in method references. */ -var objectProto$5 = Object.prototype; - -/** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ -var nativeObjectToString = objectProto$5.toString; - /** - * Converts `value` to a string using `Object.prototype.toString`. + * Gets the value at `key` of `object`. * * @private - * @param {*} value The value to convert. - * @returns {string} Returns the converted string. + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. */ -function objectToString(value) { - return nativeObjectToString.call(value); +function getValue(object, key) { + return object == null ? undefined : object[key]; } -/** `Object#toString` result references. */ -var nullTag = '[object Null]', - undefinedTag = '[object Undefined]'; - -/** Built-in value references. */ -var symToStringTag = Symbol$1 ? Symbol$1.toStringTag : undefined; - /** - * The base implementation of `getTag` without fallbacks for buggy environments. + * Gets the native function at `key` of `object`. * * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. + * @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 baseGetTag(value) { - if (value == null) { - return value === undefined ? undefinedTag : nullTag; - } - return (symToStringTag && symToStringTag in Object(value)) - ? getRawTag(value) - : objectToString(value); +function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; } /** - * 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 + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. * - * _.isObjectLike(null); - * // => false + * @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 isObjectLike(value) { - return value != null && typeof value == 'object'; +function apply(func, thisArg, args) { + switch (args.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); } -/** `Object#toString` result references. */ -var symbolTag = '[object Symbol]'; +/** Used to detect hot functions by number of calls within a span of milliseconds. */ +var HOT_COUNT = 800, + HOT_SPAN = 16; -/** - * 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 a symbol, else `false`. - * @example - * - * _.isSymbol(Symbol.iterator); - * // => true - * - * _.isSymbol('abc'); - * // => false - */ -function isSymbol(value) { - return typeof value == 'symbol' || - (isObjectLike(value) && baseGetTag(value) == symbolTag); -} +/* Built-in method references for those with the same name as other `lodash` methods. */ +var nativeNow = Date.now; /** - * A specialized version of `_.map` for arrays without support for iteratee - * shorthands. + * Creates a function that'll short out and invoke `identity` instead + * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` + * milliseconds. * * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new shortable function. */ -function arrayMap(array, iteratee) { - var index = -1, - length = array == null ? 0 : array.length, - result = Array(length); +function shortOut(func) { + var count = 0, + lastCalled = 0; - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; + return function() { + var stamp = nativeNow(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return arguments[0]; + } + } else { + count = 0; + } + return func.apply(undefined, arguments); + }; } /** - * Checks if `value` is classified as an `Array` object. + * Creates a function that returns `value`. * * @static * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @since 2.4.0 + * @category Util + * @param {*} value The value to return from the new function. + * @returns {Function} Returns the new constant function. * @example * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(document.body.children); - * // => false + * var objects = _.times(2, _.constant({ 'a': 1 })); * - * _.isArray('abc'); - * // => false + * console.log(objects); + * // => [{ 'a': 1 }, { 'a': 1 }] * - * _.isArray(_.noop); - * // => false + * console.log(objects[0] === objects[1]); + * // => true */ -var isArray = Array.isArray; - -/** Used as references for various `Number` constants. */ -var INFINITY$1 = 1 / 0; +function constant(value) { + return function() { + return value; + }; +} -/** Used to convert symbols to primitives and strings. */ -var symbolProto = Symbol$1 ? Symbol$1.prototype : undefined, - symbolToString = symbolProto ? symbolProto.toString : undefined; +var defineProperty = (function() { + try { + var func = getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) {} +}()); /** - * The base implementation of `_.toString` which doesn't convert nullish - * values to empty strings. + * The base implementation of `setToString` without support for hot loop shorting. * * @private - * @param {*} value The value to process. - * @returns {string} Returns the string. + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. */ -function baseToString(value) { - // Exit early for strings to avoid a performance hit in some environments. - if (typeof value == 'string') { - return value; - } - if (isArray(value)) { - // Recursively convert values (susceptible to call stack limits). - return arrayMap(value, baseToString) + ''; - } - if (isSymbol(value)) { - return symbolToString ? symbolToString.call(value) : ''; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY$1) ? '-0' : result; -} +var baseSetToString = !defineProperty ? identity : function(func, string) { + return defineProperty(func, 'toString', { + 'configurable': true, + 'enumerable': false, + 'value': constant(string), + 'writable': true + }); +}; /** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.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 + * Sets the `toString` method of `func` to return `string`. * - * _.isObject(_.noop); - * // => true + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ +var setToString = shortOut(baseSetToString); + +/** + * The base implementation of `_.findIndex` and `_.findLastIndex` without + * support for iteratee shorthands. * - * _.isObject(null); - * // => false + * @private + * @param {Array} array The array to inspect. + * @param {Function} predicate The function invoked per iteration. + * @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 value, else `-1`. */ -function isObject(value) { - var type = typeof value; - return value != null && (type == 'object' || type == 'function'); +function baseFindIndex(array, predicate, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 1 : -1); + + while ((fromRight ? index-- : ++index < length)) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; } /** - * This method returns the first argument it receives. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Util - * @param {*} value Any value. - * @returns {*} Returns `value`. - * @example - * - * var object = { 'a': 1 }; + * The base implementation of `_.isNaN` without support for number objects. * - * console.log(_.identity(object) === object); - * // => true + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. */ -function identity(value) { - return value; +function baseIsNaN(value) { + return value !== value; } -/** `Object#toString` result references. */ -var asyncTag = '[object AsyncFunction]', - funcTag = '[object Function]', - genTag = '[object GeneratorFunction]', - proxyTag = '[object Proxy]'; - /** - * Checks if `value` is classified as a `Function` object. + * A specialized version of `_.indexOf` which performs strict equality + * comparisons of values, i.e. `===`. * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false + * @private + * @param {Array} array The array to inspect. + * @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 isFunction(value) { - if (!isObject(value)) { - return false; +function strictIndexOf(array, value, fromIndex) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } } - // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 9 which returns 'object' for typed arrays and other constructors. - var tag = baseGetTag(value); - return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; + return -1; } -/** Used to detect overreaching core-js shims. */ -var coreJsData = root['__core-js_shared__']; - -/** Used to detect methods masquerading as native. */ -var maskSrcKey = (function() { - var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); - return uid ? ('Symbol(src)_1.' + uid) : ''; -}()); - /** - * Checks if `func` has its source masked. + * The base implementation of `_.indexOf` without `fromIndex` bounds checks. * * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` is masked, else `false`. + * @param {Array} array The array to inspect. + * @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 isMasked(func) { - return !!maskSrcKey && (maskSrcKey in func); +function baseIndexOf(array, value, fromIndex) { + return value === value + ? strictIndexOf(array, value, fromIndex) + : baseFindIndex(array, baseIsNaN, fromIndex); } -/** Used for built-in method references. */ -var funcProto$1 = Function.prototype; - -/** Used to resolve the decompiled source of functions. */ -var funcToString$1 = funcProto$1.toString; - /** - * Converts `func` to its source code. + * A specialized version of `_.includes` for arrays without support for + * specifying an index to search from. * * @private - * @param {Function} func The function to convert. - * @returns {string} Returns the source code. + * @param {Array} [array] The array to inspect. + * @param {*} target The value to search for. + * @returns {boolean} Returns `true` if `target` is found, else `false`. */ -function toSource(func) { - if (func != null) { - try { - return funcToString$1.call(func); - } catch (e) {} - try { - return (func + ''); - } catch (e) {} - } - return ''; +function arrayIncludes(array, value) { + var length = array == null ? 0 : array.length; + return !!length && baseIndexOf(array, value, 0) > -1; } -/** - * Used to match `RegExp` - * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). - */ -var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; - -/** Used to detect host constructors (Safari). */ -var reIsHostCtor = /^\[object .+?Constructor\]$/; - -/** Used for built-in method references. */ -var funcProto = Function.prototype, - objectProto$4 = Object.prototype; - -/** Used to resolve the decompiled source of functions. */ -var funcToString = funcProto.toString; - -/** Used to check objects for own properties. */ -var hasOwnProperty$4 = objectProto$4.hasOwnProperty; +/** Used as references for various `Number` constants. */ +var MAX_SAFE_INTEGER$1 = 9007199254740991; -/** Used to detect if a method is native. */ -var reIsNative = RegExp('^' + - funcToString.call(hasOwnProperty$4).replace(reRegExpChar, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' -); +/** Used to detect unsigned integer values. */ +var reIsUint = /^(?:0|[1-9]\d*)$/; /** - * The base implementation of `_.isNative` without bad shim checks. + * Checks if `value` is a valid array-like index. * * @private * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, - * else `false`. + * @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 baseIsNative(value) { - if (!isObject(value) || isMasked(value)) { - return false; - } - var pattern = isFunction(value) ? reIsNative : reIsHostCtor; - return pattern.test(toSource(value)); +function isIndex(value, length) { + var type = typeof value; + length = length == null ? MAX_SAFE_INTEGER$1 : length; + + return !!length && + (type == 'number' || + (type != 'symbol' && reIsUint.test(value))) && + (value > -1 && value % 1 == 0 && value < length); } /** - * Gets the value at `key` of `object`. + * The base implementation of `assignValue` and `assignMergeValue` without + * value checks. * * @private - * @param {Object} [object] The object to query. - * @param {string} key The key of the property to get. - * @returns {*} Returns the property value. + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. */ -function getValue(object, key) { - return object == null ? undefined : object[key]; +function baseAssignValue(object, key, value) { + if (key == '__proto__' && defineProperty) { + defineProperty(object, key, { + 'configurable': true, + 'enumerable': true, + 'value': value, + 'writable': true + }); + } else { + object[key] = value; + } } /** - * Gets the native function at `key` of `object`. + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. * - * @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`. + * @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 = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true */ -function getNative(object, key) { - var value = getValue(object, key); - return baseIsNative(value) ? value : undefined; +function eq(value, other) { + return value === other || (value !== value && other !== other); } +/** Used for built-in method references. */ +var objectProto$3 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$3 = objectProto$3.hasOwnProperty; + /** - * A faster alternative to `Function#apply`, this function invokes `func` - * with the `this` binding of `thisArg` and the arguments of `args`. + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. * * @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`. + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. */ -function apply(func, thisArg, args) { - switch (args.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]); +function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty$3.call(object, key) && eq(objValue, value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); } - return func.apply(thisArg, args); } -/** Used to detect hot functions by number of calls within a span of milliseconds. */ -var HOT_COUNT = 800, - HOT_SPAN = 16; - /* Built-in method references for those with the same name as other `lodash` methods. */ -var nativeNow = Date.now; +var nativeMax = Math.max; /** - * Creates a function that'll short out and invoke `identity` instead - * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` - * milliseconds. + * A specialized version of `baseRest` which transforms the rest array. * * @private - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new shortable 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. + * @param {Function} transform The rest array transform. + * @returns {Function} Returns the new function. */ -function shortOut(func) { - var count = 0, - lastCalled = 0; - +function overRest(func, start, transform) { + start = nativeMax(start === undefined ? (func.length - 1) : start, 0); return function() { - var stamp = nativeNow(), - remaining = HOT_SPAN - (stamp - lastCalled); + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + array = Array(length); - lastCalled = stamp; - if (remaining > 0) { - if (++count >= HOT_COUNT) { - return arguments[0]; - } - } else { - count = 0; + while (++index < length) { + array[index] = args[start + index]; } - return func.apply(undefined, arguments); + index = -1; + var otherArgs = Array(start + 1); + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = transform(array); + return apply(func, this, otherArgs); }; } /** - * Creates a function that returns `value`. + * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * + * @private + * @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. + */ +function baseRest(func, start) { + return setToString(overRest(func, start, identity), func + ''); +} + +/** Used as references for various `Number` constants. */ +var MAX_SAFE_INTEGER = 9007199254740991; + +/** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). * * @static * @memberOf _ - * @since 2.4.0 - * @category Util - * @param {*} value The value to return from the new function. - * @returns {Function} Returns the new constant function. + * @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 * - * var objects = _.times(2, _.constant({ 'a': 1 })); + * _.isLength(3); + * // => true * - * console.log(objects); - * // => [{ 'a': 1 }, { 'a': 1 }] + * _.isLength(Number.MIN_VALUE); + * // => false * - * console.log(objects[0] === objects[1]); + * _.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 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 constant(value) { - return function() { - return value; - }; +function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); } -var defineProperty = (function() { - try { - var func = getNative(Object, 'defineProperty'); - func({}, '', {}); - return func; - } catch (e) {} -}()); +/** `Object#toString` result references. */ +var argsTag = '[object Arguments]'; /** - * The base implementation of `setToString` without support for hot loop shorting. + * The base implementation of `_.isArguments`. * * @private - * @param {Function} func The function to modify. - * @param {Function} string The `toString` result. - * @returns {Function} Returns `func`. + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, */ -var baseSetToString = !defineProperty ? identity : function(func, string) { - return defineProperty(func, 'toString', { - 'configurable': true, - 'enumerable': false, - 'value': constant(string), - 'writable': true - }); -}; +function baseIsArguments(value) { + return isObjectLike(value) && baseGetTag(value) == argsTag; +} + +/** Used for built-in method references. */ +var objectProto$2 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$2 = objectProto$2.hasOwnProperty; + +/** Built-in value references. */ +var propertyIsEnumerable = objectProto$2.propertyIsEnumerable; /** - * Sets the `toString` method of `func` to return `string`. + * Checks if `value` is likely an `arguments` object. * - * @private - * @param {Function} func The function to modify. - * @param {Function} string The `toString` result. - * @returns {Function} Returns `func`. + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false */ -var setToString = shortOut(baseSetToString); +var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty$2.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); +}; /** - * The base implementation of `_.findIndex` and `_.findLastIndex` without - * support for iteratee shorthands. + * The base implementation of `_.unary` without support for storing metadata. * * @private - * @param {Array} array The array to inspect. - * @param {Function} predicate The function invoked per iteration. - * @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 value, else `-1`. + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. */ -function baseFindIndex(array, predicate, fromIndex, fromRight) { - var length = array.length, - index = fromIndex + (fromRight ? 1 : -1); +function baseUnary(func) { + return function(value) { + return func(value); + }; +} - while ((fromRight ? index-- : ++index < length)) { - if (predicate(array[index], index, array)) { - return index; +/** Detect free variable `exports`. */ +var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + +/** Detect free variable `module`. */ +var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + +/** Detect the popular CommonJS extension `module.exports`. */ +var moduleExports = freeModule && freeModule.exports === freeExports; + +/** Detect free variable `process` from Node.js. */ +var freeProcess = moduleExports && freeGlobal.process; + +/** Used to access faster Node.js helpers. */ +var nodeUtil = (function() { + try { + // Use `util.types` for Node.js 10+. + var types = freeModule && freeModule.require && freeModule.require('util').types; + + if (types) { + return types; } - } - return -1; -} + + // Legacy `process.binding('util')` for Node.js < 10. + return freeProcess && freeProcess.binding && freeProcess.binding('util'); + } catch (e) {} +}()); + +/** Used to match property names within property paths. */ +var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/; /** - * The base implementation of `_.isNaN` without support for number objects. + * Checks if `value` is a property name and not a property path. * * @private * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. */ -function baseIsNaN(value) { - return value !== value; +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)); } +/* Built-in method references that are verified to be native. */ +var nativeCreate = getNative(Object, 'create'); + /** - * A specialized version of `_.indexOf` which performs strict equality - * comparisons of values, i.e. `===`. + * Removes all key-value entries from the hash. * * @private - * @param {Array} array The array to inspect. - * @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`. + * @name clear + * @memberOf Hash */ -function strictIndexOf(array, value, fromIndex) { - var index = fromIndex - 1, - length = array.length; - - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; +function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + this.size = 0; } /** - * The base implementation of `_.indexOf` without `fromIndex` bounds checks. + * Removes `key` and its value from the hash. * * @private - * @param {Array} array The array to inspect. - * @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`. + * @name delete + * @memberOf Hash + * @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 baseIndexOf(array, value, fromIndex) { - return value === value - ? strictIndexOf(array, value, fromIndex) - : baseFindIndex(array, baseIsNaN, fromIndex); +function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; } +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED$2 = '__lodash_hash_undefined__'; + +/** Used for built-in method references. */ +var objectProto$1 = Object.prototype; + +/** Used to check objects for own properties. */ +var hasOwnProperty$1 = objectProto$1.hasOwnProperty; + /** - * A specialized version of `_.includes` for arrays without support for - * specifying an index to search from. + * Gets the hash value for `key`. * * @private - * @param {Array} [array] The array to inspect. - * @param {*} target The value to search for. - * @returns {boolean} Returns `true` if `target` is found, else `false`. + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. */ -function arrayIncludes(array, value) { - var length = array == null ? 0 : array.length; - return !!length && baseIndexOf(array, value, 0) > -1; +function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED$2 ? undefined : result; + } + return hasOwnProperty$1.call(data, key) ? data[key] : undefined; } -/** Used as references for various `Number` constants. */ -var MAX_SAFE_INTEGER$1 = 9007199254740991; +/** Used for built-in method references. */ +var objectProto = Object.prototype; -/** Used to detect unsigned integer values. */ -var reIsUint = /^(?:0|[1-9]\d*)$/; +/** Used to check objects for own properties. */ +var hasOwnProperty = objectProto.hasOwnProperty; /** - * Checks if `value` is a valid array-like index. + * Checks if a hash value for `key` exists. * * @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`. + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ -function isIndex(value, length) { - var type = typeof value; - length = length == null ? MAX_SAFE_INTEGER$1 : length; +function hashHas(key) { + var data = this.__data__; + return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); +} - return !!length && - (type == 'number' || - (type != 'symbol' && reIsUint.test(value))) && - (value > -1 && value % 1 == 0 && value < length); +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED$1 = '__lodash_hash_undefined__'; + +/** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ +function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED$1 : value; + return this; } /** - * The base implementation of `assignValue` and `assignMergeValue` without - * value checks. + * Creates a hash object. * * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. + * @constructor + * @param {Array} [entries] The key-value pairs to cache. */ -function baseAssignValue(object, key, value) { - if (key == '__proto__' && defineProperty) { - defineProperty(object, key, { - 'configurable': true, - 'enumerable': true, - 'value': value, - 'writable': true - }); - } else { - object[key] = value; +function Hash(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); } } +// Add methods to `Hash`. +Hash.prototype.clear = hashClear; +Hash.prototype['delete'] = hashDelete; +Hash.prototype.get = hashGet; +Hash.prototype.has = hashHas; +Hash.prototype.set = hashSet; + /** - * Performs a - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.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 = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.eq(object, object); - * // => true - * - * _.eq(object, other); - * // => false - * - * _.eq('a', 'a'); - * // => true + * Removes all key-value entries from the list cache. * - * _.eq('a', Object('a')); - * // => false + * @private + * @name clear + * @memberOf ListCache + */ +function listCacheClear() { + this.__data__ = []; + this.size = 0; +} + +/** + * Gets the index at which the `key` is found in `array` of key-value pairs. * - * _.eq(NaN, NaN); - * // => true + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. */ -function eq(value, other) { - return value === other || (value !== value && other !== other); +function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; + } + } + return -1; } /** Used for built-in method references. */ -var objectProto$3 = Object.prototype; +var arrayProto = Array.prototype; -/** Used to check objects for own properties. */ -var hasOwnProperty$3 = objectProto$3.hasOwnProperty; +/** Built-in value references. */ +var splice = arrayProto.splice; /** - * Assigns `value` to `key` of `object` if the existing value is not equivalent - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. + * Removes `key` and its value from the list cache. * * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ -function assignValue(object, key, value) { - var objValue = object[key]; - if (!(hasOwnProperty$3.call(object, key) && eq(objValue, value)) || - (value === undefined && !(key in object))) { - baseAssignValue(object, key, value); +function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); } + --this.size; + return true; } -/* Built-in method references for those with the same name as other `lodash` methods. */ -var nativeMax = Math.max; - /** - * A specialized version of `baseRest` which transforms the rest array. + * Gets the list cache value for `key`. * * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @param {Function} transform The rest array transform. - * @returns {Function} Returns the new function. + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. */ -function overRest(func, start, transform) { - start = nativeMax(start === undefined ? (func.length - 1) : start, 0); - return function() { - var args = arguments, - index = -1, - length = nativeMax(args.length - start, 0), - array = Array(length); +function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); - while (++index < length) { - array[index] = args[start + index]; - } - index = -1; - var otherArgs = Array(start + 1); - while (++index < start) { - otherArgs[index] = args[index]; - } - otherArgs[start] = transform(array); - return apply(func, this, otherArgs); - }; + return index < 0 ? undefined : data[index][1]; } /** - * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * Checks if a list cache value for `key` exists. * * @private - * @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. + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ -function baseRest(func, start) { - return setToString(overRest(func, start, identity), func + ''); +function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; } -/** Used as references for various `Number` constants. */ -var MAX_SAFE_INTEGER = 9007199254740991; - /** - * Checks if `value` is a valid array-like length. + * Sets the list cache `key` to `value`. * - * **Note:** This method is loosely based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.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 + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. */ -function isLength(value) { - return typeof value == 'number' && - value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; -} +function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); -/** - * 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(value.length) && !isFunction(value); + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; } -/** `Object#toString` result references. */ -var argsTag = '[object Arguments]'; - /** - * The base implementation of `_.isArguments`. + * Creates an list cache object. * * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * @constructor + * @param {Array} [entries] The key-value pairs to cache. */ -function baseIsArguments(value) { - return isObjectLike(value) && baseGetTag(value) == argsTag; -} - -/** Used for built-in method references. */ -var objectProto$2 = Object.prototype; +function ListCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; -/** Used to check objects for own properties. */ -var hasOwnProperty$2 = objectProto$2.hasOwnProperty; + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } +} -/** Built-in value references. */ -var propertyIsEnumerable = objectProto$2.propertyIsEnumerable; +// Add methods to `ListCache`. +ListCache.prototype.clear = listCacheClear; +ListCache.prototype['delete'] = listCacheDelete; +ListCache.prototype.get = listCacheGet; +ListCache.prototype.has = listCacheHas; +ListCache.prototype.set = listCacheSet; -/** - * 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 an `arguments` object, - * else `false`. - * @example - * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ -var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { - return isObjectLike(value) && hasOwnProperty$2.call(value, 'callee') && - !propertyIsEnumerable.call(value, 'callee'); -}; +/* Built-in method references that are verified to be native. */ +var Map$1 = getNative(root, 'Map'); /** - * The base implementation of `_.unary` without support for storing metadata. + * Removes all key-value entries from the map. * * @private - * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new capped function. + * @name clear + * @memberOf MapCache */ -function baseUnary(func) { - return function(value) { - return func(value); +function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new Hash, + 'map': new (Map$1 || ListCache), + 'string': new Hash }; } -/** Detect free variable `exports`. */ -var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; - -/** Detect free variable `module`. */ -var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; - -/** Detect the popular CommonJS extension `module.exports`. */ -var moduleExports = freeModule && freeModule.exports === freeExports; - -/** Detect free variable `process` from Node.js. */ -var freeProcess = moduleExports && freeGlobal.process; - -/** Used to access faster Node.js helpers. */ -var nodeUtil = (function() { - try { - // Use `util.types` for Node.js 10+. - var types = freeModule && freeModule.require && freeModule.require('util').types; - - if (types) { - return types; - } - - // Legacy `process.binding('util')` for Node.js < 10. - return freeProcess && freeProcess.binding && freeProcess.binding('util'); - } catch (e) {} -}()); - -/** Used to match property names within property paths. */ -var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, - reIsPlainProp = /^\w*$/; - /** - * Checks if `value` is a property name and not a property path. + * Checks if `value` is suitable for use as unique object key. * * @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`. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. */ -function isKey(value, object) { - if (isArray(value)) { - return false; - } +function isKeyable(value) { 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)); + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); } -/* Built-in method references that are verified to be native. */ -var nativeCreate = getNative(Object, 'create'); - /** - * Removes all key-value entries from the hash. + * Gets the data for `map`. * * @private - * @name clear - * @memberOf Hash + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. */ -function hashClear() { - this.__data__ = nativeCreate ? nativeCreate(null) : {}; - this.size = 0; +function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; } /** - * Removes `key` and its value from the hash. + * Removes `key` and its value from the map. * * @private * @name delete - * @memberOf Hash - * @param {Object} hash The hash to modify. + * @memberOf MapCache * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ -function hashDelete(key) { - var result = this.has(key) && delete this.__data__[key]; +function mapCacheDelete(key) { + var result = getMapData(this, key)['delete'](key); this.size -= result ? 1 : 0; return result; } -/** Used to stand-in for `undefined` hash values. */ -var HASH_UNDEFINED$2 = '__lodash_hash_undefined__'; - -/** Used for built-in method references. */ -var objectProto$1 = Object.prototype; - -/** Used to check objects for own properties. */ -var hasOwnProperty$1 = objectProto$1.hasOwnProperty; - /** - * Gets the hash value for `key`. + * Gets the map value for `key`. * * @private * @name get - * @memberOf Hash + * @memberOf MapCache * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ -function hashGet(key) { - var data = this.__data__; - if (nativeCreate) { - var result = data[key]; - return result === HASH_UNDEFINED$2 ? undefined : result; - } - return hasOwnProperty$1.call(data, key) ? data[key] : undefined; +function mapCacheGet(key) { + return getMapData(this, key).get(key); } -/** Used for built-in method references. */ -var objectProto = Object.prototype; - -/** Used to check objects for own properties. */ -var hasOwnProperty = objectProto.hasOwnProperty; - /** - * Checks if a hash value for `key` exists. + * Checks if a map value for `key` exists. * * @private * @name has - * @memberOf Hash + * @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 hashHas(key) { - var data = this.__data__; - return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); +function mapCacheHas(key) { + return getMapData(this, key).has(key); } -/** Used to stand-in for `undefined` hash values. */ -var HASH_UNDEFINED$1 = '__lodash_hash_undefined__'; - /** - * Sets the hash `key` to `value`. + * Sets the map `key` to `value`. * * @private * @name set - * @memberOf Hash + * @memberOf MapCache * @param {string} key The key of the value to set. * @param {*} value The value to set. - * @returns {Object} Returns the hash instance. + * @returns {Object} Returns the map cache instance. */ -function hashSet(key, value) { - var data = this.__data__; - this.size += this.has(key) ? 0 : 1; - data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED$1 : value; +function mapCacheSet(key, value) { + var data = getMapData(this, key), + size = data.size; + + data.set(key, value); + this.size += data.size == size ? 0 : 1; return this; } /** - * Creates a hash object. + * Creates a map cache object to store key-value pairs. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ -function Hash(entries) { +function MapCache(entries) { var index = -1, length = entries == null ? 0 : entries.length; @@ -3109,1017 +2972,1162 @@ function Hash(entries) { } } -// Add methods to `Hash`. -Hash.prototype.clear = hashClear; -Hash.prototype['delete'] = hashDelete; -Hash.prototype.get = hashGet; -Hash.prototype.has = hashHas; -Hash.prototype.set = hashSet; +// Add methods to `MapCache`. +MapCache.prototype.clear = mapCacheClear; +MapCache.prototype['delete'] = mapCacheDelete; +MapCache.prototype.get = mapCacheGet; +MapCache.prototype.has = mapCacheHas; +MapCache.prototype.set = mapCacheSet; + +/** Error message constants. */ +var FUNC_ERROR_TEXT = 'Expected a function'; /** - * Removes all key-value entries from the list cache. + * 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. * - * @private - * @name clear - * @memberOf ListCache + * **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/7.0/#sec-properties-of-the-map-prototype-object) + * method interface of `clear`, `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 memoized 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 listCacheClear() { - this.__data__ = []; - this.size = 0; +function memoize(func, resolver) { + if (typeof func != 'function' || (resolver != null && 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) || cache; + return result; + }; + memoized.cache = new (memoize.Cache || MapCache); + return memoized; } +// Expose `MapCache`. +memoize.Cache = MapCache; + +/** Used as the maximum memoize cache size. */ +var MAX_MEMOIZE_SIZE = 500; + /** - * Gets the index at which the `key` is found in `array` of key-value pairs. + * A specialized version of `_.memoize` which clears the memoized function's + * cache when it exceeds `MAX_MEMOIZE_SIZE`. * * @private - * @param {Array} array The array to inspect. - * @param {*} key The key to search for. - * @returns {number} Returns the index of the matched value, else `-1`. + * @param {Function} func The function to have its output memoized. + * @returns {Function} Returns the new memoized function. */ -function assocIndexOf(array, key) { - var length = array.length; - while (length--) { - if (eq(array[length][0], key)) { - return length; +function memoizeCapped(func) { + var result = memoize(func, function(key) { + if (cache.size === MAX_MEMOIZE_SIZE) { + cache.clear(); } - } - return -1; + return key; + }); + + var cache = result.cache; + return result; } -/** Used for built-in method references. */ -var arrayProto = Array.prototype; +/** Used to match property names within property paths. */ +var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; -/** Built-in value references. */ -var splice = arrayProto.splice; +/** Used to match backslashes in property paths. */ +var reEscapeChar = /\\(\\)?/g; /** - * Removes `key` and its value from the list cache. + * Converts `string` to a property path array. * * @private - * @name delete - * @memberOf ListCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. + * @param {string} string The string to convert. + * @returns {Array} Returns the property path array. */ -function listCacheDelete(key) { - var data = this.__data__, - index = assocIndexOf(data, key); - - if (index < 0) { - return false; - } - var lastIndex = data.length - 1; - if (index == lastIndex) { - data.pop(); - } else { - splice.call(data, index, 1); +var stringToPath = memoizeCapped(function(string) { + var result = []; + if (string.charCodeAt(0) === 46 /* . */) { + result.push(''); } - --this.size; - return true; -} + string.replace(rePropName, function(match, number, quote, subString) { + result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; +}); /** - * Gets the list cache value for `key`. + * Converts `value` to a string. An empty string is returned for `null` + * and `undefined` values. The sign of `-0` is preserved. * - * @private - * @name get - * @memberOf ListCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.toString(null); + * // => '' + * + * _.toString(-0); + * // => '-0' + * + * _.toString([1, 2, 3]); + * // => '1,2,3' */ -function listCacheGet(key) { - var data = this.__data__, - index = assocIndexOf(data, key); - - return index < 0 ? undefined : data[index][1]; +function toString(value) { + return value == null ? '' : baseToString(value); } /** - * Checks if a list cache value for `key` exists. + * Casts `value` to a path array if it's not one. * * @private - * @name has - * @memberOf ListCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + * @param {*} value The value to inspect. + * @param {Object} [object] The object to query keys on. + * @returns {Array} Returns the cast property path array. */ -function listCacheHas(key) { - return assocIndexOf(this.__data__, key) > -1; +function castPath(value, object) { + if (isArray(value)) { + return value; + } + return isKey(value, object) ? [value] : stringToPath(toString(value)); } +/** Used as references for various `Number` constants. */ +var INFINITY = 1 / 0; + /** - * Sets the list cache `key` to `value`. + * Converts `value` to a string key if it's not a string or symbol. * * @private - * @name set - * @memberOf ListCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the list cache instance. + * @param {*} value The value to inspect. + * @returns {string|symbol} Returns the key. */ -function listCacheSet(key, value) { - var data = this.__data__, - index = assocIndexOf(data, key); - - if (index < 0) { - ++this.size; - data.push([key, value]); - } else { - data[index][1] = value; +function toKey(value) { + if (typeof value == 'string' || isSymbol(value)) { + return value; } - return this; + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; } /** - * Creates an list cache object. + * The base implementation of `_.get` without support for default values. * * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @returns {*} Returns the resolved value. */ -function ListCache(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; +function baseGet(object, path) { + path = castPath(path, object); + + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[toKey(path[index++])]; + } + return (index && index == length) ? object : undefined; +} + +/** + * 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; - this.clear(); while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); + array[offset + index] = values[index]; } + return array; } -// Add methods to `ListCache`. -ListCache.prototype.clear = listCacheClear; -ListCache.prototype['delete'] = listCacheDelete; -ListCache.prototype.get = listCacheGet; -ListCache.prototype.has = listCacheHas; -ListCache.prototype.set = listCacheSet; +/** Built-in value references. */ +var spreadableSymbol = Symbol$1 ? Symbol$1.isConcatSpreadable : undefined; -/* Built-in method references that are verified to be native. */ -var Map$1 = getNative(root, 'Map'); +/** + * 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 isArray(value) || isArguments(value) || + !!(spreadableSymbol && value && value[spreadableSymbol]); +} /** - * Removes all key-value entries from the map. + * The base implementation of `_.flatten` with support for restricting flattening. * * @private - * @name clear - * @memberOf MapCache + * @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 mapCacheClear() { - this.size = 0; - this.__data__ = { - 'hash': new Hash, - 'map': new (Map$1 || ListCache), - 'string': new Hash - }; +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; } /** - * Checks if `value` is suitable for use as unique object key. + * 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 == null ? 0 : array.length; + return length ? baseFlatten(array, 1) : []; +} + +/** + * A specialized version of `baseRest` which flattens the rest array. * * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + * @param {Function} func The function to apply a rest parameter to. + * @returns {Function} Returns the new function. */ -function isKeyable(value) { - var type = typeof value; - return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') - ? (value !== '__proto__') - : (value === null); +function flatRest(func) { + return setToString(overRest(func, undefined, flatten), func + ''); } +/** Used to stand-in for `undefined` hash values. */ +var HASH_UNDEFINED = '__lodash_hash_undefined__'; + /** - * Gets the data for `map`. + * Adds `value` to the array cache. * * @private - * @param {Object} map The map to query. - * @param {string} key The reference key. - * @returns {*} Returns the map data. + * @name add + * @memberOf SetCache + * @alias push + * @param {*} value The value to cache. + * @returns {Object} Returns the cache instance. */ -function getMapData(map, key) { - var data = map.__data__; - return isKeyable(key) - ? data[typeof key == 'string' ? 'string' : 'hash'] - : data.map; +function setCacheAdd(value) { + this.__data__.set(value, HASH_UNDEFINED); + return this; } /** - * Removes `key` and its value from the map. + * Checks if `value` is in the array cache. * * @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`. + * @name has + * @memberOf SetCache + * @param {*} value The value to search for. + * @returns {number} Returns `true` if `value` is found, else `false`. */ -function mapCacheDelete(key) { - var result = getMapData(this, key)['delete'](key); - this.size -= result ? 1 : 0; - return result; +function setCacheHas(value) { + return this.__data__.has(value); } /** - * Gets the map value for `key`. + * + * Creates an array cache object to store unique values. * * @private - * @name get - * @memberOf MapCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. + * @constructor + * @param {Array} [values] The values to cache. */ -function mapCacheGet(key) { - return getMapData(this, key).get(key); +function SetCache(values) { + var index = -1, + length = values == null ? 0 : values.length; + + this.__data__ = new MapCache; + while (++index < length) { + this.add(values[index]); + } } +// Add methods to `SetCache`. +SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; +SetCache.prototype.has = setCacheHas; + /** - * Checks if a map value for `key` exists. + * Checks if a `cache` value for `key` exists. * * @private - * @name has - * @memberOf MapCache + * @param {Object} cache The cache 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 mapCacheHas(key) { - return getMapData(this, key).has(key); +function cacheHas(cache, key) { + return cache.has(key); } /** - * Sets the map `key` to `value`. + * The base implementation of `_.hasIn` without support for deep paths. * * @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. + * @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 mapCacheSet(key, value) { - var data = getMapData(this, key), - size = data.size; - - data.set(key, value); - this.size += data.size == size ? 0 : 1; - return this; +function baseHasIn(object, key) { + return object != null && key in Object(object); } /** - * Creates a map cache object to store key-value pairs. + * Checks if `path` exists on `object`. * * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. + * @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 MapCache(entries) { +function hasPath(object, path, hasFunc) { + path = castPath(path, object); + var index = -1, - length = entries == null ? 0 : entries.length; + length = path.length, + result = false; - this.clear(); while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); + var key = toKey(path[index]); + if (!(result = object != null && hasFunc(object, key))) { + break; + } + object = object[key]; } + if (result || ++index != length) { + return result; + } + length = object == null ? 0 : object.length; + return !!length && isLength(length) && isIndex(key, length) && + (isArray(object) || isArguments(object)); } -// Add methods to `MapCache`. -MapCache.prototype.clear = mapCacheClear; -MapCache.prototype['delete'] = mapCacheDelete; -MapCache.prototype.get = mapCacheGet; -MapCache.prototype.has = mapCacheHas; -MapCache.prototype.set = mapCacheSet; - -/** Error message constants. */ -var FUNC_ERROR_TEXT = 'Expected a function'; - /** - * 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/7.0/#sec-properties-of-the-map-prototype-object) - * method interface of `clear`, `delete`, `get`, `has`, and `set`. + * Checks if `path` is a direct or inherited property of `object`. * * @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 memoized function. + * @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 = { 'a': 1, 'b': 2 }; - * var other = { 'c': 3, 'd': 4 }; - * - * var values = _.memoize(_.values); - * values(object); - * // => [1, 2] - * - * values(other); - * // => [3, 4] + * var object = _.create({ 'a': _.create({ 'b': 2 }) }); * - * object.a = 2; - * values(object); - * // => [1, 2] + * _.hasIn(object, 'a'); + * // => true * - * // Modify the result cache. - * values.cache.set(object, ['a', 'b']); - * values(object); - * // => ['a', 'b'] + * _.hasIn(object, 'a.b'); + * // => true * - * // Replace `_.memoize.Cache`. - * _.memoize.Cache = WeakMap; - */ -function memoize(func, resolver) { - if (typeof func != 'function' || (resolver != null && 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) || cache; - return result; - }; - memoized.cache = new (memoize.Cache || MapCache); - return memoized; -} - -// Expose `MapCache`. -memoize.Cache = MapCache; - -/** Used as the maximum memoize cache size. */ -var MAX_MEMOIZE_SIZE = 500; - -/** - * A specialized version of `_.memoize` which clears the memoized function's - * cache when it exceeds `MAX_MEMOIZE_SIZE`. + * _.hasIn(object, ['a', 'b']); + * // => true * - * @private - * @param {Function} func The function to have its output memoized. - * @returns {Function} Returns the new memoized function. + * _.hasIn(object, 'b'); + * // => false */ -function memoizeCapped(func) { - var result = memoize(func, function(key) { - if (cache.size === MAX_MEMOIZE_SIZE) { - cache.clear(); - } - return key; - }); - - var cache = result.cache; - return result; +function hasIn(object, path) { + return object != null && hasPath(object, path, baseHasIn); } -/** Used to match property names within property paths. */ -var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; - -/** Used to match backslashes in property paths. */ -var reEscapeChar = /\\(\\)?/g; - -/** - * Converts `string` to a property path array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the property path array. - */ -var stringToPath = memoizeCapped(function(string) { - var result = []; - if (string.charCodeAt(0) === 46 /* . */) { - result.push(''); - } - string.replace(rePropName, function(match, number, quote, subString) { - result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); - }); - return result; -}); - /** - * Converts `value` to a string. An empty string is returned for `null` - * and `undefined` values. The sign of `-0` is preserved. + * 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 convert. - * @returns {string} Returns the converted string. + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, + * else `false`. * @example * - * _.toString(null); - * // => '' - * - * _.toString(-0); - * // => '-0' + * _.isArrayLikeObject([1, 2, 3]); + * // => true * - * _.toString([1, 2, 3]); - * // => '1,2,3' - */ -function toString(value) { - return value == null ? '' : baseToString(value); -} - -/** - * Casts `value` to a path array if it's not one. + * _.isArrayLikeObject(document.body.children); + * // => true * - * @private - * @param {*} value The value to inspect. - * @param {Object} [object] The object to query keys on. - * @returns {Array} Returns the cast property path array. - */ -function castPath(value, object) { - if (isArray(value)) { - return value; - } - return isKey(value, object) ? [value] : stringToPath(toString(value)); -} - -/** Used as references for various `Number` constants. */ -var INFINITY = 1 / 0; - -/** - * Converts `value` to a string key if it's not a string or symbol. + * _.isArrayLikeObject('abc'); + * // => false * - * @private - * @param {*} value The value to inspect. - * @returns {string|symbol} Returns the key. + * _.isArrayLikeObject(_.noop); + * // => false */ -function toKey(value) { - if (typeof value == 'string' || isSymbol(value)) { - return value; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; +function isArrayLikeObject(value) { + return isObjectLike(value) && isArrayLike(value); } /** - * The base implementation of `_.get` without support for default values. + * This function is like `arrayIncludes` except that it accepts a comparator. * * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @returns {*} Returns the resolved value. + * @param {Array} [array] The array to inspect. + * @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 baseGet(object, path) { - path = castPath(path, object); - - var index = 0, - length = path.length; +function arrayIncludesWith(array, value, comparator) { + var index = -1, + length = array == null ? 0 : array.length; - while (object != null && index < length) { - object = object[toKey(path[index++])]; + while (++index < length) { + if (comparator(value, array[index])) { + return true; + } } - return (index && index == length) ? object : undefined; + return false; } +/** Used as the size to enable large array optimizations. */ +var LARGE_ARRAY_SIZE = 200; + /** - * Appends the elements of `values` to `array`. + * The base implementation of methods like `_.difference` without support + * for excluding multiple arrays or iteratee shorthands. * * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to append. - * @returns {Array} Returns `array`. + * @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 arrayPush(array, values) { +function baseDifference(array, values, iteratee, comparator) { var index = -1, - length = values.length, - offset = array.length; + 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) { - array[offset + index] = values[index]; + var value = array[index], + computed = iteratee == null ? value : iteratee(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 array; + return result; } -/** Built-in value references. */ -var spreadableSymbol = Symbol$1 ? Symbol$1.isConcatSpreadable : undefined; - /** - * Checks if `value` is a flattenable `arguments` object or array. + * Creates an array of `array` values not included in the other given arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. The order and references of result values are + * determined by the first array. * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. - */ -function isFlattenable(value) { - return isArray(value) || isArguments(value) || - !!(spreadableSymbol && value && value[spreadableSymbol]); -} - -/** - * The base implementation of `_.flatten` with support for restricting flattening. + * **Note:** Unlike `_.pullAll`, this method returns a new array. * - * @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. + * @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([2, 1], [2, 3]); + * // => [1] */ -function baseFlatten(array, depth, predicate, isStrict, result) { - var index = -1, - length = array.length; - - predicate || (predicate = isFlattenable); - result || (result = []); +var difference = baseRest(function(array, values) { + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) + : []; +}); - 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; -} +/** `Object#toString` result references. */ +var stringTag = '[object String]'; /** - * Flattens `array` a single level deep. + * Checks if `value` is classified as a `String` primitive or object. * * @static - * @memberOf _ * @since 0.1.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a string, else `false`. * @example * - * _.flatten([1, [2, [3, [4]], 5]]); - * // => [1, 2, [3, [4]], 5] + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false */ -function flatten(array) { - var length = array == null ? 0 : array.length; - return length ? baseFlatten(array, 1) : []; +function isString(value) { + return typeof value == 'string' || + (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); } +/** `Object#toString` result references. */ +var regexpTag = '[object RegExp]'; + /** - * A specialized version of `baseRest` which flattens the rest array. + * The base implementation of `_.isRegExp` without Node.js optimizations. * * @private - * @param {Function} func The function to apply a rest parameter to. - * @returns {Function} Returns the new function. + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. */ -function flatRest(func) { - return setToString(overRest(func, undefined, flatten), func + ''); +function baseIsRegExp(value) { + return isObjectLike(value) && baseGetTag(value) == regexpTag; } -/** Used to stand-in for `undefined` hash values. */ -var HASH_UNDEFINED = '__lodash_hash_undefined__'; +/* Node.js helper references. */ +var nodeIsRegExp = nodeUtil && nodeUtil.isRegExp; /** - * Adds `value` to the array cache. + * Checks if `value` is classified as a `RegExp` object. * - * @private - * @name add - * @memberOf SetCache - * @alias push - * @param {*} value The value to cache. - * @returns {Object} Returns the cache instance. + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. + * @example + * + * _.isRegExp(/abc/); + * // => true + * + * _.isRegExp('/abc/'); + * // => false */ -function setCacheAdd(value) { - this.__data__.set(value, HASH_UNDEFINED); - return this; -} +var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; /** - * Checks if `value` is in the array cache. + * The base implementation of `_.set`. * * @private - * @name has - * @memberOf SetCache - * @param {*} value The value to search for. - * @returns {number} Returns `true` if `value` is found, else `false`. + * @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 path creation. + * @returns {Object} Returns `object`. */ -function setCacheHas(value) { - return this.__data__.has(value); +function baseSet(object, path, value, customizer) { + if (!isObject(object)) { + return object; + } + path = castPath(path, object); + + var index = -1, + length = path.length, + lastIndex = length - 1, + nested = object; + + while (nested != null && ++index < length) { + var key = toKey(path[index]), + newValue = value; + + if (key === '__proto__' || key === 'constructor' || key === 'prototype') { + return object; + } + + if (index != lastIndex) { + var objValue = nested[key]; + newValue = customizer ? customizer(objValue, key, nested) : undefined; + if (newValue === undefined) { + newValue = isObject(objValue) + ? objValue + : (isIndex(path[index + 1]) ? [] : {}); + } + } + assignValue(nested, key, newValue); + nested = nested[key]; + } + return object; } /** - * - * Creates an array cache object to store unique values. + * The base implementation of `_.pickBy` without support for iteratee shorthands. * * @private - * @constructor - * @param {Array} [values] The values to cache. + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @param {Function} predicate The function invoked per property. + * @returns {Object} Returns the new object. */ -function SetCache(values) { +function basePickBy(object, paths, predicate) { var index = -1, - length = values == null ? 0 : values.length; + length = paths.length, + result = {}; - this.__data__ = new MapCache; while (++index < length) { - this.add(values[index]); + var path = paths[index], + value = baseGet(object, path); + + if (predicate(value, path)) { + baseSet(result, castPath(path, object), value); + } } + return result; } -// Add methods to `SetCache`. -SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; -SetCache.prototype.has = setCacheHas; - /** - * Checks if a `cache` value for `key` exists. + * The base implementation of `_.pick` without support for individual + * property identifiers. * * @private - * @param {Object} cache The cache to query. - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @returns {Object} Returns the new object. */ -function cacheHas(cache, key) { - return cache.has(key); +function basePick(object, paths) { + return basePickBy(object, paths, function(value, path) { + return hasIn(object, path); + }); } /** - * The base implementation of `_.hasIn` without support for deep paths. + * Creates an object composed of the picked `object` properties. * - * @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 object != null && key in Object(object); -} - -/** - * Checks if `path` exists on `object`. + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Object} Returns the new object. + * @example * - * @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`. + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pick(object, ['a', 'c']); + * // => { 'a': 1, 'c': 3 } */ -function hasPath(object, path, hasFunc) { - path = castPath(path, object); - - var index = -1, - length = path.length, - result = false; +var pick = flatRest(function(object, paths) { + return object == null ? {} : basePick(object, paths); +}); - while (++index < length) { - var key = toKey(path[index]); - if (!(result = object != null && hasFunc(object, key))) { - break; +class EventHub { + all = new Map(); + constructor(eventMap = {}, bindThis = null) { + this.bindThis = bindThis || globalThis; + this.on(eventMap); + + // 创建一个 rxjs 流源头 + this.createSource$ = memoize((eventName) => { + return fromEventPattern( + (handle) => this.on(eventName, handle), + (handle) => this.off(eventName, handle), + ); + }); + } + #on(type, handler) { + const handlers = this.all.get(type); + // ! 注意,栈的结构,这里要使用 unshift 将元素插入到头部,这样触发的时候才会最后执行最先声明的函数作为默认函数 + // 栈的结构可以保证 在 destroy 事件的时候,首先定义的 destroy 可以最后执行,保证后面绑定 destroy 事件的函数可以先触发,而在 destroy 的定义函数中可以最后 off('*') 解除事件 + handlers ? handlers.unshift(handler) : this.all.set(type, [handler]); + } + on(type, handler) { + // 函数重载 + if (typeof type === 'string') { + this.#on(type, handler); + } else if (type instanceof Object) { + // 在直接赋值为一个 + Object.entries(type).forEach(([key, value]) => { + if (value instanceof Array) { + value.forEach((item) => this.#on(key, item)); + } else { + this.#on(key, value); + } + }); + } + } + off(type, handler) { + if (type === '*') { + return this.all.clear(); + } else { + const handlers = this.all.get(type); + if (handlers) { + return handler ? handlers.splice(handlers.indexOf(handler) >>> 0, 1) : this.all.set(type, []); + } + return false; + } + } + emit(type, ...eventParams) { + console.log(type); + const handlers = this.all.get(type); + return handlers + ? handlers.map((handler) => { + return handler.apply(this.bindThis, eventParams); + }) + : []; } - object = object[key]; - } - if (result || ++index != length) { - return result; - } - length = object == null ? 0 : object.length; - return !!length && isLength(length) && isIndex(key, length) && - (isArray(object) || isArguments(object)); -} -/** - * 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); + operators = { + // TODO EventHub 中对于 rxjs 流的支持 + EmitWhen(config) {}, + }; } -/** - * 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); -} +const staticEvent$2 = {}; -/** - * This function is like `arrayIncludes` except that it accepts a comparator. - * - * @private - * @param {Array} [array] The array to inspect. - * @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 == null ? 0 : array.length; +// Unique ID creation requires a high quality random # generator. In the browser we therefore +// require the crypto API and do not support built-in fallback to lower quality random number +// generators (like Math.random()). +var getRandomValues; +var rnds8 = new Uint8Array(16); +function rng() { + // lazy load so that environments that need to polyfill have a chance to do so + if (!getRandomValues) { + // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also, + // find the complete implementation of crypto (msCrypto) on IE11. + getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto); - while (++index < length) { - if (comparator(value, array[index])) { - return true; + if (!getRandomValues) { + throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); } } - return false; + + return getRandomValues(rnds8); } -/** Used as the size to enable large array optimizations. */ -var LARGE_ARRAY_SIZE = 200; +var REGEX = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; + +function validate(uuid) { + return typeof uuid === 'string' && REGEX.test(uuid); +} /** - * 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. + * Convert array of 16 byte values to UUID string format of the form: + * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ -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)); +var byteToHex = []; + +for (var i = 0; i < 256; ++i) { + byteToHex.push((i + 0x100).toString(16).substr(1)); +} + +function stringify(arr) { + var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + // Note: Be careful editing this code! It's been tuned for performance + // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 + var uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one + // of the following: + // - One or more input array values don't map to a hex octet (leading to + // "undefined" in the uuid) + // - Invalid input values for the RFC `version` or `variant` fields + + if (!validate(uuid)) { + throw TypeError('Stringified UUID is invalid'); } - if (comparator) { - includes = arrayIncludesWith; - isCommon = false; + + return uuid; +} + +function parse(uuid) { + if (!validate(uuid)) { + throw TypeError('Invalid UUID'); } - else if (values.length >= LARGE_ARRAY_SIZE) { - includes = cacheHas; - isCommon = false; - values = new SetCache(values); + + var v; + var arr = new Uint8Array(16); // Parse ########-....-....-....-............ + + arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; + arr[1] = v >>> 16 & 0xff; + arr[2] = v >>> 8 & 0xff; + arr[3] = v & 0xff; // Parse ........-####-....-....-............ + + arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; + arr[5] = v & 0xff; // Parse ........-....-####-....-............ + + arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; + arr[7] = v & 0xff; // Parse ........-....-....-####-............ + + arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; + arr[9] = v & 0xff; // Parse ........-....-....-....-############ + // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes) + + arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff; + arr[11] = v / 0x100000000 & 0xff; + arr[12] = v >>> 24 & 0xff; + arr[13] = v >>> 16 & 0xff; + arr[14] = v >>> 8 & 0xff; + arr[15] = v & 0xff; + return arr; +} + +function stringToBytes(str) { + str = unescape(encodeURIComponent(str)); // UTF8 escape + + var bytes = []; + + for (var i = 0; i < str.length; ++i) { + bytes.push(str.charCodeAt(i)); } - outer: - while (++index < length) { - var value = array[index], - computed = iteratee == null ? value : iteratee(value); - value = (comparator || value !== 0) ? value : 0; - if (isCommon && computed === computed) { - var valuesIndex = valuesLength; - while (valuesIndex--) { - if (values[valuesIndex] === computed) { - continue outer; - } + return bytes; +} + +var DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; +var URL$1 = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; +function v35 (name, version, hashfunc) { + function generateUUID(value, namespace, buf, offset) { + if (typeof value === 'string') { + value = stringToBytes(value); + } + + if (typeof namespace === 'string') { + namespace = parse(namespace); + } + + if (namespace.length !== 16) { + throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); + } // Compute hash of namespace and value, Per 4.3 + // Future: Use spread syntax when supported on all platforms, e.g. `bytes = + // hashfunc([...namespace, ... value])` + + + var bytes = new Uint8Array(16 + value.length); + bytes.set(namespace); + bytes.set(value, namespace.length); + bytes = hashfunc(bytes); + bytes[6] = bytes[6] & 0x0f | version; + bytes[8] = bytes[8] & 0x3f | 0x80; + + if (buf) { + offset = offset || 0; + + for (var i = 0; i < 16; ++i) { + buf[offset + i] = bytes[i]; } - result.push(value); + + return buf; } - else if (!includes(values, computed, comparator)) { - result.push(value); + + return stringify(bytes); + } // Function#name is not settable on some platforms (#270) + + + try { + generateUUID.name = name; // eslint-disable-next-line no-empty + } catch (err) {} // For CommonJS default export support + + + generateUUID.DNS = DNS; + generateUUID.URL = URL$1; + return generateUUID; +} + +function v4(options, buf, offset) { + options = options || {}; + var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` + + rnds[6] = rnds[6] & 0x0f | 0x40; + rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided + + if (buf) { + offset = offset || 0; + + for (var i = 0; i < 16; ++i) { + buf[offset + i] = rnds[i]; } + + return buf; } - return result; + + return stringify(rnds); } -/** - * Creates an array of `array` values not included in the other given arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. The order and references of result values are - * determined by the first array. - * - * **Note:** Unlike `_.pullAll`, this method returns a new 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([2, 1], [2, 3]); - * // => [1] - */ -var difference = baseRest(function(array, values) { - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) - : []; -}); +// Adapted from Chris Veness' SHA1 code at +// http://www.movable-type.co.uk/scripts/sha1.html +function f(s, x, y, z) { + switch (s) { + case 0: + return x & y ^ ~x & z; -/** `Object#toString` result references. */ -var stringTag = '[object String]'; + case 1: + return x ^ y ^ z; -/** - * 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 a string, else `false`. - * @example - * - * _.isString('abc'); - * // => true - * - * _.isString(1); - * // => false - */ -function isString(value) { - return typeof value == 'string' || - (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); -} + case 2: + return x & y ^ x & z ^ y & z; -/** `Object#toString` result references. */ -var regexpTag = '[object RegExp]'; + case 3: + return x ^ y ^ z; + } +} -/** - * The base implementation of `_.isRegExp` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. - */ -function baseIsRegExp(value) { - return isObjectLike(value) && baseGetTag(value) == regexpTag; +function ROTL(x, n) { + return x << n | x >>> 32 - n; } -/* Node.js helper references. */ -var nodeIsRegExp = nodeUtil && nodeUtil.isRegExp; +function sha1(bytes) { + var K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]; + var H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; -/** - * 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 a regexp, else `false`. - * @example - * - * _.isRegExp(/abc/); - * // => true - * - * _.isRegExp('/abc/'); - * // => false - */ -var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; + if (typeof bytes === 'string') { + var msg = unescape(encodeURIComponent(bytes)); // UTF8 escape -/** - * The base implementation of `_.set`. - * - * @private - * @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 path creation. - * @returns {Object} Returns `object`. - */ -function baseSet(object, path, value, customizer) { - if (!isObject(object)) { - return object; + bytes = []; + + for (var i = 0; i < msg.length; ++i) { + bytes.push(msg.charCodeAt(i)); + } + } else if (!Array.isArray(bytes)) { + // Convert Array-like to Array + bytes = Array.prototype.slice.call(bytes); } - path = castPath(path, object); - var index = -1, - length = path.length, - lastIndex = length - 1, - nested = object; + bytes.push(0x80); + var l = bytes.length / 4 + 2; + var N = Math.ceil(l / 16); + var M = new Array(N); - while (nested != null && ++index < length) { - var key = toKey(path[index]), - newValue = value; + for (var _i = 0; _i < N; ++_i) { + var arr = new Uint32Array(16); - if (key === '__proto__' || key === 'constructor' || key === 'prototype') { - return object; + for (var j = 0; j < 16; ++j) { + arr[j] = bytes[_i * 64 + j * 4] << 24 | bytes[_i * 64 + j * 4 + 1] << 16 | bytes[_i * 64 + j * 4 + 2] << 8 | bytes[_i * 64 + j * 4 + 3]; } - if (index != lastIndex) { - var objValue = nested[key]; - newValue = customizer ? customizer(objValue, key, nested) : undefined; - if (newValue === undefined) { - newValue = isObject(objValue) - ? objValue - : (isIndex(path[index + 1]) ? [] : {}); - } + M[_i] = arr; + } + + M[N - 1][14] = (bytes.length - 1) * 8 / Math.pow(2, 32); + M[N - 1][14] = Math.floor(M[N - 1][14]); + M[N - 1][15] = (bytes.length - 1) * 8 & 0xffffffff; + + for (var _i2 = 0; _i2 < N; ++_i2) { + var W = new Uint32Array(80); + + for (var t = 0; t < 16; ++t) { + W[t] = M[_i2][t]; } - assignValue(nested, key, newValue); - nested = nested[key]; + + for (var _t = 16; _t < 80; ++_t) { + W[_t] = ROTL(W[_t - 3] ^ W[_t - 8] ^ W[_t - 14] ^ W[_t - 16], 1); + } + + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + + for (var _t2 = 0; _t2 < 80; ++_t2) { + var s = Math.floor(_t2 / 20); + var T = ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[_t2] >>> 0; + e = d; + d = c; + c = ROTL(b, 30) >>> 0; + b = a; + a = T; + } + + H[0] = H[0] + a >>> 0; + H[1] = H[1] + b >>> 0; + H[2] = H[2] + c >>> 0; + H[3] = H[3] + d >>> 0; + H[4] = H[4] + e >>> 0; } - return object; + + return [H[0] >> 24 & 0xff, H[0] >> 16 & 0xff, H[0] >> 8 & 0xff, H[0] & 0xff, H[1] >> 24 & 0xff, H[1] >> 16 & 0xff, H[1] >> 8 & 0xff, H[1] & 0xff, H[2] >> 24 & 0xff, H[2] >> 16 & 0xff, H[2] >> 8 & 0xff, H[2] & 0xff, H[3] >> 24 & 0xff, H[3] >> 16 & 0xff, H[3] >> 8 & 0xff, H[3] & 0xff, H[4] >> 24 & 0xff, H[4] >> 16 & 0xff, H[4] >> 8 & 0xff, H[4] & 0xff]; +} + +var v5 = v35('v5', 0x50, sha1); + +/* + * @Author: KonghaYao + * @Date: 2021-06-28 21:07:01 + * @Last Modified by: KonghaYao + * @Last Modified time: 2021-06-28 21:07:01 + */ + +function createUUID(string) { + return v5(string, v5.URL); } /** - * The base implementation of `_.pickBy` without support for iteratee shorthands. - * - * @private - * @param {Object} object The source object. - * @param {string[]} paths The property paths to pick. - * @param {Function} predicate The function invoked per property. - * @returns {Object} Returns the new object. + * 函数用途描述 + * 这个是用于 async 函数队列 连续执行的函数,只要 enQueue 之后就会连续执行,直至停止 */ -function basePickBy(object, paths, predicate) { - var index = -1, - length = paths.length, - result = {}; - while (++index < length) { - var path = paths[index], - value = baseGet(object, path); +class functionQueue { + QueuePromise = Promise.resolve(); + constructor() {} + enQueue(...args) { + this.QueuePromise = args.reduce((promise, current) => { + return promise.then(current); + }, this.QueuePromise); + return this; + } +} + +// Pipeline 是组合 Plugin 实例的工具类,用于创建一个可以不断提供 source 进行固定操作的功能对象。 +class Pipeline { + constructor(Plugins) { + this.Plugins = Plugins; + } + UUID = null; // 唯一的标识 + operator = null; // 主要被引用的 operator + + #PluginQueue = new functionQueue(); // 准备 Plugin 中的异步 init 事件 + preparePipeline() { + let uuidString = ''; + // ! 一次遍历实现取出 operator 和 导出 plugin init 函数的 promise 链,并延长 uuidString 用于创建 UUID + const pipeline = this.Plugins.map((plugin) => { + uuidString += plugin.operator.toString(); + + if (plugin.init instanceof Function) { + this.#PluginQueue.enQueue(plugin.init); + } + // 将 plugin 中的 operator 注入 pipeline 中 + return plugin.operator(this); + }); + this.operator = pipe(...pipeline); + + this.UUID = createUUID(uuidString); - if (predicate(value, path)) { - baseSet(result, castPath(path, object), value); + return this.#PluginQueue.QueuePromise; } - } - return result; } -/** - * The base implementation of `_.pick` without support for individual - * property identifiers. - * - * @private - * @param {Object} object The source object. - * @param {string[]} paths The property paths to pick. - * @returns {Object} Returns the new object. - */ -function basePick(object, paths) { - return basePickBy(object, paths, function(value, path) { - return hasIn(object, path); - }); -} +// 每个 Task 拥有的静态事件 +// 这些事件一般通过 $commit(eventName,payload) 进行执行 +// ! this 被绑定为 Task 的实例 +const staticEvent$1 = { + start(UUID) { + this._status = 'busy'; + // ! 这里会有一个清空这个 key 的 value 的情况,这是因为 start 是强制的 + this._progress.set(UUID, { process: 'start' }); -/** - * 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[])} [paths] The property paths 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 = flatRest(function(object, paths) { - return object == null ? {} : basePick(object, paths); -}); + return this._output || this._originData; + }, + success(output, UUID) { + this._status = 'free'; + this._progress.set(UUID, { process: 'success', output }); + this._output = output; + }, + complete(UUID) { + this._status = 'complete'; + }, + error(err, UUID) { + this._status = 'error'; + this._progress.set(UUID, { process: 'error', err }); + }, + destroy() { + this._process = []; + this._output = null; + this._belongTo = null; + this._originData = null; + this.$off('*'); + }, +}; // 装载信息的最小单元 @@ -4248,18 +4256,25 @@ var staticEvent = { stateChange(state) { this.state = state; }, - // runPipeline() {}, // 这个函数没有必要监听是因为 rxjs 代理了这个事件 - 'Task:success'(task) {}, - 'Task:error'(error) { - console.log(error); + 'Flow:stop'() { + this._stop = true; }, - 'Task:complete'() { + 'Flow:start'() { + this._stop = false; + }, + + // 'Flow:input'() {} + // 'Spider:clearFlow'(){} + 'Task:success'(task) { task.$commit('complete'); if (task instanceof TaskGroup) { task.$destroy(); } - console.log('所有情况完成'); }, + 'Task:error'(error) { + console.log(error); + }, + 'Task:complete'() {}, }; function createTaskViewModel(task) { @@ -4290,6 +4305,141 @@ class TaskManager { } } +function pauseToggle(openings, closings) { + return (observable) => + new Observable((subscriber) => { + const buffers = new Set(); + let closingSubscription = false; + const subscription = observable.subscribe( + (value) => { + closingSubscription ? buffers.add(value) : subscriber.next(value); + }, + noop, + () => { + buffers.forEach((item) => subscriber.next(item)); + subscriber.complete(); + }, + ); + const openingSubscription = openings.subscribe(() => { + // 输出所有的 buffer + const emitBuffer = () => { + buffers.forEach((item) => subscriber.next(item)); + buffers.clear(); + closingSubscription.unsubscribe(); + closingSubscription = false; + }; + closingSubscription = closings.subscribe(emitBuffer); + }); + return () => { + buffers.clear(); + subscription.unsubscribe(); + openingSubscription.unsubscribe(); + if (closingSubscription) closingSubscription.unsubscribe(); + }; + }); +} + +// ControlPanel 是 JSpider 内部的事件和数据中心。 +// 全部 JSpider 涉及到的边界中,ControlPanel 只有一个,但是 View 可以有多个,而 Spider 就是 View 中的一个 +// 用于分发数据流,提供 Task 的状态变更。 +// TODO 并且可以提供数据的响应给类似于 UI 界面形成可视化 + +class ControlPanel$1 { + state = 'free'; // 'free' 'preparing' + #runningQueue = new functionQueue(); // init 阶段的 Queue 队列 + _stop = false; // 用于直接切断 spiderSource$ 的流 + spiderSource$ = null; + _pipeline = null; + TaskManager = new TaskManager(); + constructor() { + this.$EventHub = new EventHub(staticEvent, this); + } + // ! 这是一个完整的流控 + _createLogicLine() { + this.spiderSource$ = this.$EventHub.createSource$('Flow:input').pipe( + pauseToggle( + this.$EventHub.createSource$('Flow:stop'), + + this.$EventHub.createSource$('Flow:start'), + ), + this._pipeline.operator, + ); + + this.spiderSource$.subscribe( + // 所有的事件分配到 staticEvent 中去写 + (task) => this.$EventHub.emit('Task:success', task), + (error) => this.$EventHub.emit('Task:error', error), + () => this.$EventHub.emit('Task:complete'), + ); + this.$EventHub.emit('Flow:stop'); + } + + set pipeline(value) { + if (this.state === 'free') { + this.$EventHub.emit('stateChange', 'preparing'); + this._pipeline = value; + this.#runningQueue.enQueue( + () => this._pipeline.preparePipeline(), + () => { + this.$EventHub.emit('Spider:clearFlow'); // 先注销流 + this._createLogicLine(); // 创建新流 + this.$EventHub.emit('stateChange', 'free'); + }, + ); + } else { + throw new Error('在运行阶段是不能够进行操作的哦'); + } + } + + // startInfo --TaskManager.createTask--> Task --emit--EventHub--> Flow + createFlow(infos) { + return this.#runningQueue.enQueue(() => { + infos.forEach((info) => { + if (!this._pipeline) throw new Error('没有创建pipeline'); + const task = this.TaskManager.createTask(info, this._pipeline.UUID); + this.$EventHub.emit('Flow:input', task); + }); + }); + } + startFlow() { + this.$EventHub.emit('Flow:start'); + } + // TODO 测试暂停功能 + stopFlow() { + this.$EventHub.emit('Flow:stop'); + } +} + +var ControlPanel = new ControlPanel$1(); + +/* + * @Author: KonghaYao + * @Date: 2021-07-13 15:33:08 + * @Last Modified by: KonghaYao + * @Last Modified time: 2021-07-19 16:34:32 + */ + +// TODO 未完成接口的接入 +class Spider { + constructor(config = {}) { + this.config = config; + this.$EventHub = new EventHub(staticEvent$2, this); // 注册静态事件 + } + crawl(...args) { + ControlPanel.createFlow(args.flat()); + return this; + } + pipeline(...plugins) { + ControlPanel.pipeline = new Pipeline(plugins); + } + start() { + ControlPanel.startFlow(); + } + stop() { + ControlPanel.stopFlow(); + } +} + /** PURE_IMPORTS_START tslib,_scheduler_async,_Subscriber,_util_isScheduler PURE_IMPORTS_END */ function bufferTime(bufferTimeSpan) { var length = arguments.length; @@ -4824,41 +4974,6 @@ var SwitchMapSubscriber = /*@__PURE__*/ (function (_super) { return SwitchMapSubscriber; }(SimpleOuterSubscriber)); -/** PURE_IMPORTS_START tslib,_innerSubscribe PURE_IMPORTS_END */ -function takeUntil(notifier) { - return function (source) { return source.lift(new TakeUntilOperator(notifier)); }; -} -var TakeUntilOperator = /*@__PURE__*/ (function () { - function TakeUntilOperator(notifier) { - this.notifier = notifier; - } - TakeUntilOperator.prototype.call = function (subscriber, source) { - var takeUntilSubscriber = new TakeUntilSubscriber(subscriber); - var notifierSubscription = innerSubscribe(this.notifier, new SimpleInnerSubscriber(takeUntilSubscriber)); - if (notifierSubscription && !takeUntilSubscriber.seenValue) { - takeUntilSubscriber.add(notifierSubscription); - return source.subscribe(takeUntilSubscriber); - } - return takeUntilSubscriber; - }; - return TakeUntilOperator; -}()); -var TakeUntilSubscriber = /*@__PURE__*/ (function (_super) { - __extends(TakeUntilSubscriber, _super); - function TakeUntilSubscriber(destination) { - var _this = _super.call(this, destination) || this; - _this.seenValue = false; - return _this; - } - TakeUntilSubscriber.prototype.notifyNext = function () { - this.seenValue = true; - this.complete(); - }; - TakeUntilSubscriber.prototype.notifyComplete = function () { - }; - return TakeUntilSubscriber; -}(SimpleOuterSubscriber)); - /** PURE_IMPORTS_START tslib,_Subscriber,_util_noop,_util_isFunction PURE_IMPORTS_END */ function tap(nextOrObserver, error, complete) { return function tapOperatorFunction(source) { @@ -4930,92 +5045,6 @@ var TapSubscriber = /*@__PURE__*/ (function (_super) { return TapSubscriber; }(Subscriber)); -// ControlPanel 是 JSpider 内部的事件和数据中心。 -// 全部 JSpider 涉及到的边界中,ControlPanel 只有一个,但是 View 可以有多个,而 Spider 就是 View 中的一个 -// 用于分发数据流,提供 Task 的状态变更。 -// TODO 并且可以提供数据的响应给类似于 UI 界面形成可视化 - -class ControlPanel$1 { - state = 'free'; // 'free' 'preparing' - #runningQueue = new functionQueue(); // 准备阶段的 Queue 队列 - #stopFlow = null; - _pipeline = null; - TaskManager = new TaskManager(); - constructor() { - this.$EventHub = new EventHub(staticEvent, this); - this.#stopFlow = this.$EventHub.createSource$('stopFlow'); - } - // 这是一个完整的流控 - _createLogicLine() { - this.spiderSource$ = this.$EventHub - .createSource$('runPipeline') - .pipe(this._pipeline.operator, takeUntil(this.#stopFlow)); - this.spiderSource$.subscribe( - // 所有的事件分配到 staticEvent 中去写 - (task) => this.$EventHub.emit('Task:success', task), - (error) => this.$EventHub.emit('Task:error', error), - () => this.$EventHub.emit('Task:complete'), - ); - } - - set pipeline(value) { - if (this.state === 'free') { - this.$EventHub.emit('stateChange', 'preparing'); - this._pipeline = value; - this.#runningQueue.enQueue( - () => this._pipeline.preparePipeline(), - () => { - this.$EventHub.emit('stopFlow'); // 先注销流 - this._createLogicLine(); // 创建新流 - this.$EventHub.emit('stateChange', 'free'); - }, - ); - } else { - throw new Error('在运行阶段是不能够进行操作的哦'); - } - } - - // startInfo --TaskManager.createTask--> Task --emit--EventHub--> Flow - createFlow(infos) { - this.#runningQueue.enQueue(() => { - infos.forEach((info) => { - if (!this._pipeline) throw new Error('没有创建pipeline'); - const task = this.TaskManager.createTask(info, this._pipeline.UUID); - this.$EventHub.emit('runPipeline', task); - }); - }); - } -} - -var ControlPanel = new ControlPanel$1(); - -/* - * @Author: KonghaYao - * @Date: 2021-07-13 15:33:08 - * @Last Modified by: KonghaYao - * @Last Modified time: 2021-07-18 09:43:40 - */ - -// TODO 未完成接口的接入 -class Spider { - infoList = []; - constructor(config = {}) { - this.config = config; - this.EventHub = new EventHub(staticEvent$2, this); // 注册静态事件 - } - crawl(...args) { - this.infoList.push(...args.flat()); - return this; - } - pipeline(...plugins) { - ControlPanel.pipeline = new Pipeline(plugins); - } - start() { - ControlPanel.createFlow(this.infoList); - } - stop() {} -} - // 在 JSpider 系统中的流发生了错误 // Plugin main 函数发生了错误 @@ -6047,7 +6076,7 @@ var index = Object.assign(Spider, tools, { Task, TaskGroup, version: "3.1.8", - buildDate: new Date(1626575076697), + buildDate: new Date(1626696870961), }); export default index; diff --git a/dist/JSpider.min.js b/dist/JSpider.min.js index 32f5941..948a5db 100644 --- a/dist/JSpider.min.js +++ b/dist/JSpider.min.js @@ -1639,1469 +1639,1332 @@ var JSpider = (function () { this.schedule(state, period); } - class EventHub { - all = new Map(); - constructor(eventMap = {}, bindThis = null) { - this.bindThis = bindThis || globalThis; - this.on(eventMap); - } - #on(type, handler) { - const handlers = this.all.get(type); - // ! 注意,栈的结构,这里要使用 unshift 将元素插入到头部,这样触发的时候才会最后执行最先声明的函数作为默认函数 - // 栈的结构可以保证 在 destroy 事件的时候,首先定义的 destroy 可以最后执行,保证后面绑定 destroy 事件的函数可以先触发,而在 destroy 的定义函数中可以最后 off('*') 解除事件 - handlers ? handlers.unshift(handler) : this.all.set(type, [handler]); - } - on(type, handler) { - // 函数重载 - if (typeof type === 'string') { - this.#on(type, handler); - } else if (type instanceof Object) { - // 在直接赋值为一个 - Object.entries(type).forEach(([key, value]) => { - if (value instanceof Array) { - value.forEach((item) => this.#on(key, item)); - } else { - this.#on(key, value); - } - }); - } - } - off(type, handler) { - if (type === '*') { - return this.all.clear(); - } else { - const handlers = this.all.get(type); - if (handlers) { - return handler ? handlers.splice(handlers.indexOf(handler) >>> 0, 1) : this.all.set(type, []); - } - return false; - } - } - emit(type, ...eventParams) { - const handlers = this.all.get(type); - return handlers - ? handlers.map((handler) => { - return handler.apply(this.bindThis, eventParams); - }) - : []; - } - // 创建一个 rxjs 流源头 - createSource$(eventName) { - return fromEventPattern( - (handle) => this.on(eventName, handle), - (handle) => this.off(eventName, handle), - ); - } - } - - const staticEvent$2 = {}; + /** Detect free variable `global` from Node.js. */ + var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - // Unique ID creation requires a high quality random # generator. In the browser we therefore - // require the crypto API and do not support built-in fallback to lower quality random number - // generators (like Math.random()). - var getRandomValues; - var rnds8 = new Uint8Array(16); - function rng() { - // lazy load so that environments that need to polyfill have a chance to do so - if (!getRandomValues) { - // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also, - // find the complete implementation of crypto (msCrypto) on IE11. - getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto); + /** Detect free variable `self`. */ + var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - if (!getRandomValues) { - throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); - } - } + /** Used as a reference to the global object. */ + var root = freeGlobal || freeSelf || Function('return this')(); - return getRandomValues(rnds8); - } + /** Built-in value references. */ + var Symbol$1 = root.Symbol; - var REGEX = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; + /** Used for built-in method references. */ + var objectProto$6 = Object.prototype; - function validate(uuid) { - return typeof uuid === 'string' && REGEX.test(uuid); - } + /** Used to check objects for own properties. */ + var hasOwnProperty$5 = objectProto$6.hasOwnProperty; /** - * Convert array of 16 byte values to UUID string format of the form: - * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. */ + var nativeObjectToString$1 = objectProto$6.toString; - var byteToHex = []; + /** Built-in value references. */ + var symToStringTag$1 = Symbol$1 ? Symbol$1.toStringTag : undefined; - for (var i = 0; i < 256; ++i) { - byteToHex.push((i + 0x100).toString(16).substr(1)); - } + /** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ + function getRawTag(value) { + var isOwn = hasOwnProperty$5.call(value, symToStringTag$1), + tag = value[symToStringTag$1]; - function stringify(arr) { - var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - // Note: Be careful editing this code! It's been tuned for performance - // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 - var uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one - // of the following: - // - One or more input array values don't map to a hex octet (leading to - // "undefined" in the uuid) - // - Invalid input values for the RFC `version` or `variant` fields + try { + value[symToStringTag$1] = undefined; + var unmasked = true; + } catch (e) {} - if (!validate(uuid)) { - throw TypeError('Stringified UUID is invalid'); + var result = nativeObjectToString$1.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag$1] = tag; + } else { + delete value[symToStringTag$1]; + } } - - return uuid; + return result; } - function parse(uuid) { - if (!validate(uuid)) { - throw TypeError('Invalid UUID'); - } - - var v; - var arr = new Uint8Array(16); // Parse ########-....-....-....-............ - - arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; - arr[1] = v >>> 16 & 0xff; - arr[2] = v >>> 8 & 0xff; - arr[3] = v & 0xff; // Parse ........-####-....-....-............ - - arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; - arr[5] = v & 0xff; // Parse ........-....-####-....-............ - - arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; - arr[7] = v & 0xff; // Parse ........-....-....-####-............ + /** Used for built-in method references. */ + var objectProto$5 = Object.prototype; - arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; - arr[9] = v & 0xff; // Parse ........-....-....-....-############ - // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes) + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString = objectProto$5.toString; - arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff; - arr[11] = v / 0x100000000 & 0xff; - arr[12] = v >>> 24 & 0xff; - arr[13] = v >>> 16 & 0xff; - arr[14] = v >>> 8 & 0xff; - arr[15] = v & 0xff; - return arr; + /** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ + function objectToString(value) { + return nativeObjectToString.call(value); } - function stringToBytes(str) { - str = unescape(encodeURIComponent(str)); // UTF8 escape + /** `Object#toString` result references. */ + var nullTag = '[object Null]', + undefinedTag = '[object Undefined]'; - var bytes = []; + /** Built-in value references. */ + var symToStringTag = Symbol$1 ? Symbol$1.toStringTag : undefined; - for (var i = 0; i < str.length; ++i) { - bytes.push(str.charCodeAt(i)); + /** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; } - - return bytes; + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); } - var DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; - var URL$1 = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; - function v35 (name, version, hashfunc) { - function generateUUID(value, namespace, buf, offset) { - if (typeof value === 'string') { - value = stringToBytes(value); - } - - if (typeof namespace === 'string') { - namespace = parse(namespace); - } - - if (namespace.length !== 16) { - throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); - } // Compute hash of namespace and value, Per 4.3 - // Future: Use spread syntax when supported on all platforms, e.g. `bytes = - // hashfunc([...namespace, ... value])` - + /** + * 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 != null && typeof value == 'object'; + } - var bytes = new Uint8Array(16 + value.length); - bytes.set(namespace); - bytes.set(value, namespace.length); - bytes = hashfunc(bytes); - bytes[6] = bytes[6] & 0x0f | version; - bytes[8] = bytes[8] & 0x3f | 0x80; + /** `Object#toString` result references. */ + var symbolTag = '[object Symbol]'; - if (buf) { - offset = offset || 0; - - for (var i = 0; i < 16; ++i) { - buf[offset + i] = bytes[i]; - } - - return buf; - } - - return stringify(bytes); - } // Function#name is not settable on some platforms (#270) - - - try { - generateUUID.name = name; // eslint-disable-next-line no-empty - } catch (err) {} // For CommonJS default export support - - - generateUUID.DNS = DNS; - generateUUID.URL = URL$1; - return generateUUID; + /** + * 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 a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ + function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && baseGetTag(value) == symbolTag); } - function v4(options, buf, offset) { - options = options || {}; - var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` - - rnds[6] = rnds[6] & 0x0f | 0x40; - rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided - - if (buf) { - offset = offset || 0; - - for (var i = 0; i < 16; ++i) { - buf[offset + i] = rnds[i]; - } + /** + * 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 == null ? 0 : array.length, + result = Array(length); - return buf; + while (++index < length) { + result[index] = iteratee(array[index], index, array); } - - return stringify(rnds); + return result; } - // Adapted from Chris Veness' SHA1 code at - // http://www.movable-type.co.uk/scripts/sha1.html - function f(s, x, y, z) { - switch (s) { - case 0: - return x & y ^ ~x & z; + /** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ + var isArray = Array.isArray; - case 1: - return x ^ y ^ z; + /** Used as references for various `Number` constants. */ + var INFINITY$1 = 1 / 0; - case 2: - return x & y ^ x & z ^ y & z; + /** Used to convert symbols to primitives and strings. */ + var symbolProto = Symbol$1 ? Symbol$1.prototype : undefined, + symbolToString = symbolProto ? symbolProto.toString : undefined; - case 3: - return x ^ y ^ z; + /** + * 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 (isArray(value)) { + // Recursively convert values (susceptible to call stack limits). + return arrayMap(value, baseToString) + ''; + } + if (isSymbol(value)) { + return symbolToString ? symbolToString.call(value) : ''; } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY$1) ? '-0' : result; } - function ROTL(x, n) { - return x << n | x >>> 32 - n; + /** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.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 != null && (type == 'object' || type == 'function'); } - function sha1(bytes) { - var K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]; - var H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; - - if (typeof bytes === 'string') { - var msg = unescape(encodeURIComponent(bytes)); // UTF8 escape + /** + * This method returns the first argument it receives. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Util + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'a': 1 }; + * + * console.log(_.identity(object) === object); + * // => true + */ + function identity(value) { + return value; + } - bytes = []; + /** `Object#toString` result references. */ + var asyncTag = '[object AsyncFunction]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + proxyTag = '[object Proxy]'; - for (var i = 0; i < msg.length; ++i) { - bytes.push(msg.charCodeAt(i)); - } - } else if (!Array.isArray(bytes)) { - // Convert Array-like to Array - bytes = Array.prototype.slice.call(bytes); + /** + * 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 a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ + function isFunction(value) { + if (!isObject(value)) { + return false; } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; + } - bytes.push(0x80); - var l = bytes.length / 4 + 2; - var N = Math.ceil(l / 16); - var M = new Array(N); + /** Used to detect overreaching core-js shims. */ + var coreJsData = root['__core-js_shared__']; - for (var _i = 0; _i < N; ++_i) { - var arr = new Uint32Array(16); + /** Used to detect methods masquerading as native. */ + var maskSrcKey = (function() { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; + }()); - for (var j = 0; j < 16; ++j) { - arr[j] = bytes[_i * 64 + j * 4] << 24 | bytes[_i * 64 + j * 4 + 1] << 16 | bytes[_i * 64 + j * 4 + 2] << 8 | bytes[_i * 64 + j * 4 + 3]; - } + /** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ + function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); + } - M[_i] = arr; - } + /** Used for built-in method references. */ + var funcProto$1 = Function.prototype; - M[N - 1][14] = (bytes.length - 1) * 8 / Math.pow(2, 32); - M[N - 1][14] = Math.floor(M[N - 1][14]); - M[N - 1][15] = (bytes.length - 1) * 8 & 0xffffffff; - - for (var _i2 = 0; _i2 < N; ++_i2) { - var W = new Uint32Array(80); - - for (var t = 0; t < 16; ++t) { - W[t] = M[_i2][t]; - } - - for (var _t = 16; _t < 80; ++_t) { - W[_t] = ROTL(W[_t - 3] ^ W[_t - 8] ^ W[_t - 14] ^ W[_t - 16], 1); - } - - var a = H[0]; - var b = H[1]; - var c = H[2]; - var d = H[3]; - var e = H[4]; - - for (var _t2 = 0; _t2 < 80; ++_t2) { - var s = Math.floor(_t2 / 20); - var T = ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[_t2] >>> 0; - e = d; - d = c; - c = ROTL(b, 30) >>> 0; - b = a; - a = T; - } - - H[0] = H[0] + a >>> 0; - H[1] = H[1] + b >>> 0; - H[2] = H[2] + c >>> 0; - H[3] = H[3] + d >>> 0; - H[4] = H[4] + e >>> 0; - } - - return [H[0] >> 24 & 0xff, H[0] >> 16 & 0xff, H[0] >> 8 & 0xff, H[0] & 0xff, H[1] >> 24 & 0xff, H[1] >> 16 & 0xff, H[1] >> 8 & 0xff, H[1] & 0xff, H[2] >> 24 & 0xff, H[2] >> 16 & 0xff, H[2] >> 8 & 0xff, H[2] & 0xff, H[3] >> 24 & 0xff, H[3] >> 16 & 0xff, H[3] >> 8 & 0xff, H[3] & 0xff, H[4] >> 24 & 0xff, H[4] >> 16 & 0xff, H[4] >> 8 & 0xff, H[4] & 0xff]; - } - - var v5 = v35('v5', 0x50, sha1); + /** Used to resolve the decompiled source of functions. */ + var funcToString$1 = funcProto$1.toString; - /* - * @Author: KonghaYao - * @Date: 2021-06-28 21:07:01 - * @Last Modified by: KonghaYao - * @Last Modified time: 2021-06-28 21:07:01 + /** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. */ - - function createUUID(string) { - return v5(string, v5.URL); + function toSource(func) { + if (func != null) { + try { + return funcToString$1.call(func); + } catch (e) {} + try { + return (func + ''); + } catch (e) {} + } + return ''; } /** - * 函数用途描述 - * 这个是用于 async 函数队列 连续执行的函数,只要 enQueue 之后就会连续执行,直至停止 + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). */ + var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; - class functionQueue { - QueuePromise = Promise.resolve(); - constructor() {} - enQueue(...args) { - this.QueuePromise = args.reduce((promise, current) => { - return promise.then(current); - }, this.QueuePromise); - } - } - - // Pipeline 是组合 Plugin 实例的工具类,用于创建一个可以不断提供 source 进行固定操作的功能对象。 - class Pipeline { - constructor(Plugins) { - this.Plugins = Plugins; - } - UUID = null; // 唯一的标识 - operator = null; // 主要被引用的 operator - - #PluginQueue = new functionQueue(); // 准备 Plugin 中的异步 init 事件 - preparePipeline() { - let uuidString = ''; - // ! 一次遍历实现取出 operator 和 导出 plugin init 函数的 promise 链,并延长 uuidString 用于创建 UUID - const pipeline = this.Plugins.map((plugin) => { - uuidString += plugin.operator.toString(); - - if (plugin.init instanceof Function) { - this.#PluginQueue.enQueue(plugin.init); - } - // 将 plugin 中的 operator 注入 pipeline 中 - return plugin.operator(this); - }); - this.operator = pipe(...pipeline); - - this.UUID = createUUID(uuidString); - - return this.#PluginQueue.QueuePromise; - } - } - - // 每个 Task 拥有的静态事件 - // 这些事件一般通过 $commit(eventName,payload) 进行执行 - // ! this 被绑定为 Task 的实例 - const staticEvent$1 = { - start(UUID) { - this._status = 'busy'; - // ! 这里会有一个清空这个 key 的 value 的情况,这是因为 start 是强制的 - this._progress.set(UUID, { process: 'start' }); - - return this._output || this._originData; - }, - success(output, UUID) { - this._status = 'free'; - this._progress.set(UUID, { process: 'success', output }); - this._output = output; - }, - complete(UUID) { - this._status = 'complete'; - }, - error(err, UUID) { - this._status = 'error'; - this._progress.set(UUID, { process: 'error', err }); - }, - destroy() { - this._process = []; - this._output = null; - this._belongTo = null; - this._originData = null; - this.$off('*'); - }, - }; - - /** Detect free variable `global` from Node.js. */ - var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - - /** Detect free variable `self`. */ - var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - - /** Used as a reference to the global object. */ - var root = freeGlobal || freeSelf || Function('return this')(); - - /** Built-in value references. */ - var Symbol$1 = root.Symbol; + /** Used to detect host constructors (Safari). */ + var reIsHostCtor = /^\[object .+?Constructor\]$/; /** Used for built-in method references. */ - var objectProto$6 = Object.prototype; + var funcProto = Function.prototype, + objectProto$4 = Object.prototype; - /** Used to check objects for own properties. */ - var hasOwnProperty$5 = objectProto$6.hasOwnProperty; + /** Used to resolve the decompiled source of functions. */ + var funcToString = funcProto.toString; - /** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ - var nativeObjectToString$1 = objectProto$6.toString; + /** Used to check objects for own properties. */ + var hasOwnProperty$4 = objectProto$4.hasOwnProperty; - /** Built-in value references. */ - var symToStringTag$1 = Symbol$1 ? Symbol$1.toStringTag : undefined; + /** Used to detect if a method is native. */ + var reIsNative = RegExp('^' + + funcToString.call(hasOwnProperty$4).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' + ); /** - * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * The base implementation of `_.isNative` without bad shim checks. * * @private - * @param {*} value The value to query. - * @returns {string} Returns the raw `toStringTag`. + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. */ - function getRawTag(value) { - var isOwn = hasOwnProperty$5.call(value, symToStringTag$1), - tag = value[symToStringTag$1]; - - try { - value[symToStringTag$1] = undefined; - var unmasked = true; - } catch (e) {} - - var result = nativeObjectToString$1.call(value); - if (unmasked) { - if (isOwn) { - value[symToStringTag$1] = tag; - } else { - delete value[symToStringTag$1]; - } + function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; } - return result; + var pattern = isFunction(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); } - /** Used for built-in method references. */ - var objectProto$5 = Object.prototype; - - /** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ - var nativeObjectToString = objectProto$5.toString; - /** - * Converts `value` to a string using `Object.prototype.toString`. + * Gets the value at `key` of `object`. * * @private - * @param {*} value The value to convert. - * @returns {string} Returns the converted string. + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. */ - function objectToString(value) { - return nativeObjectToString.call(value); + function getValue(object, key) { + return object == null ? undefined : object[key]; } - /** `Object#toString` result references. */ - var nullTag = '[object Null]', - undefinedTag = '[object Undefined]'; - - /** Built-in value references. */ - var symToStringTag = Symbol$1 ? Symbol$1.toStringTag : undefined; - /** - * The base implementation of `getTag` without fallbacks for buggy environments. + * Gets the native function at `key` of `object`. * * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. + * @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 baseGetTag(value) { - if (value == null) { - return value === undefined ? undefinedTag : nullTag; - } - return (symToStringTag && symToStringTag in Object(value)) - ? getRawTag(value) - : objectToString(value); + function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; } /** - * 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 + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. * - * _.isObjectLike(null); - * // => false + * @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 isObjectLike(value) { - return value != null && typeof value == 'object'; + function apply(func, thisArg, args) { + switch (args.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); } - /** `Object#toString` result references. */ - var symbolTag = '[object Symbol]'; + /** Used to detect hot functions by number of calls within a span of milliseconds. */ + var HOT_COUNT = 800, + HOT_SPAN = 16; - /** - * 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 a symbol, else `false`. - * @example - * - * _.isSymbol(Symbol.iterator); - * // => true - * - * _.isSymbol('abc'); - * // => false - */ - function isSymbol(value) { - return typeof value == 'symbol' || - (isObjectLike(value) && baseGetTag(value) == symbolTag); - } + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeNow = Date.now; /** - * A specialized version of `_.map` for arrays without support for iteratee - * shorthands. + * Creates a function that'll short out and invoke `identity` instead + * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` + * milliseconds. * * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new shortable function. */ - function arrayMap(array, iteratee) { - var index = -1, - length = array == null ? 0 : array.length, - result = Array(length); + function shortOut(func) { + var count = 0, + lastCalled = 0; - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; + return function() { + var stamp = nativeNow(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return arguments[0]; + } + } else { + count = 0; + } + return func.apply(undefined, arguments); + }; } /** - * Checks if `value` is classified as an `Array` object. + * Creates a function that returns `value`. * * @static * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @since 2.4.0 + * @category Util + * @param {*} value The value to return from the new function. + * @returns {Function} Returns the new constant function. * @example * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(document.body.children); - * // => false + * var objects = _.times(2, _.constant({ 'a': 1 })); * - * _.isArray('abc'); - * // => false + * console.log(objects); + * // => [{ 'a': 1 }, { 'a': 1 }] * - * _.isArray(_.noop); - * // => false + * console.log(objects[0] === objects[1]); + * // => true */ - var isArray = Array.isArray; - - /** Used as references for various `Number` constants. */ - var INFINITY$1 = 1 / 0; + function constant(value) { + return function() { + return value; + }; + } - /** Used to convert symbols to primitives and strings. */ - var symbolProto = Symbol$1 ? Symbol$1.prototype : undefined, - symbolToString = symbolProto ? symbolProto.toString : undefined; + var defineProperty = (function() { + try { + var func = getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) {} + }()); /** - * The base implementation of `_.toString` which doesn't convert nullish - * values to empty strings. + * The base implementation of `setToString` without support for hot loop shorting. * * @private - * @param {*} value The value to process. - * @returns {string} Returns the string. + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. */ - function baseToString(value) { - // Exit early for strings to avoid a performance hit in some environments. - if (typeof value == 'string') { - return value; - } - if (isArray(value)) { - // Recursively convert values (susceptible to call stack limits). - return arrayMap(value, baseToString) + ''; - } - if (isSymbol(value)) { - return symbolToString ? symbolToString.call(value) : ''; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY$1) ? '-0' : result; - } + var baseSetToString = !defineProperty ? identity : function(func, string) { + return defineProperty(func, 'toString', { + 'configurable': true, + 'enumerable': false, + 'value': constant(string), + 'writable': true + }); + }; /** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.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 + * Sets the `toString` method of `func` to return `string`. * - * _.isObject(_.noop); - * // => true + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ + var setToString = shortOut(baseSetToString); + + /** + * The base implementation of `_.findIndex` and `_.findLastIndex` without + * support for iteratee shorthands. * - * _.isObject(null); - * // => false + * @private + * @param {Array} array The array to inspect. + * @param {Function} predicate The function invoked per iteration. + * @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 value, else `-1`. */ - function isObject(value) { - var type = typeof value; - return value != null && (type == 'object' || type == 'function'); + function baseFindIndex(array, predicate, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 1 : -1); + + while ((fromRight ? index-- : ++index < length)) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; } /** - * This method returns the first argument it receives. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Util - * @param {*} value Any value. - * @returns {*} Returns `value`. - * @example - * - * var object = { 'a': 1 }; + * The base implementation of `_.isNaN` without support for number objects. * - * console.log(_.identity(object) === object); - * // => true + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. */ - function identity(value) { - return value; + function baseIsNaN(value) { + return value !== value; } - /** `Object#toString` result references. */ - var asyncTag = '[object AsyncFunction]', - funcTag = '[object Function]', - genTag = '[object GeneratorFunction]', - proxyTag = '[object Proxy]'; - /** - * Checks if `value` is classified as a `Function` object. + * A specialized version of `_.indexOf` which performs strict equality + * comparisons of values, i.e. `===`. * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false + * @private + * @param {Array} array The array to inspect. + * @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 isFunction(value) { - if (!isObject(value)) { - return false; + function strictIndexOf(array, value, fromIndex) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } } - // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 9 which returns 'object' for typed arrays and other constructors. - var tag = baseGetTag(value); - return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; + return -1; } - /** Used to detect overreaching core-js shims. */ - var coreJsData = root['__core-js_shared__']; - - /** Used to detect methods masquerading as native. */ - var maskSrcKey = (function() { - var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); - return uid ? ('Symbol(src)_1.' + uid) : ''; - }()); - /** - * Checks if `func` has its source masked. + * The base implementation of `_.indexOf` without `fromIndex` bounds checks. * * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` is masked, else `false`. + * @param {Array} array The array to inspect. + * @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 isMasked(func) { - return !!maskSrcKey && (maskSrcKey in func); + function baseIndexOf(array, value, fromIndex) { + return value === value + ? strictIndexOf(array, value, fromIndex) + : baseFindIndex(array, baseIsNaN, fromIndex); } - /** Used for built-in method references. */ - var funcProto$1 = Function.prototype; - - /** Used to resolve the decompiled source of functions. */ - var funcToString$1 = funcProto$1.toString; - /** - * Converts `func` to its source code. + * A specialized version of `_.includes` for arrays without support for + * specifying an index to search from. * * @private - * @param {Function} func The function to convert. - * @returns {string} Returns the source code. + * @param {Array} [array] The array to inspect. + * @param {*} target The value to search for. + * @returns {boolean} Returns `true` if `target` is found, else `false`. */ - function toSource(func) { - if (func != null) { - try { - return funcToString$1.call(func); - } catch (e) {} - try { - return (func + ''); - } catch (e) {} - } - return ''; + function arrayIncludes(array, value) { + var length = array == null ? 0 : array.length; + return !!length && baseIndexOf(array, value, 0) > -1; } - /** - * Used to match `RegExp` - * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). - */ - var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; - - /** Used to detect host constructors (Safari). */ - var reIsHostCtor = /^\[object .+?Constructor\]$/; - - /** Used for built-in method references. */ - var funcProto = Function.prototype, - objectProto$4 = Object.prototype; - - /** Used to resolve the decompiled source of functions. */ - var funcToString = funcProto.toString; - - /** Used to check objects for own properties. */ - var hasOwnProperty$4 = objectProto$4.hasOwnProperty; + /** Used as references for various `Number` constants. */ + var MAX_SAFE_INTEGER$1 = 9007199254740991; - /** Used to detect if a method is native. */ - var reIsNative = RegExp('^' + - funcToString.call(hasOwnProperty$4).replace(reRegExpChar, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' - ); + /** Used to detect unsigned integer values. */ + var reIsUint = /^(?:0|[1-9]\d*)$/; /** - * The base implementation of `_.isNative` without bad shim checks. + * Checks if `value` is a valid array-like index. * * @private * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, - * else `false`. + * @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 baseIsNative(value) { - if (!isObject(value) || isMasked(value)) { - return false; - } - var pattern = isFunction(value) ? reIsNative : reIsHostCtor; - return pattern.test(toSource(value)); + function isIndex(value, length) { + var type = typeof value; + length = length == null ? MAX_SAFE_INTEGER$1 : length; + + return !!length && + (type == 'number' || + (type != 'symbol' && reIsUint.test(value))) && + (value > -1 && value % 1 == 0 && value < length); } /** - * Gets the value at `key` of `object`. + * The base implementation of `assignValue` and `assignMergeValue` without + * value checks. * * @private - * @param {Object} [object] The object to query. - * @param {string} key The key of the property to get. - * @returns {*} Returns the property value. + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. */ - function getValue(object, key) { - return object == null ? undefined : object[key]; + function baseAssignValue(object, key, value) { + if (key == '__proto__' && defineProperty) { + defineProperty(object, key, { + 'configurable': true, + 'enumerable': true, + 'value': value, + 'writable': true + }); + } else { + object[key] = value; + } } /** - * Gets the native function at `key` of `object`. + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. * - * @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`. + * @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 = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true */ - function getNative(object, key) { - var value = getValue(object, key); - return baseIsNative(value) ? value : undefined; + function eq(value, other) { + return value === other || (value !== value && other !== other); } + /** Used for built-in method references. */ + var objectProto$3 = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty$3 = objectProto$3.hasOwnProperty; + /** - * A faster alternative to `Function#apply`, this function invokes `func` - * with the `this` binding of `thisArg` and the arguments of `args`. + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. * * @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`. + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. */ - function apply(func, thisArg, args) { - switch (args.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]); + function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty$3.call(object, key) && eq(objValue, value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); } - return func.apply(thisArg, args); } - /** Used to detect hot functions by number of calls within a span of milliseconds. */ - var HOT_COUNT = 800, - HOT_SPAN = 16; - /* Built-in method references for those with the same name as other `lodash` methods. */ - var nativeNow = Date.now; + var nativeMax = Math.max; /** - * Creates a function that'll short out and invoke `identity` instead - * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` - * milliseconds. + * A specialized version of `baseRest` which transforms the rest array. * * @private - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new shortable 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. + * @param {Function} transform The rest array transform. + * @returns {Function} Returns the new function. */ - function shortOut(func) { - var count = 0, - lastCalled = 0; - + function overRest(func, start, transform) { + start = nativeMax(start === undefined ? (func.length - 1) : start, 0); return function() { - var stamp = nativeNow(), - remaining = HOT_SPAN - (stamp - lastCalled); + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + array = Array(length); - lastCalled = stamp; - if (remaining > 0) { - if (++count >= HOT_COUNT) { - return arguments[0]; - } - } else { - count = 0; + while (++index < length) { + array[index] = args[start + index]; } - return func.apply(undefined, arguments); + index = -1; + var otherArgs = Array(start + 1); + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = transform(array); + return apply(func, this, otherArgs); }; } /** - * Creates a function that returns `value`. + * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * + * @private + * @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. + */ + function baseRest(func, start) { + return setToString(overRest(func, start, identity), func + ''); + } + + /** Used as references for various `Number` constants. */ + var MAX_SAFE_INTEGER = 9007199254740991; + + /** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). * * @static * @memberOf _ - * @since 2.4.0 - * @category Util - * @param {*} value The value to return from the new function. - * @returns {Function} Returns the new constant function. + * @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 * - * var objects = _.times(2, _.constant({ 'a': 1 })); + * _.isLength(3); + * // => true * - * console.log(objects); - * // => [{ 'a': 1 }, { 'a': 1 }] + * _.isLength(Number.MIN_VALUE); + * // => false * - * console.log(objects[0] === objects[1]); + * _.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 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 constant(value) { - return function() { - return value; - }; + function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); } - var defineProperty = (function() { - try { - var func = getNative(Object, 'defineProperty'); - func({}, '', {}); - return func; - } catch (e) {} - }()); + /** `Object#toString` result references. */ + var argsTag = '[object Arguments]'; /** - * The base implementation of `setToString` without support for hot loop shorting. + * The base implementation of `_.isArguments`. * * @private - * @param {Function} func The function to modify. - * @param {Function} string The `toString` result. - * @returns {Function} Returns `func`. + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, */ - var baseSetToString = !defineProperty ? identity : function(func, string) { - return defineProperty(func, 'toString', { - 'configurable': true, - 'enumerable': false, - 'value': constant(string), - 'writable': true - }); - }; + function baseIsArguments(value) { + return isObjectLike(value) && baseGetTag(value) == argsTag; + } + + /** Used for built-in method references. */ + var objectProto$2 = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty$2 = objectProto$2.hasOwnProperty; + + /** Built-in value references. */ + var propertyIsEnumerable = objectProto$2.propertyIsEnumerable; /** - * Sets the `toString` method of `func` to return `string`. + * Checks if `value` is likely an `arguments` object. * - * @private - * @param {Function} func The function to modify. - * @param {Function} string The `toString` result. - * @returns {Function} Returns `func`. + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false */ - var setToString = shortOut(baseSetToString); + var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty$2.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); + }; /** - * The base implementation of `_.findIndex` and `_.findLastIndex` without - * support for iteratee shorthands. + * The base implementation of `_.unary` without support for storing metadata. * * @private - * @param {Array} array The array to inspect. - * @param {Function} predicate The function invoked per iteration. - * @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 value, else `-1`. + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. */ - function baseFindIndex(array, predicate, fromIndex, fromRight) { - var length = array.length, - index = fromIndex + (fromRight ? 1 : -1); + function baseUnary(func) { + return function(value) { + return func(value); + }; + } - while ((fromRight ? index-- : ++index < length)) { - if (predicate(array[index], index, array)) { - return index; + /** Detect free variable `exports`. */ + var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + + /** Detect free variable `module`. */ + var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + + /** Detect the popular CommonJS extension `module.exports`. */ + var moduleExports = freeModule && freeModule.exports === freeExports; + + /** Detect free variable `process` from Node.js. */ + var freeProcess = moduleExports && freeGlobal.process; + + /** Used to access faster Node.js helpers. */ + var nodeUtil = (function() { + try { + // Use `util.types` for Node.js 10+. + var types = freeModule && freeModule.require && freeModule.require('util').types; + + if (types) { + return types; } - } - return -1; - } + + // Legacy `process.binding('util')` for Node.js < 10. + return freeProcess && freeProcess.binding && freeProcess.binding('util'); + } catch (e) {} + }()); + + /** Used to match property names within property paths. */ + var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/; /** - * The base implementation of `_.isNaN` without support for number objects. + * Checks if `value` is a property name and not a property path. * * @private * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. */ - function baseIsNaN(value) { - return value !== value; + 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)); } + /* Built-in method references that are verified to be native. */ + var nativeCreate = getNative(Object, 'create'); + /** - * A specialized version of `_.indexOf` which performs strict equality - * comparisons of values, i.e. `===`. + * Removes all key-value entries from the hash. * * @private - * @param {Array} array The array to inspect. - * @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`. + * @name clear + * @memberOf Hash */ - function strictIndexOf(array, value, fromIndex) { - var index = fromIndex - 1, - length = array.length; - - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; + function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + this.size = 0; } /** - * The base implementation of `_.indexOf` without `fromIndex` bounds checks. + * Removes `key` and its value from the hash. * * @private - * @param {Array} array The array to inspect. - * @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`. + * @name delete + * @memberOf Hash + * @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 baseIndexOf(array, value, fromIndex) { - return value === value - ? strictIndexOf(array, value, fromIndex) - : baseFindIndex(array, baseIsNaN, fromIndex); + function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; } + /** Used to stand-in for `undefined` hash values. */ + var HASH_UNDEFINED$2 = '__lodash_hash_undefined__'; + + /** Used for built-in method references. */ + var objectProto$1 = Object.prototype; + + /** Used to check objects for own properties. */ + var hasOwnProperty$1 = objectProto$1.hasOwnProperty; + /** - * A specialized version of `_.includes` for arrays without support for - * specifying an index to search from. + * Gets the hash value for `key`. * * @private - * @param {Array} [array] The array to inspect. - * @param {*} target The value to search for. - * @returns {boolean} Returns `true` if `target` is found, else `false`. + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. */ - function arrayIncludes(array, value) { - var length = array == null ? 0 : array.length; - return !!length && baseIndexOf(array, value, 0) > -1; + function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED$2 ? undefined : result; + } + return hasOwnProperty$1.call(data, key) ? data[key] : undefined; } - /** Used as references for various `Number` constants. */ - var MAX_SAFE_INTEGER$1 = 9007199254740991; + /** Used for built-in method references. */ + var objectProto = Object.prototype; - /** Used to detect unsigned integer values. */ - var reIsUint = /^(?:0|[1-9]\d*)$/; + /** Used to check objects for own properties. */ + var hasOwnProperty = objectProto.hasOwnProperty; /** - * Checks if `value` is a valid array-like index. + * Checks if a hash value for `key` exists. * * @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`. + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ - function isIndex(value, length) { - var type = typeof value; - length = length == null ? MAX_SAFE_INTEGER$1 : length; + function hashHas(key) { + var data = this.__data__; + return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); + } - return !!length && - (type == 'number' || - (type != 'symbol' && reIsUint.test(value))) && - (value > -1 && value % 1 == 0 && value < length); + /** Used to stand-in for `undefined` hash values. */ + var HASH_UNDEFINED$1 = '__lodash_hash_undefined__'; + + /** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ + function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED$1 : value; + return this; } /** - * The base implementation of `assignValue` and `assignMergeValue` without - * value checks. + * Creates a hash object. * * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. + * @constructor + * @param {Array} [entries] The key-value pairs to cache. */ - function baseAssignValue(object, key, value) { - if (key == '__proto__' && defineProperty) { - defineProperty(object, key, { - 'configurable': true, - 'enumerable': true, - 'value': value, - 'writable': true - }); - } else { - object[key] = value; + function Hash(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); } } + // Add methods to `Hash`. + Hash.prototype.clear = hashClear; + Hash.prototype['delete'] = hashDelete; + Hash.prototype.get = hashGet; + Hash.prototype.has = hashHas; + Hash.prototype.set = hashSet; + /** - * Performs a - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.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 = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.eq(object, object); - * // => true - * - * _.eq(object, other); - * // => false - * - * _.eq('a', 'a'); - * // => true + * Removes all key-value entries from the list cache. * - * _.eq('a', Object('a')); - * // => false + * @private + * @name clear + * @memberOf ListCache + */ + function listCacheClear() { + this.__data__ = []; + this.size = 0; + } + + /** + * Gets the index at which the `key` is found in `array` of key-value pairs. * - * _.eq(NaN, NaN); - * // => true + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. */ - function eq(value, other) { - return value === other || (value !== value && other !== other); + function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; + } + } + return -1; } /** Used for built-in method references. */ - var objectProto$3 = Object.prototype; + var arrayProto = Array.prototype; - /** Used to check objects for own properties. */ - var hasOwnProperty$3 = objectProto$3.hasOwnProperty; + /** Built-in value references. */ + var splice = arrayProto.splice; /** - * Assigns `value` to `key` of `object` if the existing value is not equivalent - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. + * Removes `key` and its value from the list cache. * * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ - function assignValue(object, key, value) { - var objValue = object[key]; - if (!(hasOwnProperty$3.call(object, key) && eq(objValue, value)) || - (value === undefined && !(key in object))) { - baseAssignValue(object, key, value); + function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); } + --this.size; + return true; } - /* Built-in method references for those with the same name as other `lodash` methods. */ - var nativeMax = Math.max; - /** - * A specialized version of `baseRest` which transforms the rest array. + * Gets the list cache value for `key`. * * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @param {Function} transform The rest array transform. - * @returns {Function} Returns the new function. + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. */ - function overRest(func, start, transform) { - start = nativeMax(start === undefined ? (func.length - 1) : start, 0); - return function() { - var args = arguments, - index = -1, - length = nativeMax(args.length - start, 0), - array = Array(length); + function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); - while (++index < length) { - array[index] = args[start + index]; - } - index = -1; - var otherArgs = Array(start + 1); - while (++index < start) { - otherArgs[index] = args[index]; - } - otherArgs[start] = transform(array); - return apply(func, this, otherArgs); - }; + return index < 0 ? undefined : data[index][1]; } /** - * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * Checks if a list cache value for `key` exists. * * @private - * @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. + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ - function baseRest(func, start) { - return setToString(overRest(func, start, identity), func + ''); + function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; } - /** Used as references for various `Number` constants. */ - var MAX_SAFE_INTEGER = 9007199254740991; - /** - * Checks if `value` is a valid array-like length. + * Sets the list cache `key` to `value`. * - * **Note:** This method is loosely based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.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 + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. */ - function isLength(value) { - return typeof value == 'number' && - value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; - } + function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); - /** - * 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(value.length) && !isFunction(value); + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; } - /** `Object#toString` result references. */ - var argsTag = '[object Arguments]'; - /** - * The base implementation of `_.isArguments`. + * Creates an list cache object. * * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * @constructor + * @param {Array} [entries] The key-value pairs to cache. */ - function baseIsArguments(value) { - return isObjectLike(value) && baseGetTag(value) == argsTag; - } - - /** Used for built-in method references. */ - var objectProto$2 = Object.prototype; + function ListCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; - /** Used to check objects for own properties. */ - var hasOwnProperty$2 = objectProto$2.hasOwnProperty; + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } - /** Built-in value references. */ - var propertyIsEnumerable = objectProto$2.propertyIsEnumerable; + // Add methods to `ListCache`. + ListCache.prototype.clear = listCacheClear; + ListCache.prototype['delete'] = listCacheDelete; + ListCache.prototype.get = listCacheGet; + ListCache.prototype.has = listCacheHas; + ListCache.prototype.set = listCacheSet; - /** - * 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 an `arguments` object, - * else `false`. - * @example - * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ - var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { - return isObjectLike(value) && hasOwnProperty$2.call(value, 'callee') && - !propertyIsEnumerable.call(value, 'callee'); - }; + /* Built-in method references that are verified to be native. */ + var Map$1 = getNative(root, 'Map'); /** - * The base implementation of `_.unary` without support for storing metadata. + * Removes all key-value entries from the map. * * @private - * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new capped function. + * @name clear + * @memberOf MapCache */ - function baseUnary(func) { - return function(value) { - return func(value); + function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new Hash, + 'map': new (Map$1 || ListCache), + 'string': new Hash }; } - /** Detect free variable `exports`. */ - var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; - - /** Detect free variable `module`. */ - var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; - - /** Detect the popular CommonJS extension `module.exports`. */ - var moduleExports = freeModule && freeModule.exports === freeExports; - - /** Detect free variable `process` from Node.js. */ - var freeProcess = moduleExports && freeGlobal.process; - - /** Used to access faster Node.js helpers. */ - var nodeUtil = (function() { - try { - // Use `util.types` for Node.js 10+. - var types = freeModule && freeModule.require && freeModule.require('util').types; - - if (types) { - return types; - } - - // Legacy `process.binding('util')` for Node.js < 10. - return freeProcess && freeProcess.binding && freeProcess.binding('util'); - } catch (e) {} - }()); - - /** Used to match property names within property paths. */ - var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, - reIsPlainProp = /^\w*$/; - /** - * Checks if `value` is a property name and not a property path. + * Checks if `value` is suitable for use as unique object key. * * @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`. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. */ - function isKey(value, object) { - if (isArray(value)) { - return false; - } + function isKeyable(value) { 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)); + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); } - /* Built-in method references that are verified to be native. */ - var nativeCreate = getNative(Object, 'create'); - /** - * Removes all key-value entries from the hash. + * Gets the data for `map`. * * @private - * @name clear - * @memberOf Hash + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. */ - function hashClear() { - this.__data__ = nativeCreate ? nativeCreate(null) : {}; - this.size = 0; + function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; } /** - * Removes `key` and its value from the hash. + * Removes `key` and its value from the map. * * @private * @name delete - * @memberOf Hash - * @param {Object} hash The hash to modify. + * @memberOf MapCache * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed, else `false`. */ - function hashDelete(key) { - var result = this.has(key) && delete this.__data__[key]; + function mapCacheDelete(key) { + var result = getMapData(this, key)['delete'](key); this.size -= result ? 1 : 0; return result; } - /** Used to stand-in for `undefined` hash values. */ - var HASH_UNDEFINED$2 = '__lodash_hash_undefined__'; - - /** Used for built-in method references. */ - var objectProto$1 = Object.prototype; - - /** Used to check objects for own properties. */ - var hasOwnProperty$1 = objectProto$1.hasOwnProperty; - /** - * Gets the hash value for `key`. + * Gets the map value for `key`. * * @private * @name get - * @memberOf Hash + * @memberOf MapCache * @param {string} key The key of the value to get. * @returns {*} Returns the entry value. */ - function hashGet(key) { - var data = this.__data__; - if (nativeCreate) { - var result = data[key]; - return result === HASH_UNDEFINED$2 ? undefined : result; - } - return hasOwnProperty$1.call(data, key) ? data[key] : undefined; + function mapCacheGet(key) { + return getMapData(this, key).get(key); } - /** Used for built-in method references. */ - var objectProto = Object.prototype; - - /** Used to check objects for own properties. */ - var hasOwnProperty = objectProto.hasOwnProperty; - /** - * Checks if a hash value for `key` exists. + * Checks if a map value for `key` exists. * * @private * @name has - * @memberOf Hash + * @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 hashHas(key) { - var data = this.__data__; - return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); + function mapCacheHas(key) { + return getMapData(this, key).has(key); } - /** Used to stand-in for `undefined` hash values. */ - var HASH_UNDEFINED$1 = '__lodash_hash_undefined__'; - /** - * Sets the hash `key` to `value`. + * Sets the map `key` to `value`. * * @private * @name set - * @memberOf Hash + * @memberOf MapCache * @param {string} key The key of the value to set. * @param {*} value The value to set. - * @returns {Object} Returns the hash instance. + * @returns {Object} Returns the map cache instance. */ - function hashSet(key, value) { - var data = this.__data__; - this.size += this.has(key) ? 0 : 1; - data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED$1 : value; + function mapCacheSet(key, value) { + var data = getMapData(this, key), + size = data.size; + + data.set(key, value); + this.size += data.size == size ? 0 : 1; return this; } /** - * Creates a hash object. + * Creates a map cache object to store key-value pairs. * * @private * @constructor * @param {Array} [entries] The key-value pairs to cache. */ - function Hash(entries) { + function MapCache(entries) { var index = -1, length = entries == null ? 0 : entries.length; @@ -3112,1017 +2975,1162 @@ var JSpider = (function () { } } - // Add methods to `Hash`. - Hash.prototype.clear = hashClear; - Hash.prototype['delete'] = hashDelete; - Hash.prototype.get = hashGet; - Hash.prototype.has = hashHas; - Hash.prototype.set = hashSet; + // Add methods to `MapCache`. + MapCache.prototype.clear = mapCacheClear; + MapCache.prototype['delete'] = mapCacheDelete; + MapCache.prototype.get = mapCacheGet; + MapCache.prototype.has = mapCacheHas; + MapCache.prototype.set = mapCacheSet; + + /** Error message constants. */ + var FUNC_ERROR_TEXT = 'Expected a function'; /** - * Removes all key-value entries from the list cache. + * 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. * - * @private - * @name clear - * @memberOf ListCache + * **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/7.0/#sec-properties-of-the-map-prototype-object) + * method interface of `clear`, `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 memoized 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 listCacheClear() { - this.__data__ = []; - this.size = 0; + function memoize(func, resolver) { + if (typeof func != 'function' || (resolver != null && 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) || cache; + return result; + }; + memoized.cache = new (memoize.Cache || MapCache); + return memoized; } + // Expose `MapCache`. + memoize.Cache = MapCache; + + /** Used as the maximum memoize cache size. */ + var MAX_MEMOIZE_SIZE = 500; + /** - * Gets the index at which the `key` is found in `array` of key-value pairs. + * A specialized version of `_.memoize` which clears the memoized function's + * cache when it exceeds `MAX_MEMOIZE_SIZE`. * * @private - * @param {Array} array The array to inspect. - * @param {*} key The key to search for. - * @returns {number} Returns the index of the matched value, else `-1`. + * @param {Function} func The function to have its output memoized. + * @returns {Function} Returns the new memoized function. */ - function assocIndexOf(array, key) { - var length = array.length; - while (length--) { - if (eq(array[length][0], key)) { - return length; + function memoizeCapped(func) { + var result = memoize(func, function(key) { + if (cache.size === MAX_MEMOIZE_SIZE) { + cache.clear(); } - } - return -1; + return key; + }); + + var cache = result.cache; + return result; } - /** Used for built-in method references. */ - var arrayProto = Array.prototype; + /** Used to match property names within property paths. */ + var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; - /** Built-in value references. */ - var splice = arrayProto.splice; + /** Used to match backslashes in property paths. */ + var reEscapeChar = /\\(\\)?/g; /** - * Removes `key` and its value from the list cache. + * Converts `string` to a property path array. * * @private - * @name delete - * @memberOf ListCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. + * @param {string} string The string to convert. + * @returns {Array} Returns the property path array. */ - function listCacheDelete(key) { - var data = this.__data__, - index = assocIndexOf(data, key); - - if (index < 0) { - return false; - } - var lastIndex = data.length - 1; - if (index == lastIndex) { - data.pop(); - } else { - splice.call(data, index, 1); + var stringToPath = memoizeCapped(function(string) { + var result = []; + if (string.charCodeAt(0) === 46 /* . */) { + result.push(''); } - --this.size; - return true; - } + string.replace(rePropName, function(match, number, quote, subString) { + result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; + }); /** - * Gets the list cache value for `key`. + * Converts `value` to a string. An empty string is returned for `null` + * and `undefined` values. The sign of `-0` is preserved. * - * @private - * @name get - * @memberOf ListCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.toString(null); + * // => '' + * + * _.toString(-0); + * // => '-0' + * + * _.toString([1, 2, 3]); + * // => '1,2,3' */ - function listCacheGet(key) { - var data = this.__data__, - index = assocIndexOf(data, key); - - return index < 0 ? undefined : data[index][1]; + function toString(value) { + return value == null ? '' : baseToString(value); } /** - * Checks if a list cache value for `key` exists. + * Casts `value` to a path array if it's not one. * * @private - * @name has - * @memberOf ListCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + * @param {*} value The value to inspect. + * @param {Object} [object] The object to query keys on. + * @returns {Array} Returns the cast property path array. */ - function listCacheHas(key) { - return assocIndexOf(this.__data__, key) > -1; + function castPath(value, object) { + if (isArray(value)) { + return value; + } + return isKey(value, object) ? [value] : stringToPath(toString(value)); } + /** Used as references for various `Number` constants. */ + var INFINITY = 1 / 0; + /** - * Sets the list cache `key` to `value`. + * Converts `value` to a string key if it's not a string or symbol. * * @private - * @name set - * @memberOf ListCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the list cache instance. + * @param {*} value The value to inspect. + * @returns {string|symbol} Returns the key. */ - function listCacheSet(key, value) { - var data = this.__data__, - index = assocIndexOf(data, key); - - if (index < 0) { - ++this.size; - data.push([key, value]); - } else { - data[index][1] = value; + function toKey(value) { + if (typeof value == 'string' || isSymbol(value)) { + return value; } - return this; + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; } /** - * Creates an list cache object. + * The base implementation of `_.get` without support for default values. * * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @returns {*} Returns the resolved value. */ - function ListCache(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; + function baseGet(object, path) { + path = castPath(path, object); + + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[toKey(path[index++])]; + } + return (index && index == length) ? object : undefined; + } + + /** + * 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; - this.clear(); while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); + array[offset + index] = values[index]; } + return array; } - // Add methods to `ListCache`. - ListCache.prototype.clear = listCacheClear; - ListCache.prototype['delete'] = listCacheDelete; - ListCache.prototype.get = listCacheGet; - ListCache.prototype.has = listCacheHas; - ListCache.prototype.set = listCacheSet; + /** Built-in value references. */ + var spreadableSymbol = Symbol$1 ? Symbol$1.isConcatSpreadable : undefined; - /* Built-in method references that are verified to be native. */ - var Map$1 = getNative(root, 'Map'); + /** + * 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 isArray(value) || isArguments(value) || + !!(spreadableSymbol && value && value[spreadableSymbol]); + } /** - * Removes all key-value entries from the map. + * The base implementation of `_.flatten` with support for restricting flattening. * * @private - * @name clear - * @memberOf MapCache + * @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 mapCacheClear() { - this.size = 0; - this.__data__ = { - 'hash': new Hash, - 'map': new (Map$1 || ListCache), - 'string': new Hash - }; + 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; } /** - * Checks if `value` is suitable for use as unique object key. + * 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 == null ? 0 : array.length; + return length ? baseFlatten(array, 1) : []; + } + + /** + * A specialized version of `baseRest` which flattens the rest array. * * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + * @param {Function} func The function to apply a rest parameter to. + * @returns {Function} Returns the new function. */ - function isKeyable(value) { - var type = typeof value; - return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') - ? (value !== '__proto__') - : (value === null); + function flatRest(func) { + return setToString(overRest(func, undefined, flatten), func + ''); } + /** Used to stand-in for `undefined` hash values. */ + var HASH_UNDEFINED = '__lodash_hash_undefined__'; + /** - * Gets the data for `map`. + * Adds `value` to the array cache. * * @private - * @param {Object} map The map to query. - * @param {string} key The reference key. - * @returns {*} Returns the map data. + * @name add + * @memberOf SetCache + * @alias push + * @param {*} value The value to cache. + * @returns {Object} Returns the cache instance. */ - function getMapData(map, key) { - var data = map.__data__; - return isKeyable(key) - ? data[typeof key == 'string' ? 'string' : 'hash'] - : data.map; + function setCacheAdd(value) { + this.__data__.set(value, HASH_UNDEFINED); + return this; } /** - * Removes `key` and its value from the map. + * Checks if `value` is in the array cache. * * @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`. + * @name has + * @memberOf SetCache + * @param {*} value The value to search for. + * @returns {number} Returns `true` if `value` is found, else `false`. */ - function mapCacheDelete(key) { - var result = getMapData(this, key)['delete'](key); - this.size -= result ? 1 : 0; - return result; + function setCacheHas(value) { + return this.__data__.has(value); } /** - * Gets the map value for `key`. + * + * Creates an array cache object to store unique values. * * @private - * @name get - * @memberOf MapCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. + * @constructor + * @param {Array} [values] The values to cache. */ - function mapCacheGet(key) { - return getMapData(this, key).get(key); + function SetCache(values) { + var index = -1, + length = values == null ? 0 : values.length; + + this.__data__ = new MapCache; + while (++index < length) { + this.add(values[index]); + } } + // Add methods to `SetCache`. + SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; + SetCache.prototype.has = setCacheHas; + /** - * Checks if a map value for `key` exists. + * Checks if a `cache` value for `key` exists. * * @private - * @name has - * @memberOf MapCache + * @param {Object} cache The cache 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 mapCacheHas(key) { - return getMapData(this, key).has(key); + function cacheHas(cache, key) { + return cache.has(key); } /** - * Sets the map `key` to `value`. + * The base implementation of `_.hasIn` without support for deep paths. * * @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. + * @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 mapCacheSet(key, value) { - var data = getMapData(this, key), - size = data.size; - - data.set(key, value); - this.size += data.size == size ? 0 : 1; - return this; + function baseHasIn(object, key) { + return object != null && key in Object(object); } /** - * Creates a map cache object to store key-value pairs. + * Checks if `path` exists on `object`. * * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. + * @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 MapCache(entries) { + function hasPath(object, path, hasFunc) { + path = castPath(path, object); + var index = -1, - length = entries == null ? 0 : entries.length; + length = path.length, + result = false; - this.clear(); while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); + var key = toKey(path[index]); + if (!(result = object != null && hasFunc(object, key))) { + break; + } + object = object[key]; } + if (result || ++index != length) { + return result; + } + length = object == null ? 0 : object.length; + return !!length && isLength(length) && isIndex(key, length) && + (isArray(object) || isArguments(object)); } - // Add methods to `MapCache`. - MapCache.prototype.clear = mapCacheClear; - MapCache.prototype['delete'] = mapCacheDelete; - MapCache.prototype.get = mapCacheGet; - MapCache.prototype.has = mapCacheHas; - MapCache.prototype.set = mapCacheSet; - - /** Error message constants. */ - var FUNC_ERROR_TEXT = 'Expected a function'; - /** - * 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/7.0/#sec-properties-of-the-map-prototype-object) - * method interface of `clear`, `delete`, `get`, `has`, and `set`. + * Checks if `path` is a direct or inherited property of `object`. * * @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 memoized function. + * @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 = { 'a': 1, 'b': 2 }; - * var other = { 'c': 3, 'd': 4 }; - * - * var values = _.memoize(_.values); - * values(object); - * // => [1, 2] - * - * values(other); - * // => [3, 4] + * var object = _.create({ 'a': _.create({ 'b': 2 }) }); * - * object.a = 2; - * values(object); - * // => [1, 2] + * _.hasIn(object, 'a'); + * // => true * - * // Modify the result cache. - * values.cache.set(object, ['a', 'b']); - * values(object); - * // => ['a', 'b'] + * _.hasIn(object, 'a.b'); + * // => true * - * // Replace `_.memoize.Cache`. - * _.memoize.Cache = WeakMap; - */ - function memoize(func, resolver) { - if (typeof func != 'function' || (resolver != null && 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) || cache; - return result; - }; - memoized.cache = new (memoize.Cache || MapCache); - return memoized; - } - - // Expose `MapCache`. - memoize.Cache = MapCache; - - /** Used as the maximum memoize cache size. */ - var MAX_MEMOIZE_SIZE = 500; - - /** - * A specialized version of `_.memoize` which clears the memoized function's - * cache when it exceeds `MAX_MEMOIZE_SIZE`. + * _.hasIn(object, ['a', 'b']); + * // => true * - * @private - * @param {Function} func The function to have its output memoized. - * @returns {Function} Returns the new memoized function. + * _.hasIn(object, 'b'); + * // => false */ - function memoizeCapped(func) { - var result = memoize(func, function(key) { - if (cache.size === MAX_MEMOIZE_SIZE) { - cache.clear(); - } - return key; - }); - - var cache = result.cache; - return result; + function hasIn(object, path) { + return object != null && hasPath(object, path, baseHasIn); } - /** Used to match property names within property paths. */ - var rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; - - /** Used to match backslashes in property paths. */ - var reEscapeChar = /\\(\\)?/g; - - /** - * Converts `string` to a property path array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the property path array. - */ - var stringToPath = memoizeCapped(function(string) { - var result = []; - if (string.charCodeAt(0) === 46 /* . */) { - result.push(''); - } - string.replace(rePropName, function(match, number, quote, subString) { - result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); - }); - return result; - }); - /** - * Converts `value` to a string. An empty string is returned for `null` - * and `undefined` values. The sign of `-0` is preserved. + * 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 convert. - * @returns {string} Returns the converted string. + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, + * else `false`. * @example * - * _.toString(null); - * // => '' - * - * _.toString(-0); - * // => '-0' + * _.isArrayLikeObject([1, 2, 3]); + * // => true * - * _.toString([1, 2, 3]); - * // => '1,2,3' - */ - function toString(value) { - return value == null ? '' : baseToString(value); - } - - /** - * Casts `value` to a path array if it's not one. + * _.isArrayLikeObject(document.body.children); + * // => true * - * @private - * @param {*} value The value to inspect. - * @param {Object} [object] The object to query keys on. - * @returns {Array} Returns the cast property path array. - */ - function castPath(value, object) { - if (isArray(value)) { - return value; - } - return isKey(value, object) ? [value] : stringToPath(toString(value)); - } - - /** Used as references for various `Number` constants. */ - var INFINITY = 1 / 0; - - /** - * Converts `value` to a string key if it's not a string or symbol. + * _.isArrayLikeObject('abc'); + * // => false * - * @private - * @param {*} value The value to inspect. - * @returns {string|symbol} Returns the key. + * _.isArrayLikeObject(_.noop); + * // => false */ - function toKey(value) { - if (typeof value == 'string' || isSymbol(value)) { - return value; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + function isArrayLikeObject(value) { + return isObjectLike(value) && isArrayLike(value); } /** - * The base implementation of `_.get` without support for default values. + * This function is like `arrayIncludes` except that it accepts a comparator. * * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @returns {*} Returns the resolved value. + * @param {Array} [array] The array to inspect. + * @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 baseGet(object, path) { - path = castPath(path, object); - - var index = 0, - length = path.length; + function arrayIncludesWith(array, value, comparator) { + var index = -1, + length = array == null ? 0 : array.length; - while (object != null && index < length) { - object = object[toKey(path[index++])]; + while (++index < length) { + if (comparator(value, array[index])) { + return true; + } } - return (index && index == length) ? object : undefined; + return false; } + /** Used as the size to enable large array optimizations. */ + var LARGE_ARRAY_SIZE = 200; + /** - * Appends the elements of `values` to `array`. + * The base implementation of methods like `_.difference` without support + * for excluding multiple arrays or iteratee shorthands. * * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to append. - * @returns {Array} Returns `array`. + * @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 arrayPush(array, values) { + function baseDifference(array, values, iteratee, comparator) { var index = -1, - length = values.length, - offset = array.length; + 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) { - array[offset + index] = values[index]; + var value = array[index], + computed = iteratee == null ? value : iteratee(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 array; + return result; } - /** Built-in value references. */ - var spreadableSymbol = Symbol$1 ? Symbol$1.isConcatSpreadable : undefined; - /** - * Checks if `value` is a flattenable `arguments` object or array. + * Creates an array of `array` values not included in the other given arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. The order and references of result values are + * determined by the first array. * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. - */ - function isFlattenable(value) { - return isArray(value) || isArguments(value) || - !!(spreadableSymbol && value && value[spreadableSymbol]); - } - - /** - * The base implementation of `_.flatten` with support for restricting flattening. + * **Note:** Unlike `_.pullAll`, this method returns a new array. * - * @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. + * @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([2, 1], [2, 3]); + * // => [1] */ - function baseFlatten(array, depth, predicate, isStrict, result) { - var index = -1, - length = array.length; - - predicate || (predicate = isFlattenable); - result || (result = []); + var difference = baseRest(function(array, values) { + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) + : []; + }); - 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; - } + /** `Object#toString` result references. */ + var stringTag = '[object String]'; /** - * Flattens `array` a single level deep. + * Checks if `value` is classified as a `String` primitive or object. * * @static - * @memberOf _ * @since 0.1.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a string, else `false`. * @example * - * _.flatten([1, [2, [3, [4]], 5]]); - * // => [1, 2, [3, [4]], 5] + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false */ - function flatten(array) { - var length = array == null ? 0 : array.length; - return length ? baseFlatten(array, 1) : []; + function isString(value) { + return typeof value == 'string' || + (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); } + /** `Object#toString` result references. */ + var regexpTag = '[object RegExp]'; + /** - * A specialized version of `baseRest` which flattens the rest array. + * The base implementation of `_.isRegExp` without Node.js optimizations. * * @private - * @param {Function} func The function to apply a rest parameter to. - * @returns {Function} Returns the new function. + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. */ - function flatRest(func) { - return setToString(overRest(func, undefined, flatten), func + ''); + function baseIsRegExp(value) { + return isObjectLike(value) && baseGetTag(value) == regexpTag; } - /** Used to stand-in for `undefined` hash values. */ - var HASH_UNDEFINED = '__lodash_hash_undefined__'; + /* Node.js helper references. */ + var nodeIsRegExp = nodeUtil && nodeUtil.isRegExp; /** - * Adds `value` to the array cache. + * Checks if `value` is classified as a `RegExp` object. * - * @private - * @name add - * @memberOf SetCache - * @alias push - * @param {*} value The value to cache. - * @returns {Object} Returns the cache instance. + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. + * @example + * + * _.isRegExp(/abc/); + * // => true + * + * _.isRegExp('/abc/'); + * // => false */ - function setCacheAdd(value) { - this.__data__.set(value, HASH_UNDEFINED); - return this; - } + var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; /** - * Checks if `value` is in the array cache. + * The base implementation of `_.set`. * * @private - * @name has - * @memberOf SetCache - * @param {*} value The value to search for. - * @returns {number} Returns `true` if `value` is found, else `false`. + * @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 path creation. + * @returns {Object} Returns `object`. */ - function setCacheHas(value) { - return this.__data__.has(value); + function baseSet(object, path, value, customizer) { + if (!isObject(object)) { + return object; + } + path = castPath(path, object); + + var index = -1, + length = path.length, + lastIndex = length - 1, + nested = object; + + while (nested != null && ++index < length) { + var key = toKey(path[index]), + newValue = value; + + if (key === '__proto__' || key === 'constructor' || key === 'prototype') { + return object; + } + + if (index != lastIndex) { + var objValue = nested[key]; + newValue = customizer ? customizer(objValue, key, nested) : undefined; + if (newValue === undefined) { + newValue = isObject(objValue) + ? objValue + : (isIndex(path[index + 1]) ? [] : {}); + } + } + assignValue(nested, key, newValue); + nested = nested[key]; + } + return object; } /** - * - * Creates an array cache object to store unique values. + * The base implementation of `_.pickBy` without support for iteratee shorthands. * * @private - * @constructor - * @param {Array} [values] The values to cache. + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @param {Function} predicate The function invoked per property. + * @returns {Object} Returns the new object. */ - function SetCache(values) { + function basePickBy(object, paths, predicate) { var index = -1, - length = values == null ? 0 : values.length; + length = paths.length, + result = {}; - this.__data__ = new MapCache; while (++index < length) { - this.add(values[index]); + var path = paths[index], + value = baseGet(object, path); + + if (predicate(value, path)) { + baseSet(result, castPath(path, object), value); + } } + return result; } - // Add methods to `SetCache`. - SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; - SetCache.prototype.has = setCacheHas; - /** - * Checks if a `cache` value for `key` exists. + * The base implementation of `_.pick` without support for individual + * property identifiers. * * @private - * @param {Object} cache The cache to query. - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @returns {Object} Returns the new object. */ - function cacheHas(cache, key) { - return cache.has(key); + function basePick(object, paths) { + return basePickBy(object, paths, function(value, path) { + return hasIn(object, path); + }); } /** - * The base implementation of `_.hasIn` without support for deep paths. + * Creates an object composed of the picked `object` properties. * - * @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 object != null && key in Object(object); - } - - /** - * Checks if `path` exists on `object`. + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Object} Returns the new object. + * @example * - * @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`. + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pick(object, ['a', 'c']); + * // => { 'a': 1, 'c': 3 } */ - function hasPath(object, path, hasFunc) { - path = castPath(path, object); - - var index = -1, - length = path.length, - result = false; + var pick = flatRest(function(object, paths) { + return object == null ? {} : basePick(object, paths); + }); - while (++index < length) { - var key = toKey(path[index]); - if (!(result = object != null && hasFunc(object, key))) { - break; + class EventHub { + all = new Map(); + constructor(eventMap = {}, bindThis = null) { + this.bindThis = bindThis || globalThis; + this.on(eventMap); + + // 创建一个 rxjs 流源头 + this.createSource$ = memoize((eventName) => { + return fromEventPattern( + (handle) => this.on(eventName, handle), + (handle) => this.off(eventName, handle), + ); + }); + } + #on(type, handler) { + const handlers = this.all.get(type); + // ! 注意,栈的结构,这里要使用 unshift 将元素插入到头部,这样触发的时候才会最后执行最先声明的函数作为默认函数 + // 栈的结构可以保证 在 destroy 事件的时候,首先定义的 destroy 可以最后执行,保证后面绑定 destroy 事件的函数可以先触发,而在 destroy 的定义函数中可以最后 off('*') 解除事件 + handlers ? handlers.unshift(handler) : this.all.set(type, [handler]); + } + on(type, handler) { + // 函数重载 + if (typeof type === 'string') { + this.#on(type, handler); + } else if (type instanceof Object) { + // 在直接赋值为一个 + Object.entries(type).forEach(([key, value]) => { + if (value instanceof Array) { + value.forEach((item) => this.#on(key, item)); + } else { + this.#on(key, value); + } + }); + } + } + off(type, handler) { + if (type === '*') { + return this.all.clear(); + } else { + const handlers = this.all.get(type); + if (handlers) { + return handler ? handlers.splice(handlers.indexOf(handler) >>> 0, 1) : this.all.set(type, []); + } + return false; + } + } + emit(type, ...eventParams) { + console.log(type); + const handlers = this.all.get(type); + return handlers + ? handlers.map((handler) => { + return handler.apply(this.bindThis, eventParams); + }) + : []; } - object = object[key]; - } - if (result || ++index != length) { - return result; - } - length = object == null ? 0 : object.length; - return !!length && isLength(length) && isIndex(key, length) && - (isArray(object) || isArguments(object)); - } - /** - * 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); + operators = { + // TODO EventHub 中对于 rxjs 流的支持 + EmitWhen(config) {}, + }; } - /** - * 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); - } + const staticEvent$2 = {}; - /** - * This function is like `arrayIncludes` except that it accepts a comparator. - * - * @private - * @param {Array} [array] The array to inspect. - * @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 == null ? 0 : array.length; + // Unique ID creation requires a high quality random # generator. In the browser we therefore + // require the crypto API and do not support built-in fallback to lower quality random number + // generators (like Math.random()). + var getRandomValues; + var rnds8 = new Uint8Array(16); + function rng() { + // lazy load so that environments that need to polyfill have a chance to do so + if (!getRandomValues) { + // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also, + // find the complete implementation of crypto (msCrypto) on IE11. + getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto); - while (++index < length) { - if (comparator(value, array[index])) { - return true; + if (!getRandomValues) { + throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); } } - return false; + + return getRandomValues(rnds8); } - /** Used as the size to enable large array optimizations. */ - var LARGE_ARRAY_SIZE = 200; + var REGEX = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; + + function validate(uuid) { + return typeof uuid === 'string' && REGEX.test(uuid); + } /** - * 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. + * Convert array of 16 byte values to UUID string format of the form: + * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX */ - 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)); + var byteToHex = []; + + for (var i = 0; i < 256; ++i) { + byteToHex.push((i + 0x100).toString(16).substr(1)); + } + + function stringify(arr) { + var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + // Note: Be careful editing this code! It's been tuned for performance + // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 + var uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one + // of the following: + // - One or more input array values don't map to a hex octet (leading to + // "undefined" in the uuid) + // - Invalid input values for the RFC `version` or `variant` fields + + if (!validate(uuid)) { + throw TypeError('Stringified UUID is invalid'); } - if (comparator) { - includes = arrayIncludesWith; - isCommon = false; + + return uuid; + } + + function parse(uuid) { + if (!validate(uuid)) { + throw TypeError('Invalid UUID'); } - else if (values.length >= LARGE_ARRAY_SIZE) { - includes = cacheHas; - isCommon = false; - values = new SetCache(values); + + var v; + var arr = new Uint8Array(16); // Parse ########-....-....-....-............ + + arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; + arr[1] = v >>> 16 & 0xff; + arr[2] = v >>> 8 & 0xff; + arr[3] = v & 0xff; // Parse ........-####-....-....-............ + + arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; + arr[5] = v & 0xff; // Parse ........-....-####-....-............ + + arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; + arr[7] = v & 0xff; // Parse ........-....-....-####-............ + + arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; + arr[9] = v & 0xff; // Parse ........-....-....-....-############ + // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes) + + arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff; + arr[11] = v / 0x100000000 & 0xff; + arr[12] = v >>> 24 & 0xff; + arr[13] = v >>> 16 & 0xff; + arr[14] = v >>> 8 & 0xff; + arr[15] = v & 0xff; + return arr; + } + + function stringToBytes(str) { + str = unescape(encodeURIComponent(str)); // UTF8 escape + + var bytes = []; + + for (var i = 0; i < str.length; ++i) { + bytes.push(str.charCodeAt(i)); } - outer: - while (++index < length) { - var value = array[index], - computed = iteratee == null ? value : iteratee(value); - value = (comparator || value !== 0) ? value : 0; - if (isCommon && computed === computed) { - var valuesIndex = valuesLength; - while (valuesIndex--) { - if (values[valuesIndex] === computed) { - continue outer; - } + return bytes; + } + + var DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; + var URL$1 = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; + function v35 (name, version, hashfunc) { + function generateUUID(value, namespace, buf, offset) { + if (typeof value === 'string') { + value = stringToBytes(value); + } + + if (typeof namespace === 'string') { + namespace = parse(namespace); + } + + if (namespace.length !== 16) { + throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); + } // Compute hash of namespace and value, Per 4.3 + // Future: Use spread syntax when supported on all platforms, e.g. `bytes = + // hashfunc([...namespace, ... value])` + + + var bytes = new Uint8Array(16 + value.length); + bytes.set(namespace); + bytes.set(value, namespace.length); + bytes = hashfunc(bytes); + bytes[6] = bytes[6] & 0x0f | version; + bytes[8] = bytes[8] & 0x3f | 0x80; + + if (buf) { + offset = offset || 0; + + for (var i = 0; i < 16; ++i) { + buf[offset + i] = bytes[i]; } - result.push(value); + + return buf; } - else if (!includes(values, computed, comparator)) { - result.push(value); + + return stringify(bytes); + } // Function#name is not settable on some platforms (#270) + + + try { + generateUUID.name = name; // eslint-disable-next-line no-empty + } catch (err) {} // For CommonJS default export support + + + generateUUID.DNS = DNS; + generateUUID.URL = URL$1; + return generateUUID; + } + + function v4(options, buf, offset) { + options = options || {}; + var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` + + rnds[6] = rnds[6] & 0x0f | 0x40; + rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided + + if (buf) { + offset = offset || 0; + + for (var i = 0; i < 16; ++i) { + buf[offset + i] = rnds[i]; } + + return buf; } - return result; + + return stringify(rnds); } - /** - * Creates an array of `array` values not included in the other given arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. The order and references of result values are - * determined by the first array. - * - * **Note:** Unlike `_.pullAll`, this method returns a new 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([2, 1], [2, 3]); - * // => [1] - */ - var difference = baseRest(function(array, values) { - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) - : []; - }); + // Adapted from Chris Veness' SHA1 code at + // http://www.movable-type.co.uk/scripts/sha1.html + function f(s, x, y, z) { + switch (s) { + case 0: + return x & y ^ ~x & z; - /** `Object#toString` result references. */ - var stringTag = '[object String]'; + case 1: + return x ^ y ^ z; - /** - * 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 a string, else `false`. - * @example - * - * _.isString('abc'); - * // => true - * - * _.isString(1); - * // => false - */ - function isString(value) { - return typeof value == 'string' || - (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); - } + case 2: + return x & y ^ x & z ^ y & z; - /** `Object#toString` result references. */ - var regexpTag = '[object RegExp]'; + case 3: + return x ^ y ^ z; + } + } - /** - * The base implementation of `_.isRegExp` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. - */ - function baseIsRegExp(value) { - return isObjectLike(value) && baseGetTag(value) == regexpTag; + function ROTL(x, n) { + return x << n | x >>> 32 - n; } - /* Node.js helper references. */ - var nodeIsRegExp = nodeUtil && nodeUtil.isRegExp; + function sha1(bytes) { + var K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]; + var H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; - /** - * 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 a regexp, else `false`. - * @example - * - * _.isRegExp(/abc/); - * // => true - * - * _.isRegExp('/abc/'); - * // => false - */ - var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; + if (typeof bytes === 'string') { + var msg = unescape(encodeURIComponent(bytes)); // UTF8 escape - /** - * The base implementation of `_.set`. - * - * @private - * @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 path creation. - * @returns {Object} Returns `object`. - */ - function baseSet(object, path, value, customizer) { - if (!isObject(object)) { - return object; + bytes = []; + + for (var i = 0; i < msg.length; ++i) { + bytes.push(msg.charCodeAt(i)); + } + } else if (!Array.isArray(bytes)) { + // Convert Array-like to Array + bytes = Array.prototype.slice.call(bytes); } - path = castPath(path, object); - var index = -1, - length = path.length, - lastIndex = length - 1, - nested = object; + bytes.push(0x80); + var l = bytes.length / 4 + 2; + var N = Math.ceil(l / 16); + var M = new Array(N); - while (nested != null && ++index < length) { - var key = toKey(path[index]), - newValue = value; + for (var _i = 0; _i < N; ++_i) { + var arr = new Uint32Array(16); - if (key === '__proto__' || key === 'constructor' || key === 'prototype') { - return object; + for (var j = 0; j < 16; ++j) { + arr[j] = bytes[_i * 64 + j * 4] << 24 | bytes[_i * 64 + j * 4 + 1] << 16 | bytes[_i * 64 + j * 4 + 2] << 8 | bytes[_i * 64 + j * 4 + 3]; } - if (index != lastIndex) { - var objValue = nested[key]; - newValue = customizer ? customizer(objValue, key, nested) : undefined; - if (newValue === undefined) { - newValue = isObject(objValue) - ? objValue - : (isIndex(path[index + 1]) ? [] : {}); - } + M[_i] = arr; + } + + M[N - 1][14] = (bytes.length - 1) * 8 / Math.pow(2, 32); + M[N - 1][14] = Math.floor(M[N - 1][14]); + M[N - 1][15] = (bytes.length - 1) * 8 & 0xffffffff; + + for (var _i2 = 0; _i2 < N; ++_i2) { + var W = new Uint32Array(80); + + for (var t = 0; t < 16; ++t) { + W[t] = M[_i2][t]; } - assignValue(nested, key, newValue); - nested = nested[key]; + + for (var _t = 16; _t < 80; ++_t) { + W[_t] = ROTL(W[_t - 3] ^ W[_t - 8] ^ W[_t - 14] ^ W[_t - 16], 1); + } + + var a = H[0]; + var b = H[1]; + var c = H[2]; + var d = H[3]; + var e = H[4]; + + for (var _t2 = 0; _t2 < 80; ++_t2) { + var s = Math.floor(_t2 / 20); + var T = ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[_t2] >>> 0; + e = d; + d = c; + c = ROTL(b, 30) >>> 0; + b = a; + a = T; + } + + H[0] = H[0] + a >>> 0; + H[1] = H[1] + b >>> 0; + H[2] = H[2] + c >>> 0; + H[3] = H[3] + d >>> 0; + H[4] = H[4] + e >>> 0; } - return object; + + return [H[0] >> 24 & 0xff, H[0] >> 16 & 0xff, H[0] >> 8 & 0xff, H[0] & 0xff, H[1] >> 24 & 0xff, H[1] >> 16 & 0xff, H[1] >> 8 & 0xff, H[1] & 0xff, H[2] >> 24 & 0xff, H[2] >> 16 & 0xff, H[2] >> 8 & 0xff, H[2] & 0xff, H[3] >> 24 & 0xff, H[3] >> 16 & 0xff, H[3] >> 8 & 0xff, H[3] & 0xff, H[4] >> 24 & 0xff, H[4] >> 16 & 0xff, H[4] >> 8 & 0xff, H[4] & 0xff]; + } + + var v5 = v35('v5', 0x50, sha1); + + /* + * @Author: KonghaYao + * @Date: 2021-06-28 21:07:01 + * @Last Modified by: KonghaYao + * @Last Modified time: 2021-06-28 21:07:01 + */ + + function createUUID(string) { + return v5(string, v5.URL); } /** - * The base implementation of `_.pickBy` without support for iteratee shorthands. - * - * @private - * @param {Object} object The source object. - * @param {string[]} paths The property paths to pick. - * @param {Function} predicate The function invoked per property. - * @returns {Object} Returns the new object. + * 函数用途描述 + * 这个是用于 async 函数队列 连续执行的函数,只要 enQueue 之后就会连续执行,直至停止 */ - function basePickBy(object, paths, predicate) { - var index = -1, - length = paths.length, - result = {}; - while (++index < length) { - var path = paths[index], - value = baseGet(object, path); + class functionQueue { + QueuePromise = Promise.resolve(); + constructor() {} + enQueue(...args) { + this.QueuePromise = args.reduce((promise, current) => { + return promise.then(current); + }, this.QueuePromise); + return this; + } + } + + // Pipeline 是组合 Plugin 实例的工具类,用于创建一个可以不断提供 source 进行固定操作的功能对象。 + class Pipeline { + constructor(Plugins) { + this.Plugins = Plugins; + } + UUID = null; // 唯一的标识 + operator = null; // 主要被引用的 operator + + #PluginQueue = new functionQueue(); // 准备 Plugin 中的异步 init 事件 + preparePipeline() { + let uuidString = ''; + // ! 一次遍历实现取出 operator 和 导出 plugin init 函数的 promise 链,并延长 uuidString 用于创建 UUID + const pipeline = this.Plugins.map((plugin) => { + uuidString += plugin.operator.toString(); + + if (plugin.init instanceof Function) { + this.#PluginQueue.enQueue(plugin.init); + } + // 将 plugin 中的 operator 注入 pipeline 中 + return plugin.operator(this); + }); + this.operator = pipe(...pipeline); + + this.UUID = createUUID(uuidString); - if (predicate(value, path)) { - baseSet(result, castPath(path, object), value); + return this.#PluginQueue.QueuePromise; } - } - return result; } - /** - * The base implementation of `_.pick` without support for individual - * property identifiers. - * - * @private - * @param {Object} object The source object. - * @param {string[]} paths The property paths to pick. - * @returns {Object} Returns the new object. - */ - function basePick(object, paths) { - return basePickBy(object, paths, function(value, path) { - return hasIn(object, path); - }); - } + // 每个 Task 拥有的静态事件 + // 这些事件一般通过 $commit(eventName,payload) 进行执行 + // ! this 被绑定为 Task 的实例 + const staticEvent$1 = { + start(UUID) { + this._status = 'busy'; + // ! 这里会有一个清空这个 key 的 value 的情况,这是因为 start 是强制的 + this._progress.set(UUID, { process: 'start' }); - /** - * 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[])} [paths] The property paths 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 = flatRest(function(object, paths) { - return object == null ? {} : basePick(object, paths); - }); + return this._output || this._originData; + }, + success(output, UUID) { + this._status = 'free'; + this._progress.set(UUID, { process: 'success', output }); + this._output = output; + }, + complete(UUID) { + this._status = 'complete'; + }, + error(err, UUID) { + this._status = 'error'; + this._progress.set(UUID, { process: 'error', err }); + }, + destroy() { + this._process = []; + this._output = null; + this._belongTo = null; + this._originData = null; + this.$off('*'); + }, + }; // 装载信息的最小单元 @@ -4251,18 +4259,25 @@ var JSpider = (function () { stateChange(state) { this.state = state; }, - // runPipeline() {}, // 这个函数没有必要监听是因为 rxjs 代理了这个事件 - 'Task:success'(task) {}, - 'Task:error'(error) { - console.log(error); + 'Flow:stop'() { + this._stop = true; }, - 'Task:complete'() { + 'Flow:start'() { + this._stop = false; + }, + + // 'Flow:input'() {} + // 'Spider:clearFlow'(){} + 'Task:success'(task) { task.$commit('complete'); if (task instanceof TaskGroup) { task.$destroy(); } - console.log('所有情况完成'); }, + 'Task:error'(error) { + console.log(error); + }, + 'Task:complete'() {}, }; function createTaskViewModel(task) { @@ -4293,6 +4308,141 @@ var JSpider = (function () { } } + function pauseToggle(openings, closings) { + return (observable) => + new Observable((subscriber) => { + const buffers = new Set(); + let closingSubscription = false; + const subscription = observable.subscribe( + (value) => { + closingSubscription ? buffers.add(value) : subscriber.next(value); + }, + noop, + () => { + buffers.forEach((item) => subscriber.next(item)); + subscriber.complete(); + }, + ); + const openingSubscription = openings.subscribe(() => { + // 输出所有的 buffer + const emitBuffer = () => { + buffers.forEach((item) => subscriber.next(item)); + buffers.clear(); + closingSubscription.unsubscribe(); + closingSubscription = false; + }; + closingSubscription = closings.subscribe(emitBuffer); + }); + return () => { + buffers.clear(); + subscription.unsubscribe(); + openingSubscription.unsubscribe(); + if (closingSubscription) closingSubscription.unsubscribe(); + }; + }); + } + + // ControlPanel 是 JSpider 内部的事件和数据中心。 + // 全部 JSpider 涉及到的边界中,ControlPanel 只有一个,但是 View 可以有多个,而 Spider 就是 View 中的一个 + // 用于分发数据流,提供 Task 的状态变更。 + // TODO 并且可以提供数据的响应给类似于 UI 界面形成可视化 + + class ControlPanel$1 { + state = 'free'; // 'free' 'preparing' + #runningQueue = new functionQueue(); // init 阶段的 Queue 队列 + _stop = false; // 用于直接切断 spiderSource$ 的流 + spiderSource$ = null; + _pipeline = null; + TaskManager = new TaskManager(); + constructor() { + this.$EventHub = new EventHub(staticEvent, this); + } + // ! 这是一个完整的流控 + _createLogicLine() { + this.spiderSource$ = this.$EventHub.createSource$('Flow:input').pipe( + pauseToggle( + this.$EventHub.createSource$('Flow:stop'), + + this.$EventHub.createSource$('Flow:start'), + ), + this._pipeline.operator, + ); + + this.spiderSource$.subscribe( + // 所有的事件分配到 staticEvent 中去写 + (task) => this.$EventHub.emit('Task:success', task), + (error) => this.$EventHub.emit('Task:error', error), + () => this.$EventHub.emit('Task:complete'), + ); + this.$EventHub.emit('Flow:stop'); + } + + set pipeline(value) { + if (this.state === 'free') { + this.$EventHub.emit('stateChange', 'preparing'); + this._pipeline = value; + this.#runningQueue.enQueue( + () => this._pipeline.preparePipeline(), + () => { + this.$EventHub.emit('Spider:clearFlow'); // 先注销流 + this._createLogicLine(); // 创建新流 + this.$EventHub.emit('stateChange', 'free'); + }, + ); + } else { + throw new Error('在运行阶段是不能够进行操作的哦'); + } + } + + // startInfo --TaskManager.createTask--> Task --emit--EventHub--> Flow + createFlow(infos) { + return this.#runningQueue.enQueue(() => { + infos.forEach((info) => { + if (!this._pipeline) throw new Error('没有创建pipeline'); + const task = this.TaskManager.createTask(info, this._pipeline.UUID); + this.$EventHub.emit('Flow:input', task); + }); + }); + } + startFlow() { + this.$EventHub.emit('Flow:start'); + } + // TODO 测试暂停功能 + stopFlow() { + this.$EventHub.emit('Flow:stop'); + } + } + + var ControlPanel = new ControlPanel$1(); + + /* + * @Author: KonghaYao + * @Date: 2021-07-13 15:33:08 + * @Last Modified by: KonghaYao + * @Last Modified time: 2021-07-19 16:34:32 + */ + + // TODO 未完成接口的接入 + class Spider { + constructor(config = {}) { + this.config = config; + this.$EventHub = new EventHub(staticEvent$2, this); // 注册静态事件 + } + crawl(...args) { + ControlPanel.createFlow(args.flat()); + return this; + } + pipeline(...plugins) { + ControlPanel.pipeline = new Pipeline(plugins); + } + start() { + ControlPanel.startFlow(); + } + stop() { + ControlPanel.stopFlow(); + } + } + /** PURE_IMPORTS_START tslib,_scheduler_async,_Subscriber,_util_isScheduler PURE_IMPORTS_END */ function bufferTime(bufferTimeSpan) { var length = arguments.length; @@ -4827,41 +4977,6 @@ var JSpider = (function () { return SwitchMapSubscriber; }(SimpleOuterSubscriber)); - /** PURE_IMPORTS_START tslib,_innerSubscribe PURE_IMPORTS_END */ - function takeUntil(notifier) { - return function (source) { return source.lift(new TakeUntilOperator(notifier)); }; - } - var TakeUntilOperator = /*@__PURE__*/ (function () { - function TakeUntilOperator(notifier) { - this.notifier = notifier; - } - TakeUntilOperator.prototype.call = function (subscriber, source) { - var takeUntilSubscriber = new TakeUntilSubscriber(subscriber); - var notifierSubscription = innerSubscribe(this.notifier, new SimpleInnerSubscriber(takeUntilSubscriber)); - if (notifierSubscription && !takeUntilSubscriber.seenValue) { - takeUntilSubscriber.add(notifierSubscription); - return source.subscribe(takeUntilSubscriber); - } - return takeUntilSubscriber; - }; - return TakeUntilOperator; - }()); - var TakeUntilSubscriber = /*@__PURE__*/ (function (_super) { - __extends(TakeUntilSubscriber, _super); - function TakeUntilSubscriber(destination) { - var _this = _super.call(this, destination) || this; - _this.seenValue = false; - return _this; - } - TakeUntilSubscriber.prototype.notifyNext = function () { - this.seenValue = true; - this.complete(); - }; - TakeUntilSubscriber.prototype.notifyComplete = function () { - }; - return TakeUntilSubscriber; - }(SimpleOuterSubscriber)); - /** PURE_IMPORTS_START tslib,_Subscriber,_util_noop,_util_isFunction PURE_IMPORTS_END */ function tap(nextOrObserver, error, complete) { return function tapOperatorFunction(source) { @@ -4933,92 +5048,6 @@ var JSpider = (function () { return TapSubscriber; }(Subscriber)); - // ControlPanel 是 JSpider 内部的事件和数据中心。 - // 全部 JSpider 涉及到的边界中,ControlPanel 只有一个,但是 View 可以有多个,而 Spider 就是 View 中的一个 - // 用于分发数据流,提供 Task 的状态变更。 - // TODO 并且可以提供数据的响应给类似于 UI 界面形成可视化 - - class ControlPanel$1 { - state = 'free'; // 'free' 'preparing' - #runningQueue = new functionQueue(); // 准备阶段的 Queue 队列 - #stopFlow = null; - _pipeline = null; - TaskManager = new TaskManager(); - constructor() { - this.$EventHub = new EventHub(staticEvent, this); - this.#stopFlow = this.$EventHub.createSource$('stopFlow'); - } - // 这是一个完整的流控 - _createLogicLine() { - this.spiderSource$ = this.$EventHub - .createSource$('runPipeline') - .pipe(this._pipeline.operator, takeUntil(this.#stopFlow)); - this.spiderSource$.subscribe( - // 所有的事件分配到 staticEvent 中去写 - (task) => this.$EventHub.emit('Task:success', task), - (error) => this.$EventHub.emit('Task:error', error), - () => this.$EventHub.emit('Task:complete'), - ); - } - - set pipeline(value) { - if (this.state === 'free') { - this.$EventHub.emit('stateChange', 'preparing'); - this._pipeline = value; - this.#runningQueue.enQueue( - () => this._pipeline.preparePipeline(), - () => { - this.$EventHub.emit('stopFlow'); // 先注销流 - this._createLogicLine(); // 创建新流 - this.$EventHub.emit('stateChange', 'free'); - }, - ); - } else { - throw new Error('在运行阶段是不能够进行操作的哦'); - } - } - - // startInfo --TaskManager.createTask--> Task --emit--EventHub--> Flow - createFlow(infos) { - this.#runningQueue.enQueue(() => { - infos.forEach((info) => { - if (!this._pipeline) throw new Error('没有创建pipeline'); - const task = this.TaskManager.createTask(info, this._pipeline.UUID); - this.$EventHub.emit('runPipeline', task); - }); - }); - } - } - - var ControlPanel = new ControlPanel$1(); - - /* - * @Author: KonghaYao - * @Date: 2021-07-13 15:33:08 - * @Last Modified by: KonghaYao - * @Last Modified time: 2021-07-18 09:43:40 - */ - - // TODO 未完成接口的接入 - class Spider { - infoList = []; - constructor(config = {}) { - this.config = config; - this.EventHub = new EventHub(staticEvent$2, this); // 注册静态事件 - } - crawl(...args) { - this.infoList.push(...args.flat()); - return this; - } - pipeline(...plugins) { - ControlPanel.pipeline = new Pipeline(plugins); - } - start() { - ControlPanel.createFlow(this.infoList); - } - stop() {} - } - // 在 JSpider 系统中的流发生了错误 // Plugin main 函数发生了错误 @@ -6050,7 +6079,7 @@ var JSpider = (function () { Task, TaskGroup, version: "3.1.8", - buildDate: new Date(1626575076697), + buildDate: new Date(1626696870961), }); return index; diff --git a/src/ControlPanel/ControlPanel.js b/src/ControlPanel/ControlPanel.js index 6ab6e24..3ba740d 100644 --- a/src/ControlPanel/ControlPanel.js +++ b/src/ControlPanel/ControlPanel.js @@ -1,8 +1,8 @@ import staticEvent from './StaticEvent'; import { TaskManager } from './TaskManager'; import { functionQueue } from '../utils/functionQueue'; -import { EventHub } from './EventHub'; -import { pauseWhile } from '../utils/pauseWhile'; +import { EventHub } from '../utils/EventHub'; +import { pauseToggle } from '../utils/pauseToggle'; // ControlPanel 是 JSpider 内部的事件和数据中心。 // 全部 JSpider 涉及到的边界中,ControlPanel 只有一个,但是 View 可以有多个,而 Spider 就是 View 中的一个 @@ -12,26 +12,31 @@ import { pauseWhile } from '../utils/pauseWhile'; export class ControlPanel { state = 'free'; // 'free' 'preparing' #runningQueue = new functionQueue(); // init 阶段的 Queue 队列 - #stop = false; // 用于直接切断 spiderSource$ 的流 + _stop = false; // 用于直接切断 spiderSource$ 的流 spiderSource$ = null; _pipeline = null; TaskManager = new TaskManager(); constructor() { this.$EventHub = new EventHub(staticEvent, this); - this.#stopFlow = this.$EventHub.createSource$('Flow:stop'); } - // 这是一个完整的流控 + // ! 这是一个完整的流控 _createLogicLine() { - this.spiderSource$ = this.$EventHub.createSource$('Flow:start').pipe( + this.spiderSource$ = this.$EventHub.createSource$('Flow:input').pipe( + pauseToggle( + this.$EventHub.createSource$('Flow:stop'), + + this.$EventHub.createSource$('Flow:start'), + ), this._pipeline.operator, - pauseWhile(() => this.#stop), ); + this.spiderSource$.subscribe( // 所有的事件分配到 staticEvent 中去写 (task) => this.$EventHub.emit('Task:success', task), (error) => this.$EventHub.emit('Task:error', error), () => this.$EventHub.emit('Task:complete'), ); + this.$EventHub.emit('Flow:stop'); } set pipeline(value) { @@ -41,7 +46,7 @@ export class ControlPanel { this.#runningQueue.enQueue( () => this._pipeline.preparePipeline(), () => { - this.$EventHub.emit('stopFlow'); // 先注销流 + this.$EventHub.emit('Spider:clearFlow'); // 先注销流 this._createLogicLine(); // 创建新流 this.$EventHub.emit('stateChange', 'free'); }, @@ -53,16 +58,18 @@ export class ControlPanel { // startInfo --TaskManager.createTask--> Task --emit--EventHub--> Flow createFlow(infos) { - this.$EventHub.emit('Flow:start'); return this.#runningQueue.enQueue(() => { infos.forEach((info) => { if (!this._pipeline) throw new Error('没有创建pipeline'); const task = this.TaskManager.createTask(info, this._pipeline.UUID); - this.$EventHub.emit('Flow:start', task); + this.$EventHub.emit('Flow:input', task); }); }); } - // TEST 测试功能 + startFlow() { + this.$EventHub.emit('Flow:start'); + } + // TODO 测试暂停功能 stopFlow() { this.$EventHub.emit('Flow:stop'); } diff --git a/src/ControlPanel/Mirror.js b/src/ControlPanel/Mirror.js index 2a49c8d..c92320b 100644 --- a/src/ControlPanel/Mirror.js +++ b/src/ControlPanel/Mirror.js @@ -1,8 +1,8 @@ // ! Mirror 是 ControlPanel 的 ViewModel // ! 继承 Mirror 可以实现一个 User Interface -export default class Mirror { - constructor(ControlPanel) {} - play() - stop() - AllTasks -} +// export default class Mirror { +// constructor(ControlPanel) {} +// play() +// stop() +// AllTasks +// } diff --git a/src/ControlPanel/StaticEvent.js b/src/ControlPanel/StaticEvent.js index 8c4c77b..b53e4c2 100644 --- a/src/ControlPanel/StaticEvent.js +++ b/src/ControlPanel/StaticEvent.js @@ -6,21 +6,22 @@ export default { this.state = state; }, 'Flow:stop'() { - this.#stop = true; + this._stop = true; }, 'Flow:start'() { - this.#stop = false; + this._stop = false; }, - // runPipeline() {}, // 这个函数没有必要监听是因为 rxjs 代理了这个事件 - 'Task:success'(task) {}, - 'Task:error'(error) { - console.log(error); - }, - 'Task:complete'() { + + // 'Flow:input'() {} + // 'Spider:clearFlow'(){} + 'Task:success'(task) { task.$commit('complete'); if (task instanceof TaskGroup) { task.$destroy(); } - console.log('所有情况完成'); }, + 'Task:error'(error) { + console.log(error); + }, + 'Task:complete'() {}, }; diff --git a/src/Spider/index.js b/src/Spider/index.js index 764d546..4e75433 100644 --- a/src/Spider/index.js +++ b/src/Spider/index.js @@ -2,34 +2,29 @@ * @Author: KonghaYao * @Date: 2021-07-13 15:33:08 * @Last Modified by: KonghaYao - * @Last Modified time: 2021-07-19 11:26:55 + * @Last Modified time: 2021-07-19 16:34:32 */ // Spider 是 JSpider 的爬虫流程工具,主要目的是爬取文件,负责如何爬取文件与数据。 -import { EventHub } from '../ControlPanel/EventHub.js'; +import { EventHub } from '../utils/EventHub.js'; import { staticEvent } from './staticEvent'; import { Pipeline } from '../Pipeline/index'; import ControlPanel from '../ControlPanel/index.js'; // TODO 未完成接口的接入 export class Spider { - infoList = new WeakSet(); // Client 端的缓存数据 constructor(config = {}) { this.config = config; - this.EventHub = new EventHub(staticEvent, this); // 注册静态事件 + this.$EventHub = new EventHub(staticEvent, this); // 注册静态事件 } crawl(...args) { - this.infoList.set(...args.flat()); + ControlPanel.createFlow(args.flat()); return this; } pipeline(...plugins) { ControlPanel.pipeline = new Pipeline(plugins); } start() { - ControlPanel.createFlow(this.infoList).enQueue(() => { - // 清除缓存 - this.infoList.clear(); - this.infoList = new WeakSet(); - }); + ControlPanel.startFlow(); } stop() { ControlPanel.stopFlow(); diff --git a/src/TaskSystem/Task.js b/src/TaskSystem/Task.js index bf0461c..a1cc0c9 100644 --- a/src/TaskSystem/Task.js +++ b/src/TaskSystem/Task.js @@ -1,4 +1,4 @@ -import { EventHub } from '../ControlPanel/EventHub'; +import { EventHub } from '../utils/EventHub'; import { staticEvent } from './StaticEvent'; import { Data } from './Data'; // 属性信息归属于 Data diff --git a/src/ControlPanel/EventHub.js b/src/utils/EventHub.js similarity index 98% rename from src/ControlPanel/EventHub.js rename to src/utils/EventHub.js index 2e3b47e..85e6282 100644 --- a/src/ControlPanel/EventHub.js +++ b/src/utils/EventHub.js @@ -1,5 +1,6 @@ import { fromEventPattern } from 'rxjs'; import { memoize } from 'lodash-es'; + export class EventHub { all = new Map(); constructor(eventMap = {}, bindThis = null) { @@ -47,6 +48,7 @@ export class EventHub { } } emit(type, ...eventParams) { + console.log(type); const handlers = this.all.get(type); return handlers ? handlers.map((handler) => { diff --git a/src/utils/pauseToggle.js b/src/utils/pauseToggle.js new file mode 100644 index 0000000..49599c5 --- /dev/null +++ b/src/utils/pauseToggle.js @@ -0,0 +1,35 @@ +import { noop, Observable } from 'rxjs'; + +export function pauseToggle(openings, closings) { + return (observable) => + new Observable((subscriber) => { + const buffers = new Set(); + let closingSubscription = false; + const subscription = observable.subscribe( + (value) => { + closingSubscription ? buffers.add(value) : subscriber.next(value); + }, + noop, + () => { + buffers.forEach((item) => subscriber.next(item)); + subscriber.complete(); + }, + ); + const openingSubscription = openings.subscribe(() => { + // 输出所有的 buffer + const emitBuffer = () => { + buffers.forEach((item) => subscriber.next(item)); + buffers.clear(); + closingSubscription.unsubscribe(); + closingSubscription = false; + }; + closingSubscription = closings.subscribe(emitBuffer); + }); + return () => { + buffers.clear(); + subscription.unsubscribe(); + openingSubscription.unsubscribe(); + if (closingSubscription) closingSubscription.unsubscribe(); + }; + }); +} diff --git a/src/utils/pauseWhile.js b/src/utils/pauseWhile.js deleted file mode 100644 index 3ecb8f5..0000000 --- a/src/utils/pauseWhile.js +++ /dev/null @@ -1,15 +0,0 @@ -export const pauseWhile = (pauseFunc) => { - const cache = []; - return (source) => - source.pipe( - switchMap((value) => { - if (pauseFunc(value)) { - cache.push(value); - console.log('save ', value); - return EMPTY; - } else { - return from([...cache, value]).pipe(tap(() => (cache.length = 0))); - } - }), - ); -}; diff --git a/test/Request.js b/test/Request.js index 2969a49..0afe0e1 100644 --- a/test/Request.js +++ b/test/Request.js @@ -9,7 +9,7 @@ const { const { Plugin } = JSpider; // 您的爬取路径代码 -const urls = [...Array(2).keys()].map((i, index) => { +const urls = [...Array(5).keys()].map((i, index) => { return { url: '/fake/excel' }; }); @@ -19,12 +19,12 @@ export async function main() { spider.pipeline( Request({ delay: 2000, buffer: 2, retry: 3, handleError: null }), - ExcelHelper({ - XLSXOptions: { - bookType: 'csv', // 可以指定为 csv 或者 xlsx - }, - }), - ZipFile({ chunk: 2 }), + // ExcelHelper({ + // XLSXOptions: { + // bookType: 'csv', // 可以指定为 csv 或者 xlsx + // }, + // }), + // ZipFile({ chunk: 2 }), Plugin((data) => { console.log(data); return data; @@ -32,5 +32,6 @@ export async function main() { // Download(), ); - spider.crawl(urls).start(); + spider.crawl(urls); + window.spider = spider; } diff --git a/test/ZipTest.js b/test/ZipTest.js deleted file mode 100644 index 0b07e0a..0000000 --- a/test/ZipTest.js +++ /dev/null @@ -1,34 +0,0 @@ -// 测试 基础 Plugins 的代码 -import JSpider from "../dist/JSpider.esm.min.js"; -const { Request, Download, ZipFile, ExcelHelper } = JSpider.plugins; -const { Plugin } = JSpider; - -// 您的爬取路径代码 -let urls = [...Array(5).keys()].map((i, index) => { - return { url: "/fake/excel" }; -}); - -async function main() { - const spider = new JSpider( - Request(), - // ExcelHelper( - // { - // XLSXOptions: { - // bookType: "csv", // 可以指定为 csv 或者 xlsx - // }, - // } - // ) - ZipFile({ - chunk: 2 - }), - Plugin((task) => { - console.log(task); - return task; - }) - - // Download() - ); - spider.apply(urls); -} - -export { main as ZipTest }; diff --git a/test/test.js b/test/test.js index 4c6031d..2ee43c6 100644 --- a/test/test.js +++ b/test/test.js @@ -1,7 +1,8 @@ const mitt = require('mitt'); -const { iif } = require('rxjs'); -const { EMPTY } = require('rxjs'); -const { of, from, pipe, fromEventPattern, timer, interval } = require('rxjs'); +const { EMPTY, iif, of, from, pipe, fromEventPattern, timer, interval, Observable } = require('rxjs'); +const { Subscription } = require('rxjs'); + +const { noop } = require('rxjs'); const { map, switchMap, @@ -23,31 +24,46 @@ const { takeUntil, switchMapTo, exhaustMap, + concat, } = require('rxjs/operators'); const emitter = mitt(); const pause$ = fromEventPattern((handle) => emitter.on('pause', handle)); -const pauseWhile = (pauseFunc) => { - const cache = []; - return (source) => - source.pipe( - switchMap((value) => { - if (pauseFunc(value)) { - cache.push(value); - console.log('save ', value); - return EMPTY; - } else { - return from([...cache, value]).pipe(tap(() => (cache.length = 0))); - } - }), - ); -}; -const source$ = interval(300).pipe( - pauseWhile((val) => { - return val % 5; - }), - take(14), -); +function pauseToggle(openings, closings) { + return (observable) => + new Observable((subscriber) => { + const buffers = new Set(); + let closingSubscription = false; + const subscription = observable.subscribe( + (value) => { + closingSubscription ? buffers.add(value) : subscriber.next(value); + }, + noop, + () => { + buffers.forEach((item) => subscriber.next(item)); + subscriber.complete(); + }, + ); + + const openingSubscription = openings.subscribe(() => { + const emitBuffer = () => { + buffers.forEach((item) => subscriber.next(item)); + buffers.clear(); + closingSubscription.unsubscribe(); + closingSubscription = false; + }; + closingSubscription = closings.subscribe(emitBuffer); + }); + return () => { + buffers.clear(); + subscription.unsubscribe(); + openingSubscription.unsubscribe(); + if (closingSubscription) closingSubscription.unsubscribe(); + }; + }); +} +const source$ = interval(100).pipe(take(14), pauseToggle(interval(500), interval(200))); + const startTime = new Date().getTime(); const compare = () => Math.ceil((new Date().getTime() - startTime) / 100); source$.subscribe((val) => console.log(compare(), val));