' + func(text) + '
';\n * });\n *\n * p('fred, barney, & pebbles');\n * // => 'fred, barney, & pebbles
'\n */\n function wrap(value, wrapper) {\n return partial(castFunction(wrapper), value);\n }\n\n /*------------------------------------------------------------------------*/\n\n /**\n * Casts `value` as an array if it's not one.\n *\n * @static\n * @memberOf _\n * @since 4.4.0\n * @category Lang\n * @param {*} value The value to inspect.\n * @returns {Array} Returns the cast array.\n * @example\n *\n * _.castArray(1);\n * // => [1]\n *\n * _.castArray({ 'a': 1 });\n * // => [{ 'a': 1 }]\n *\n * _.castArray('abc');\n * // => ['abc']\n *\n * _.castArray(null);\n * // => [null]\n *\n * _.castArray(undefined);\n * // => [undefined]\n *\n * _.castArray();\n * // => []\n *\n * var array = [1, 2, 3];\n * console.log(_.castArray(array) === array);\n * // => true\n */\n function castArray() {\n if (!arguments.length) {\n return [];\n }\n var value = arguments[0];\n return isArray(value) ? value : [value];\n }\n\n /**\n * Creates a shallow clone of `value`.\n *\n * **Note:** This method is loosely based on the\n * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm)\n * and supports cloning arrays, array buffers, booleans, date objects, maps,\n * numbers, `Object` objects, regexes, sets, strings, symbols, and typed\n * arrays. The own enumerable properties of `arguments` objects are cloned\n * as plain objects. An empty object is returned for uncloneable values such\n * as error objects, functions, DOM nodes, and WeakMaps.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to clone.\n * @returns {*} Returns the cloned value.\n * @see _.cloneDeep\n * @example\n *\n * var objects = [{ 'a': 1 }, { 'b': 2 }];\n *\n * var shallow = _.clone(objects);\n * console.log(shallow[0] === objects[0]);\n * // => true\n */\n function clone(value) {\n return baseClone(value, CLONE_SYMBOLS_FLAG);\n }\n\n /**\n * This method is like `_.clone` except that it accepts `customizer` which\n * is invoked to produce the cloned value. If `customizer` returns `undefined`,\n * cloning is handled by the method instead. The `customizer` is invoked with\n * up to four arguments; (value [, index|key, object, stack]).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to clone.\n * @param {Function} [customizer] The function to customize cloning.\n * @returns {*} Returns the cloned value.\n * @see _.cloneDeepWith\n * @example\n *\n * function customizer(value) {\n * if (_.isElement(value)) {\n * return value.cloneNode(false);\n * }\n * }\n *\n * var el = _.cloneWith(document.body, customizer);\n *\n * console.log(el === document.body);\n * // => false\n * console.log(el.nodeName);\n * // => 'BODY'\n * console.log(el.childNodes.length);\n * // => 0\n */\n function cloneWith(value, customizer) {\n customizer = typeof customizer == 'function' ? customizer : undefined;\n return baseClone(value, CLONE_SYMBOLS_FLAG, customizer);\n }\n\n /**\n * This method is like `_.clone` except that it recursively clones `value`.\n *\n * @static\n * @memberOf _\n * @since 1.0.0\n * @category Lang\n * @param {*} value The value to recursively clone.\n * @returns {*} Returns the deep cloned value.\n * @see _.clone\n * @example\n *\n * var objects = [{ 'a': 1 }, { 'b': 2 }];\n *\n * var deep = _.cloneDeep(objects);\n * console.log(deep[0] === objects[0]);\n * // => false\n */\n function cloneDeep(value) {\n return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG);\n }\n\n /**\n * This method is like `_.cloneWith` except that it recursively clones `value`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to recursively clone.\n * @param {Function} [customizer] The function to customize cloning.\n * @returns {*} Returns the deep cloned value.\n * @see _.cloneWith\n * @example\n *\n * function customizer(value) {\n * if (_.isElement(value)) {\n * return value.cloneNode(true);\n * }\n * }\n *\n * var el = _.cloneDeepWith(document.body, customizer);\n *\n * console.log(el === document.body);\n * // => false\n * console.log(el.nodeName);\n * // => 'BODY'\n * console.log(el.childNodes.length);\n * // => 20\n */\n function cloneDeepWith(value, customizer) {\n customizer = typeof customizer == 'function' ? customizer : undefined;\n return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG, customizer);\n }\n\n /**\n * Checks if `object` conforms to `source` by invoking the predicate\n * properties of `source` with the corresponding property values of `object`.\n *\n * **Note:** This method is equivalent to `_.conforms` when `source` is\n * partially applied.\n *\n * @static\n * @memberOf _\n * @since 4.14.0\n * @category Lang\n * @param {Object} object The object to inspect.\n * @param {Object} source The object of property predicates to conform to.\n * @returns {boolean} Returns `true` if `object` conforms, else `false`.\n * @example\n *\n * var object = { 'a': 1, 'b': 2 };\n *\n * _.conformsTo(object, { 'b': function(n) { return n > 1; } });\n * // => true\n *\n * _.conformsTo(object, { 'b': function(n) { return n > 2; } });\n * // => false\n */\n function conformsTo(object, source) {\n return source == null || baseConformsTo(object, source, keys(source));\n }\n\n /**\n * Performs a\n * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero)\n * comparison between two values to determine if they are equivalent.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.eq(object, object);\n * // => true\n *\n * _.eq(object, other);\n * // => false\n *\n * _.eq('a', 'a');\n * // => true\n *\n * _.eq('a', Object('a'));\n * // => false\n *\n * _.eq(NaN, NaN);\n * // => true\n */\n function eq(value, other) {\n return value === other || (value !== value && other !== other);\n }\n\n /**\n * Checks if `value` is greater than `other`.\n *\n * @static\n * @memberOf _\n * @since 3.9.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if `value` is greater than `other`,\n * else `false`.\n * @see _.lt\n * @example\n *\n * _.gt(3, 1);\n * // => true\n *\n * _.gt(3, 3);\n * // => false\n *\n * _.gt(1, 3);\n * // => false\n */\n var gt = createRelationalOperation(baseGt);\n\n /**\n * Checks if `value` is greater than or equal to `other`.\n *\n * @static\n * @memberOf _\n * @since 3.9.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if `value` is greater than or equal to\n * `other`, else `false`.\n * @see _.lte\n * @example\n *\n * _.gte(3, 1);\n * // => true\n *\n * _.gte(3, 3);\n * // => true\n *\n * _.gte(1, 3);\n * // => false\n */\n var gte = createRelationalOperation(function(value, other) {\n return value >= other;\n });\n\n /**\n * Checks if `value` is likely an `arguments` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an `arguments` object,\n * else `false`.\n * @example\n *\n * _.isArguments(function() { return arguments; }());\n * // => true\n *\n * _.isArguments([1, 2, 3]);\n * // => false\n */\n var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) {\n return isObjectLike(value) && hasOwnProperty.call(value, 'callee') &&\n !propertyIsEnumerable.call(value, 'callee');\n };\n\n /**\n * Checks if `value` is classified as an `Array` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array, else `false`.\n * @example\n *\n * _.isArray([1, 2, 3]);\n * // => true\n *\n * _.isArray(document.body.children);\n * // => false\n *\n * _.isArray('abc');\n * // => false\n *\n * _.isArray(_.noop);\n * // => false\n */\n var isArray = Array.isArray;\n\n /**\n * Checks if `value` is classified as an `ArrayBuffer` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array buffer, else `false`.\n * @example\n *\n * _.isArrayBuffer(new ArrayBuffer(2));\n * // => true\n *\n * _.isArrayBuffer(new Array(2));\n * // => false\n */\n var isArrayBuffer = nodeIsArrayBuffer ? baseUnary(nodeIsArrayBuffer) : baseIsArrayBuffer;\n\n /**\n * Checks if `value` is array-like. A value is considered array-like if it's\n * not a function and has a `value.length` that's an integer greater than or\n * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is array-like, else `false`.\n * @example\n *\n * _.isArrayLike([1, 2, 3]);\n * // => true\n *\n * _.isArrayLike(document.body.children);\n * // => true\n *\n * _.isArrayLike('abc');\n * // => true\n *\n * _.isArrayLike(_.noop);\n * // => false\n */\n function isArrayLike(value) {\n return value != null && isLength(value.length) && !isFunction(value);\n }\n\n /**\n * This method is like `_.isArrayLike` except that it also checks if `value`\n * is an object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an array-like object,\n * else `false`.\n * @example\n *\n * _.isArrayLikeObject([1, 2, 3]);\n * // => true\n *\n * _.isArrayLikeObject(document.body.children);\n * // => true\n *\n * _.isArrayLikeObject('abc');\n * // => false\n *\n * _.isArrayLikeObject(_.noop);\n * // => false\n */\n function isArrayLikeObject(value) {\n return isObjectLike(value) && isArrayLike(value);\n }\n\n /**\n * Checks if `value` is classified as a boolean primitive or object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a boolean, else `false`.\n * @example\n *\n * _.isBoolean(false);\n * // => true\n *\n * _.isBoolean(null);\n * // => false\n */\n function isBoolean(value) {\n return value === true || value === false ||\n (isObjectLike(value) && baseGetTag(value) == boolTag);\n }\n\n /**\n * Checks if `value` is a buffer.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a buffer, else `false`.\n * @example\n *\n * _.isBuffer(new Buffer(2));\n * // => true\n *\n * _.isBuffer(new Uint8Array(2));\n * // => false\n */\n var isBuffer = nativeIsBuffer || stubFalse;\n\n /**\n * Checks if `value` is classified as a `Date` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a date object, else `false`.\n * @example\n *\n * _.isDate(new Date);\n * // => true\n *\n * _.isDate('Mon April 23 2012');\n * // => false\n */\n var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate;\n\n /**\n * Checks if `value` is likely a DOM element.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a DOM element, else `false`.\n * @example\n *\n * _.isElement(document.body);\n * // => true\n *\n * _.isElement('');\n * // => false\n */\n function isElement(value) {\n return isObjectLike(value) && value.nodeType === 1 && !isPlainObject(value);\n }\n\n /**\n * Checks if `value` is an empty object, collection, map, or set.\n *\n * Objects are considered empty if they have no own enumerable string keyed\n * properties.\n *\n * Array-like values such as `arguments` objects, arrays, buffers, strings, or\n * jQuery-like collections are considered empty if they have a `length` of `0`.\n * Similarly, maps and sets are considered empty if they have a `size` of `0`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is empty, else `false`.\n * @example\n *\n * _.isEmpty(null);\n * // => true\n *\n * _.isEmpty(true);\n * // => true\n *\n * _.isEmpty(1);\n * // => true\n *\n * _.isEmpty([1, 2, 3]);\n * // => false\n *\n * _.isEmpty({ 'a': 1 });\n * // => false\n */\n function isEmpty(value) {\n if (value == null) {\n return true;\n }\n if (isArrayLike(value) &&\n (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' ||\n isBuffer(value) || isTypedArray(value) || isArguments(value))) {\n return !value.length;\n }\n var tag = getTag(value);\n if (tag == mapTag || tag == setTag) {\n return !value.size;\n }\n if (isPrototype(value)) {\n return !baseKeys(value).length;\n }\n for (var key in value) {\n if (hasOwnProperty.call(value, key)) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Performs a deep comparison between two values to determine if they are\n * equivalent.\n *\n * **Note:** This method supports comparing arrays, array buffers, booleans,\n * date objects, error objects, maps, numbers, `Object` objects, regexes,\n * sets, strings, symbols, and typed arrays. `Object` objects are compared\n * by their own, not inherited, enumerable properties. Functions and DOM\n * nodes are compared by strict equality, i.e. `===`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * var object = { 'a': 1 };\n * var other = { 'a': 1 };\n *\n * _.isEqual(object, other);\n * // => true\n *\n * object === other;\n * // => false\n */\n function isEqual(value, other) {\n return baseIsEqual(value, other);\n }\n\n /**\n * This method is like `_.isEqual` except that it accepts `customizer` which\n * is invoked to compare values. If `customizer` returns `undefined`, comparisons\n * are handled by the method instead. The `customizer` is invoked with up to\n * six arguments: (objValue, othValue [, index|key, object, other, stack]).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @param {Function} [customizer] The function to customize comparisons.\n * @returns {boolean} Returns `true` if the values are equivalent, else `false`.\n * @example\n *\n * function isGreeting(value) {\n * return /^h(?:i|ello)$/.test(value);\n * }\n *\n * function customizer(objValue, othValue) {\n * if (isGreeting(objValue) && isGreeting(othValue)) {\n * return true;\n * }\n * }\n *\n * var array = ['hello', 'goodbye'];\n * var other = ['hi', 'goodbye'];\n *\n * _.isEqualWith(array, other, customizer);\n * // => true\n */\n function isEqualWith(value, other, customizer) {\n customizer = typeof customizer == 'function' ? customizer : undefined;\n var result = customizer ? customizer(value, other) : undefined;\n return result === undefined ? baseIsEqual(value, other, undefined, customizer) : !!result;\n }\n\n /**\n * Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,\n * `SyntaxError`, `TypeError`, or `URIError` object.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an error object, else `false`.\n * @example\n *\n * _.isError(new Error);\n * // => true\n *\n * _.isError(Error);\n * // => false\n */\n function isError(value) {\n if (!isObjectLike(value)) {\n return false;\n }\n var tag = baseGetTag(value);\n return tag == errorTag || tag == domExcTag ||\n (typeof value.message == 'string' && typeof value.name == 'string' && !isPlainObject(value));\n }\n\n /**\n * Checks if `value` is a finite primitive number.\n *\n * **Note:** This method is based on\n * [`Number.isFinite`](https://mdn.io/Number/isFinite).\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a finite number, else `false`.\n * @example\n *\n * _.isFinite(3);\n * // => true\n *\n * _.isFinite(Number.MIN_VALUE);\n * // => true\n *\n * _.isFinite(Infinity);\n * // => false\n *\n * _.isFinite('3');\n * // => false\n */\n function isFinite(value) {\n return typeof value == 'number' && nativeIsFinite(value);\n }\n\n /**\n * Checks if `value` is classified as a `Function` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a function, else `false`.\n * @example\n *\n * _.isFunction(_);\n * // => true\n *\n * _.isFunction(/abc/);\n * // => false\n */\n function isFunction(value) {\n if (!isObject(value)) {\n return false;\n }\n // The use of `Object#toString` avoids issues with the `typeof` operator\n // in Safari 9 which returns 'object' for typed arrays and other constructors.\n var tag = baseGetTag(value);\n return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag;\n }\n\n /**\n * Checks if `value` is an integer.\n *\n * **Note:** This method is based on\n * [`Number.isInteger`](https://mdn.io/Number/isInteger).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an integer, else `false`.\n * @example\n *\n * _.isInteger(3);\n * // => true\n *\n * _.isInteger(Number.MIN_VALUE);\n * // => false\n *\n * _.isInteger(Infinity);\n * // => false\n *\n * _.isInteger('3');\n * // => false\n */\n function isInteger(value) {\n return typeof value == 'number' && value == toInteger(value);\n }\n\n /**\n * Checks if `value` is a valid array-like length.\n *\n * **Note:** This method is loosely based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a valid length, else `false`.\n * @example\n *\n * _.isLength(3);\n * // => true\n *\n * _.isLength(Number.MIN_VALUE);\n * // => false\n *\n * _.isLength(Infinity);\n * // => false\n *\n * _.isLength('3');\n * // => false\n */\n function isLength(value) {\n return typeof value == 'number' &&\n value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;\n }\n\n /**\n * Checks if `value` is the\n * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types)\n * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`)\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is an object, else `false`.\n * @example\n *\n * _.isObject({});\n * // => true\n *\n * _.isObject([1, 2, 3]);\n * // => true\n *\n * _.isObject(_.noop);\n * // => true\n *\n * _.isObject(null);\n * // => false\n */\n function isObject(value) {\n var type = typeof value;\n return value != null && (type == 'object' || type == 'function');\n }\n\n /**\n * Checks if `value` is object-like. A value is object-like if it's not `null`\n * and has a `typeof` result of \"object\".\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is object-like, else `false`.\n * @example\n *\n * _.isObjectLike({});\n * // => true\n *\n * _.isObjectLike([1, 2, 3]);\n * // => true\n *\n * _.isObjectLike(_.noop);\n * // => false\n *\n * _.isObjectLike(null);\n * // => false\n */\n function isObjectLike(value) {\n return value != null && typeof value == 'object';\n }\n\n /**\n * Checks if `value` is classified as a `Map` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a map, else `false`.\n * @example\n *\n * _.isMap(new Map);\n * // => true\n *\n * _.isMap(new WeakMap);\n * // => false\n */\n var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap;\n\n /**\n * Performs a partial deep comparison between `object` and `source` to\n * determine if `object` contains equivalent property values.\n *\n * **Note:** This method is equivalent to `_.matches` when `source` is\n * partially applied.\n *\n * Partial comparisons will match empty array and empty object `source`\n * values against any array or object value, respectively. See `_.isEqual`\n * for a list of supported value comparisons.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {Object} object The object to inspect.\n * @param {Object} source The object of property values to match.\n * @returns {boolean} Returns `true` if `object` is a match, else `false`.\n * @example\n *\n * var object = { 'a': 1, 'b': 2 };\n *\n * _.isMatch(object, { 'b': 2 });\n * // => true\n *\n * _.isMatch(object, { 'b': 1 });\n * // => false\n */\n function isMatch(object, source) {\n return object === source || baseIsMatch(object, source, getMatchData(source));\n }\n\n /**\n * This method is like `_.isMatch` except that it accepts `customizer` which\n * is invoked to compare values. If `customizer` returns `undefined`, comparisons\n * are handled by the method instead. The `customizer` is invoked with five\n * arguments: (objValue, srcValue, index|key, object, source).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {Object} object The object to inspect.\n * @param {Object} source The object of property values to match.\n * @param {Function} [customizer] The function to customize comparisons.\n * @returns {boolean} Returns `true` if `object` is a match, else `false`.\n * @example\n *\n * function isGreeting(value) {\n * return /^h(?:i|ello)$/.test(value);\n * }\n *\n * function customizer(objValue, srcValue) {\n * if (isGreeting(objValue) && isGreeting(srcValue)) {\n * return true;\n * }\n * }\n *\n * var object = { 'greeting': 'hello' };\n * var source = { 'greeting': 'hi' };\n *\n * _.isMatchWith(object, source, customizer);\n * // => true\n */\n function isMatchWith(object, source, customizer) {\n customizer = typeof customizer == 'function' ? customizer : undefined;\n return baseIsMatch(object, source, getMatchData(source), customizer);\n }\n\n /**\n * Checks if `value` is `NaN`.\n *\n * **Note:** This method is based on\n * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as\n * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for\n * `undefined` and other non-number values.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`.\n * @example\n *\n * _.isNaN(NaN);\n * // => true\n *\n * _.isNaN(new Number(NaN));\n * // => true\n *\n * isNaN(undefined);\n * // => true\n *\n * _.isNaN(undefined);\n * // => false\n */\n function isNaN(value) {\n // An `NaN` primitive is the only value that is not equal to itself.\n // Perform the `toStringTag` check first to avoid errors with some\n // ActiveX objects in IE.\n return isNumber(value) && value != +value;\n }\n\n /**\n * Checks if `value` is a pristine native function.\n *\n * **Note:** This method can't reliably detect native functions in the presence\n * of the core-js package because core-js circumvents this kind of detection.\n * Despite multiple requests, the core-js maintainer has made it clear: any\n * attempt to fix the detection will be obstructed. As a result, we're left\n * with little choice but to throw an error. Unfortunately, this also affects\n * packages, like [babel-polyfill](https://www.npmjs.com/package/babel-polyfill),\n * which rely on core-js.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a native function,\n * else `false`.\n * @example\n *\n * _.isNative(Array.prototype.push);\n * // => true\n *\n * _.isNative(_);\n * // => false\n */\n function isNative(value) {\n if (isMaskable(value)) {\n throw new Error(CORE_ERROR_TEXT);\n }\n return baseIsNative(value);\n }\n\n /**\n * Checks if `value` is `null`.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is `null`, else `false`.\n * @example\n *\n * _.isNull(null);\n * // => true\n *\n * _.isNull(void 0);\n * // => false\n */\n function isNull(value) {\n return value === null;\n }\n\n /**\n * Checks if `value` is `null` or `undefined`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is nullish, else `false`.\n * @example\n *\n * _.isNil(null);\n * // => true\n *\n * _.isNil(void 0);\n * // => true\n *\n * _.isNil(NaN);\n * // => false\n */\n function isNil(value) {\n return value == null;\n }\n\n /**\n * Checks if `value` is classified as a `Number` primitive or object.\n *\n * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are\n * classified as numbers, use the `_.isFinite` method.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a number, else `false`.\n * @example\n *\n * _.isNumber(3);\n * // => true\n *\n * _.isNumber(Number.MIN_VALUE);\n * // => true\n *\n * _.isNumber(Infinity);\n * // => true\n *\n * _.isNumber('3');\n * // => false\n */\n function isNumber(value) {\n return typeof value == 'number' ||\n (isObjectLike(value) && baseGetTag(value) == numberTag);\n }\n\n /**\n * Checks if `value` is a plain object, that is, an object created by the\n * `Object` constructor or one with a `[[Prototype]]` of `null`.\n *\n * @static\n * @memberOf _\n * @since 0.8.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a plain object, else `false`.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * }\n *\n * _.isPlainObject(new Foo);\n * // => false\n *\n * _.isPlainObject([1, 2, 3]);\n * // => false\n *\n * _.isPlainObject({ 'x': 0, 'y': 0 });\n * // => true\n *\n * _.isPlainObject(Object.create(null));\n * // => true\n */\n function isPlainObject(value) {\n if (!isObjectLike(value) || baseGetTag(value) != objectTag) {\n return false;\n }\n var proto = getPrototype(value);\n if (proto === null) {\n return true;\n }\n var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;\n return typeof Ctor == 'function' && Ctor instanceof Ctor &&\n funcToString.call(Ctor) == objectCtorString;\n }\n\n /**\n * Checks if `value` is classified as a `RegExp` object.\n *\n * @static\n * @memberOf _\n * @since 0.1.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a regexp, else `false`.\n * @example\n *\n * _.isRegExp(/abc/);\n * // => true\n *\n * _.isRegExp('/abc/');\n * // => false\n */\n var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp;\n\n /**\n * Checks if `value` is a safe integer. An integer is safe if it's an IEEE-754\n * double precision number which isn't the result of a rounded unsafe integer.\n *\n * **Note:** This method is based on\n * [`Number.isSafeInteger`](https://mdn.io/Number/isSafeInteger).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a safe integer, else `false`.\n * @example\n *\n * _.isSafeInteger(3);\n * // => true\n *\n * _.isSafeInteger(Number.MIN_VALUE);\n * // => false\n *\n * _.isSafeInteger(Infinity);\n * // => false\n *\n * _.isSafeInteger('3');\n * // => false\n */\n function isSafeInteger(value) {\n return isInteger(value) && value >= -MAX_SAFE_INTEGER && value <= MAX_SAFE_INTEGER;\n }\n\n /**\n * Checks if `value` is classified as a `Set` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a set, else `false`.\n * @example\n *\n * _.isSet(new Set);\n * // => true\n *\n * _.isSet(new WeakSet);\n * // => false\n */\n var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;\n\n /**\n * Checks if `value` is classified as a `String` primitive or object.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a string, else `false`.\n * @example\n *\n * _.isString('abc');\n * // => true\n *\n * _.isString(1);\n * // => false\n */\n function isString(value) {\n return typeof value == 'string' ||\n (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag);\n }\n\n /**\n * Checks if `value` is classified as a `Symbol` primitive or object.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a symbol, else `false`.\n * @example\n *\n * _.isSymbol(Symbol.iterator);\n * // => true\n *\n * _.isSymbol('abc');\n * // => false\n */\n function isSymbol(value) {\n return typeof value == 'symbol' ||\n (isObjectLike(value) && baseGetTag(value) == symbolTag);\n }\n\n /**\n * Checks if `value` is classified as a typed array.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a typed array, else `false`.\n * @example\n *\n * _.isTypedArray(new Uint8Array);\n * // => true\n *\n * _.isTypedArray([]);\n * // => false\n */\n var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray;\n\n /**\n * Checks if `value` is `undefined`.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`.\n * @example\n *\n * _.isUndefined(void 0);\n * // => true\n *\n * _.isUndefined(null);\n * // => false\n */\n function isUndefined(value) {\n return value === undefined;\n }\n\n /**\n * Checks if `value` is classified as a `WeakMap` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a weak map, else `false`.\n * @example\n *\n * _.isWeakMap(new WeakMap);\n * // => true\n *\n * _.isWeakMap(new Map);\n * // => false\n */\n function isWeakMap(value) {\n return isObjectLike(value) && getTag(value) == weakMapTag;\n }\n\n /**\n * Checks if `value` is classified as a `WeakSet` object.\n *\n * @static\n * @memberOf _\n * @since 4.3.0\n * @category Lang\n * @param {*} value The value to check.\n * @returns {boolean} Returns `true` if `value` is a weak set, else `false`.\n * @example\n *\n * _.isWeakSet(new WeakSet);\n * // => true\n *\n * _.isWeakSet(new Set);\n * // => false\n */\n function isWeakSet(value) {\n return isObjectLike(value) && baseGetTag(value) == weakSetTag;\n }\n\n /**\n * Checks if `value` is less than `other`.\n *\n * @static\n * @memberOf _\n * @since 3.9.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if `value` is less than `other`,\n * else `false`.\n * @see _.gt\n * @example\n *\n * _.lt(1, 3);\n * // => true\n *\n * _.lt(3, 3);\n * // => false\n *\n * _.lt(3, 1);\n * // => false\n */\n var lt = createRelationalOperation(baseLt);\n\n /**\n * Checks if `value` is less than or equal to `other`.\n *\n * @static\n * @memberOf _\n * @since 3.9.0\n * @category Lang\n * @param {*} value The value to compare.\n * @param {*} other The other value to compare.\n * @returns {boolean} Returns `true` if `value` is less than or equal to\n * `other`, else `false`.\n * @see _.gte\n * @example\n *\n * _.lte(1, 3);\n * // => true\n *\n * _.lte(3, 3);\n * // => true\n *\n * _.lte(3, 1);\n * // => false\n */\n var lte = createRelationalOperation(function(value, other) {\n return value <= other;\n });\n\n /**\n * Converts `value` to an array.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {Array} Returns the converted array.\n * @example\n *\n * _.toArray({ 'a': 1, 'b': 2 });\n * // => [1, 2]\n *\n * _.toArray('abc');\n * // => ['a', 'b', 'c']\n *\n * _.toArray(1);\n * // => []\n *\n * _.toArray(null);\n * // => []\n */\n function toArray(value) {\n if (!value) {\n return [];\n }\n if (isArrayLike(value)) {\n return isString(value) ? stringToArray(value) : copyArray(value);\n }\n if (symIterator && value[symIterator]) {\n return iteratorToArray(value[symIterator]());\n }\n var tag = getTag(value),\n func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values);\n\n return func(value);\n }\n\n /**\n * Converts `value` to a finite number.\n *\n * @static\n * @memberOf _\n * @since 4.12.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {number} Returns the converted number.\n * @example\n *\n * _.toFinite(3.2);\n * // => 3.2\n *\n * _.toFinite(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toFinite(Infinity);\n * // => 1.7976931348623157e+308\n *\n * _.toFinite('3.2');\n * // => 3.2\n */\n function toFinite(value) {\n if (!value) {\n return value === 0 ? value : 0;\n }\n value = toNumber(value);\n if (value === INFINITY || value === -INFINITY) {\n var sign = (value < 0 ? -1 : 1);\n return sign * MAX_INTEGER;\n }\n return value === value ? value : 0;\n }\n\n /**\n * Converts `value` to an integer.\n *\n * **Note:** This method is loosely based on\n * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {number} Returns the converted integer.\n * @example\n *\n * _.toInteger(3.2);\n * // => 3\n *\n * _.toInteger(Number.MIN_VALUE);\n * // => 0\n *\n * _.toInteger(Infinity);\n * // => 1.7976931348623157e+308\n *\n * _.toInteger('3.2');\n * // => 3\n */\n function toInteger(value) {\n var result = toFinite(value),\n remainder = result % 1;\n\n return result === result ? (remainder ? result - remainder : result) : 0;\n }\n\n /**\n * Converts `value` to an integer suitable for use as the length of an\n * array-like object.\n *\n * **Note:** This method is based on\n * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {number} Returns the converted integer.\n * @example\n *\n * _.toLength(3.2);\n * // => 3\n *\n * _.toLength(Number.MIN_VALUE);\n * // => 0\n *\n * _.toLength(Infinity);\n * // => 4294967295\n *\n * _.toLength('3.2');\n * // => 3\n */\n function toLength(value) {\n return value ? baseClamp(toInteger(value), 0, MAX_ARRAY_LENGTH) : 0;\n }\n\n /**\n * Converts `value` to a number.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to process.\n * @returns {number} Returns the number.\n * @example\n *\n * _.toNumber(3.2);\n * // => 3.2\n *\n * _.toNumber(Number.MIN_VALUE);\n * // => 5e-324\n *\n * _.toNumber(Infinity);\n * // => Infinity\n *\n * _.toNumber('3.2');\n * // => 3.2\n */\n function toNumber(value) {\n if (typeof value == 'number') {\n return value;\n }\n if (isSymbol(value)) {\n return NAN;\n }\n if (isObject(value)) {\n var other = typeof value.valueOf == 'function' ? value.valueOf() : value;\n value = isObject(other) ? (other + '') : other;\n }\n if (typeof value != 'string') {\n return value === 0 ? value : +value;\n }\n value = baseTrim(value);\n var isBinary = reIsBinary.test(value);\n return (isBinary || reIsOctal.test(value))\n ? freeParseInt(value.slice(2), isBinary ? 2 : 8)\n : (reIsBadHex.test(value) ? NAN : +value);\n }\n\n /**\n * Converts `value` to a plain object flattening inherited enumerable string\n * keyed properties of `value` to own properties of the plain object.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {Object} Returns the converted plain object.\n * @example\n *\n * function Foo() {\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.assign({ 'a': 1 }, new Foo);\n * // => { 'a': 1, 'b': 2 }\n *\n * _.assign({ 'a': 1 }, _.toPlainObject(new Foo));\n * // => { 'a': 1, 'b': 2, 'c': 3 }\n */\n function toPlainObject(value) {\n return copyObject(value, keysIn(value));\n }\n\n /**\n * Converts `value` to a safe integer. A safe integer can be compared and\n * represented correctly.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {number} Returns the converted integer.\n * @example\n *\n * _.toSafeInteger(3.2);\n * // => 3\n *\n * _.toSafeInteger(Number.MIN_VALUE);\n * // => 0\n *\n * _.toSafeInteger(Infinity);\n * // => 9007199254740991\n *\n * _.toSafeInteger('3.2');\n * // => 3\n */\n function toSafeInteger(value) {\n return value\n ? baseClamp(toInteger(value), -MAX_SAFE_INTEGER, MAX_SAFE_INTEGER)\n : (value === 0 ? value : 0);\n }\n\n /**\n * Converts `value` to a string. An empty string is returned for `null`\n * and `undefined` values. The sign of `-0` is preserved.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Lang\n * @param {*} value The value to convert.\n * @returns {string} Returns the converted string.\n * @example\n *\n * _.toString(null);\n * // => ''\n *\n * _.toString(-0);\n * // => '-0'\n *\n * _.toString([1, 2, 3]);\n * // => '1,2,3'\n */\n function toString(value) {\n return value == null ? '' : baseToString(value);\n }\n\n /*------------------------------------------------------------------------*/\n\n /**\n * Assigns own enumerable string keyed properties of source objects to the\n * destination object. Source objects are applied from left to right.\n * Subsequent sources overwrite property assignments of previous sources.\n *\n * **Note:** This method mutates `object` and is loosely based on\n * [`Object.assign`](https://mdn.io/Object/assign).\n *\n * @static\n * @memberOf _\n * @since 0.10.0\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} [sources] The source objects.\n * @returns {Object} Returns `object`.\n * @see _.assignIn\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * }\n *\n * function Bar() {\n * this.c = 3;\n * }\n *\n * Foo.prototype.b = 2;\n * Bar.prototype.d = 4;\n *\n * _.assign({ 'a': 0 }, new Foo, new Bar);\n * // => { 'a': 1, 'c': 3 }\n */\n var assign = createAssigner(function(object, source) {\n if (isPrototype(source) || isArrayLike(source)) {\n copyObject(source, keys(source), object);\n return;\n }\n for (var key in source) {\n if (hasOwnProperty.call(source, key)) {\n assignValue(object, key, source[key]);\n }\n }\n });\n\n /**\n * This method is like `_.assign` except that it iterates over own and\n * inherited source properties.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @alias extend\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} [sources] The source objects.\n * @returns {Object} Returns `object`.\n * @see _.assign\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * }\n *\n * function Bar() {\n * this.c = 3;\n * }\n *\n * Foo.prototype.b = 2;\n * Bar.prototype.d = 4;\n *\n * _.assignIn({ 'a': 0 }, new Foo, new Bar);\n * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 }\n */\n var assignIn = createAssigner(function(object, source) {\n copyObject(source, keysIn(source), object);\n });\n\n /**\n * This method is like `_.assignIn` except that it accepts `customizer`\n * which is invoked to produce the assigned values. If `customizer` returns\n * `undefined`, assignment is handled by the method instead. The `customizer`\n * is invoked with five arguments: (objValue, srcValue, key, object, source).\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @alias extendWith\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} sources The source objects.\n * @param {Function} [customizer] The function to customize assigned values.\n * @returns {Object} Returns `object`.\n * @see _.assignWith\n * @example\n *\n * function customizer(objValue, srcValue) {\n * return _.isUndefined(objValue) ? srcValue : objValue;\n * }\n *\n * var defaults = _.partialRight(_.assignInWith, customizer);\n *\n * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });\n * // => { 'a': 1, 'b': 2 }\n */\n var assignInWith = createAssigner(function(object, source, srcIndex, customizer) {\n copyObject(source, keysIn(source), object, customizer);\n });\n\n /**\n * This method is like `_.assign` except that it accepts `customizer`\n * which is invoked to produce the assigned values. If `customizer` returns\n * `undefined`, assignment is handled by the method instead. The `customizer`\n * is invoked with five arguments: (objValue, srcValue, key, object, source).\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} sources The source objects.\n * @param {Function} [customizer] The function to customize assigned values.\n * @returns {Object} Returns `object`.\n * @see _.assignInWith\n * @example\n *\n * function customizer(objValue, srcValue) {\n * return _.isUndefined(objValue) ? srcValue : objValue;\n * }\n *\n * var defaults = _.partialRight(_.assignWith, customizer);\n *\n * defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });\n * // => { 'a': 1, 'b': 2 }\n */\n var assignWith = createAssigner(function(object, source, srcIndex, customizer) {\n copyObject(source, keys(source), object, customizer);\n });\n\n /**\n * Creates an array of values corresponding to `paths` of `object`.\n *\n * @static\n * @memberOf _\n * @since 1.0.0\n * @category Object\n * @param {Object} object The object to iterate over.\n * @param {...(string|string[])} [paths] The property paths to pick.\n * @returns {Array} Returns the picked values.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] };\n *\n * _.at(object, ['a[0].b.c', 'a[1]']);\n * // => [3, 4]\n */\n var at = flatRest(baseAt);\n\n /**\n * Creates an object that inherits from the `prototype` object. If a\n * `properties` object is given, its own enumerable string keyed properties\n * are assigned to the created object.\n *\n * @static\n * @memberOf _\n * @since 2.3.0\n * @category Object\n * @param {Object} prototype The object to inherit from.\n * @param {Object} [properties] The properties to assign to the object.\n * @returns {Object} Returns the new object.\n * @example\n *\n * function Shape() {\n * this.x = 0;\n * this.y = 0;\n * }\n *\n * function Circle() {\n * Shape.call(this);\n * }\n *\n * Circle.prototype = _.create(Shape.prototype, {\n * 'constructor': Circle\n * });\n *\n * var circle = new Circle;\n * circle instanceof Circle;\n * // => true\n *\n * circle instanceof Shape;\n * // => true\n */\n function create(prototype, properties) {\n var result = baseCreate(prototype);\n return properties == null ? result : baseAssign(result, properties);\n }\n\n /**\n * Assigns own and inherited enumerable string keyed properties of source\n * objects to the destination object for all destination properties that\n * resolve to `undefined`. Source objects are applied from left to right.\n * Once a property is set, additional values of the same property are ignored.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} [sources] The source objects.\n * @returns {Object} Returns `object`.\n * @see _.defaultsDeep\n * @example\n *\n * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 });\n * // => { 'a': 1, 'b': 2 }\n */\n var defaults = baseRest(function(object, sources) {\n object = Object(object);\n\n var index = -1;\n var length = sources.length;\n var guard = length > 2 ? sources[2] : undefined;\n\n if (guard && isIterateeCall(sources[0], sources[1], guard)) {\n length = 1;\n }\n\n while (++index < length) {\n var source = sources[index];\n var props = keysIn(source);\n var propsIndex = -1;\n var propsLength = props.length;\n\n while (++propsIndex < propsLength) {\n var key = props[propsIndex];\n var value = object[key];\n\n if (value === undefined ||\n (eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))) {\n object[key] = source[key];\n }\n }\n }\n\n return object;\n });\n\n /**\n * This method is like `_.defaults` except that it recursively assigns\n * default properties.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 3.10.0\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} [sources] The source objects.\n * @returns {Object} Returns `object`.\n * @see _.defaults\n * @example\n *\n * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } });\n * // => { 'a': { 'b': 2, 'c': 3 } }\n */\n var defaultsDeep = baseRest(function(args) {\n args.push(undefined, customDefaultsMerge);\n return apply(mergeWith, undefined, args);\n });\n\n /**\n * This method is like `_.find` except that it returns the key of the first\n * element `predicate` returns truthy for instead of the element itself.\n *\n * @static\n * @memberOf _\n * @since 1.1.0\n * @category Object\n * @param {Object} object The object to inspect.\n * @param {Function} [predicate=_.identity] The function invoked per iteration.\n * @returns {string|undefined} Returns the key of the matched element,\n * else `undefined`.\n * @example\n *\n * var users = {\n * 'barney': { 'age': 36, 'active': true },\n * 'fred': { 'age': 40, 'active': false },\n * 'pebbles': { 'age': 1, 'active': true }\n * };\n *\n * _.findKey(users, function(o) { return o.age < 40; });\n * // => 'barney' (iteration order is not guaranteed)\n *\n * // The `_.matches` iteratee shorthand.\n * _.findKey(users, { 'age': 1, 'active': true });\n * // => 'pebbles'\n *\n * // The `_.matchesProperty` iteratee shorthand.\n * _.findKey(users, ['active', false]);\n * // => 'fred'\n *\n * // The `_.property` iteratee shorthand.\n * _.findKey(users, 'active');\n * // => 'barney'\n */\n function findKey(object, predicate) {\n return baseFindKey(object, getIteratee(predicate, 3), baseForOwn);\n }\n\n /**\n * This method is like `_.findKey` except that it iterates over elements of\n * a collection in the opposite order.\n *\n * @static\n * @memberOf _\n * @since 2.0.0\n * @category Object\n * @param {Object} object The object to inspect.\n * @param {Function} [predicate=_.identity] The function invoked per iteration.\n * @returns {string|undefined} Returns the key of the matched element,\n * else `undefined`.\n * @example\n *\n * var users = {\n * 'barney': { 'age': 36, 'active': true },\n * 'fred': { 'age': 40, 'active': false },\n * 'pebbles': { 'age': 1, 'active': true }\n * };\n *\n * _.findLastKey(users, function(o) { return o.age < 40; });\n * // => returns 'pebbles' assuming `_.findKey` returns 'barney'\n *\n * // The `_.matches` iteratee shorthand.\n * _.findLastKey(users, { 'age': 36, 'active': true });\n * // => 'barney'\n *\n * // The `_.matchesProperty` iteratee shorthand.\n * _.findLastKey(users, ['active', false]);\n * // => 'fred'\n *\n * // The `_.property` iteratee shorthand.\n * _.findLastKey(users, 'active');\n * // => 'pebbles'\n */\n function findLastKey(object, predicate) {\n return baseFindKey(object, getIteratee(predicate, 3), baseForOwnRight);\n }\n\n /**\n * Iterates over own and inherited enumerable string keyed properties of an\n * object and invokes `iteratee` for each property. The iteratee is invoked\n * with three arguments: (value, key, object). Iteratee functions may exit\n * iteration early by explicitly returning `false`.\n *\n * @static\n * @memberOf _\n * @since 0.3.0\n * @category Object\n * @param {Object} object The object to iterate over.\n * @param {Function} [iteratee=_.identity] The function invoked per iteration.\n * @returns {Object} Returns `object`.\n * @see _.forInRight\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.forIn(new Foo, function(value, key) {\n * console.log(key);\n * });\n * // => Logs 'a', 'b', then 'c' (iteration order is not guaranteed).\n */\n function forIn(object, iteratee) {\n return object == null\n ? object\n : baseFor(object, getIteratee(iteratee, 3), keysIn);\n }\n\n /**\n * This method is like `_.forIn` except that it iterates over properties of\n * `object` in the opposite order.\n *\n * @static\n * @memberOf _\n * @since 2.0.0\n * @category Object\n * @param {Object} object The object to iterate over.\n * @param {Function} [iteratee=_.identity] The function invoked per iteration.\n * @returns {Object} Returns `object`.\n * @see _.forIn\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.forInRight(new Foo, function(value, key) {\n * console.log(key);\n * });\n * // => Logs 'c', 'b', then 'a' assuming `_.forIn` logs 'a', 'b', then 'c'.\n */\n function forInRight(object, iteratee) {\n return object == null\n ? object\n : baseForRight(object, getIteratee(iteratee, 3), keysIn);\n }\n\n /**\n * Iterates over own enumerable string keyed properties of an object and\n * invokes `iteratee` for each property. The iteratee is invoked with three\n * arguments: (value, key, object). Iteratee functions may exit iteration\n * early by explicitly returning `false`.\n *\n * @static\n * @memberOf _\n * @since 0.3.0\n * @category Object\n * @param {Object} object The object to iterate over.\n * @param {Function} [iteratee=_.identity] The function invoked per iteration.\n * @returns {Object} Returns `object`.\n * @see _.forOwnRight\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.forOwn(new Foo, function(value, key) {\n * console.log(key);\n * });\n * // => Logs 'a' then 'b' (iteration order is not guaranteed).\n */\n function forOwn(object, iteratee) {\n return object && baseForOwn(object, getIteratee(iteratee, 3));\n }\n\n /**\n * This method is like `_.forOwn` except that it iterates over properties of\n * `object` in the opposite order.\n *\n * @static\n * @memberOf _\n * @since 2.0.0\n * @category Object\n * @param {Object} object The object to iterate over.\n * @param {Function} [iteratee=_.identity] The function invoked per iteration.\n * @returns {Object} Returns `object`.\n * @see _.forOwn\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.forOwnRight(new Foo, function(value, key) {\n * console.log(key);\n * });\n * // => Logs 'b' then 'a' assuming `_.forOwn` logs 'a' then 'b'.\n */\n function forOwnRight(object, iteratee) {\n return object && baseForOwnRight(object, getIteratee(iteratee, 3));\n }\n\n /**\n * Creates an array of function property names from own enumerable properties\n * of `object`.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to inspect.\n * @returns {Array} Returns the function names.\n * @see _.functionsIn\n * @example\n *\n * function Foo() {\n * this.a = _.constant('a');\n * this.b = _.constant('b');\n * }\n *\n * Foo.prototype.c = _.constant('c');\n *\n * _.functions(new Foo);\n * // => ['a', 'b']\n */\n function functions(object) {\n return object == null ? [] : baseFunctions(object, keys(object));\n }\n\n /**\n * Creates an array of function property names from own and inherited\n * enumerable properties of `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Object\n * @param {Object} object The object to inspect.\n * @returns {Array} Returns the function names.\n * @see _.functions\n * @example\n *\n * function Foo() {\n * this.a = _.constant('a');\n * this.b = _.constant('b');\n * }\n *\n * Foo.prototype.c = _.constant('c');\n *\n * _.functionsIn(new Foo);\n * // => ['a', 'b', 'c']\n */\n function functionsIn(object) {\n return object == null ? [] : baseFunctions(object, keysIn(object));\n }\n\n /**\n * Gets the value at `path` of `object`. If the resolved value is\n * `undefined`, the `defaultValue` is returned in its place.\n *\n * @static\n * @memberOf _\n * @since 3.7.0\n * @category Object\n * @param {Object} object The object to query.\n * @param {Array|string} path The path of the property to get.\n * @param {*} [defaultValue] The value returned for `undefined` resolved values.\n * @returns {*} Returns the resolved value.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 3 } }] };\n *\n * _.get(object, 'a[0].b.c');\n * // => 3\n *\n * _.get(object, ['a', '0', 'b', 'c']);\n * // => 3\n *\n * _.get(object, 'a.b.c', 'default');\n * // => 'default'\n */\n function get(object, path, defaultValue) {\n var result = object == null ? undefined : baseGet(object, path);\n return result === undefined ? defaultValue : result;\n }\n\n /**\n * Checks if `path` is a direct property of `object`.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @param {Array|string} path The path to check.\n * @returns {boolean} Returns `true` if `path` exists, else `false`.\n * @example\n *\n * var object = { 'a': { 'b': 2 } };\n * var other = _.create({ 'a': _.create({ 'b': 2 }) });\n *\n * _.has(object, 'a');\n * // => true\n *\n * _.has(object, 'a.b');\n * // => true\n *\n * _.has(object, ['a', 'b']);\n * // => true\n *\n * _.has(other, 'a');\n * // => false\n */\n function has(object, path) {\n return object != null && hasPath(object, path, baseHas);\n }\n\n /**\n * Checks if `path` is a direct or inherited property of `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Object\n * @param {Object} object The object to query.\n * @param {Array|string} path The path to check.\n * @returns {boolean} Returns `true` if `path` exists, else `false`.\n * @example\n *\n * var object = _.create({ 'a': _.create({ 'b': 2 }) });\n *\n * _.hasIn(object, 'a');\n * // => true\n *\n * _.hasIn(object, 'a.b');\n * // => true\n *\n * _.hasIn(object, ['a', 'b']);\n * // => true\n *\n * _.hasIn(object, 'b');\n * // => false\n */\n function hasIn(object, path) {\n return object != null && hasPath(object, path, baseHasIn);\n }\n\n /**\n * Creates an object composed of the inverted keys and values of `object`.\n * If `object` contains duplicate values, subsequent values overwrite\n * property assignments of previous values.\n *\n * @static\n * @memberOf _\n * @since 0.7.0\n * @category Object\n * @param {Object} object The object to invert.\n * @returns {Object} Returns the new inverted object.\n * @example\n *\n * var object = { 'a': 1, 'b': 2, 'c': 1 };\n *\n * _.invert(object);\n * // => { '1': 'c', '2': 'b' }\n */\n var invert = createInverter(function(result, value, key) {\n if (value != null &&\n typeof value.toString != 'function') {\n value = nativeObjectToString.call(value);\n }\n\n result[value] = key;\n }, constant(identity));\n\n /**\n * This method is like `_.invert` except that the inverted object is generated\n * from the results of running each element of `object` thru `iteratee`. The\n * corresponding inverted value of each inverted key is an array of keys\n * responsible for generating the inverted value. The iteratee is invoked\n * with one argument: (value).\n *\n * @static\n * @memberOf _\n * @since 4.1.0\n * @category Object\n * @param {Object} object The object to invert.\n * @param {Function} [iteratee=_.identity] The iteratee invoked per element.\n * @returns {Object} Returns the new inverted object.\n * @example\n *\n * var object = { 'a': 1, 'b': 2, 'c': 1 };\n *\n * _.invertBy(object);\n * // => { '1': ['a', 'c'], '2': ['b'] }\n *\n * _.invertBy(object, function(value) {\n * return 'group' + value;\n * });\n * // => { 'group1': ['a', 'c'], 'group2': ['b'] }\n */\n var invertBy = createInverter(function(result, value, key) {\n if (value != null &&\n typeof value.toString != 'function') {\n value = nativeObjectToString.call(value);\n }\n\n if (hasOwnProperty.call(result, value)) {\n result[value].push(key);\n } else {\n result[value] = [key];\n }\n }, getIteratee);\n\n /**\n * Invokes the method at `path` of `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Object\n * @param {Object} object The object to query.\n * @param {Array|string} path The path of the method to invoke.\n * @param {...*} [args] The arguments to invoke the method with.\n * @returns {*} Returns the result of the invoked method.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': [1, 2, 3, 4] } }] };\n *\n * _.invoke(object, 'a[0].b.c.slice', 1, 3);\n * // => [2, 3]\n */\n var invoke = baseRest(baseInvoke);\n\n /**\n * Creates an array of the own enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects. See the\n * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)\n * for more details.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keys(new Foo);\n * // => ['a', 'b'] (iteration order is not guaranteed)\n *\n * _.keys('hi');\n * // => ['0', '1']\n */\n function keys(object) {\n return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);\n }\n\n /**\n * Creates an array of the own and inherited enumerable property names of `object`.\n *\n * **Note:** Non-object values are coerced to objects.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property names.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.keysIn(new Foo);\n * // => ['a', 'b', 'c'] (iteration order is not guaranteed)\n */\n function keysIn(object) {\n return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object);\n }\n\n /**\n * The opposite of `_.mapValues`; this method creates an object with the\n * same values as `object` and keys generated by running each own enumerable\n * string keyed property of `object` thru `iteratee`. The iteratee is invoked\n * with three arguments: (value, key, object).\n *\n * @static\n * @memberOf _\n * @since 3.8.0\n * @category Object\n * @param {Object} object The object to iterate over.\n * @param {Function} [iteratee=_.identity] The function invoked per iteration.\n * @returns {Object} Returns the new mapped object.\n * @see _.mapValues\n * @example\n *\n * _.mapKeys({ 'a': 1, 'b': 2 }, function(value, key) {\n * return key + value;\n * });\n * // => { 'a1': 1, 'b2': 2 }\n */\n function mapKeys(object, iteratee) {\n var result = {};\n iteratee = getIteratee(iteratee, 3);\n\n baseForOwn(object, function(value, key, object) {\n baseAssignValue(result, iteratee(value, key, object), value);\n });\n return result;\n }\n\n /**\n * Creates an object with the same keys as `object` and values generated\n * by running each own enumerable string keyed property of `object` thru\n * `iteratee`. The iteratee is invoked with three arguments:\n * (value, key, object).\n *\n * @static\n * @memberOf _\n * @since 2.4.0\n * @category Object\n * @param {Object} object The object to iterate over.\n * @param {Function} [iteratee=_.identity] The function invoked per iteration.\n * @returns {Object} Returns the new mapped object.\n * @see _.mapKeys\n * @example\n *\n * var users = {\n * 'fred': { 'user': 'fred', 'age': 40 },\n * 'pebbles': { 'user': 'pebbles', 'age': 1 }\n * };\n *\n * _.mapValues(users, function(o) { return o.age; });\n * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)\n *\n * // The `_.property` iteratee shorthand.\n * _.mapValues(users, 'age');\n * // => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)\n */\n function mapValues(object, iteratee) {\n var result = {};\n iteratee = getIteratee(iteratee, 3);\n\n baseForOwn(object, function(value, key, object) {\n baseAssignValue(result, key, iteratee(value, key, object));\n });\n return result;\n }\n\n /**\n * This method is like `_.assign` except that it recursively merges own and\n * inherited enumerable string keyed properties of source objects into the\n * destination object. Source properties that resolve to `undefined` are\n * skipped if a destination value exists. Array and plain object properties\n * are merged recursively. Other objects and value types are overridden by\n * assignment. Source objects are applied from left to right. Subsequent\n * sources overwrite property assignments of previous sources.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 0.5.0\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} [sources] The source objects.\n * @returns {Object} Returns `object`.\n * @example\n *\n * var object = {\n * 'a': [{ 'b': 2 }, { 'd': 4 }]\n * };\n *\n * var other = {\n * 'a': [{ 'c': 3 }, { 'e': 5 }]\n * };\n *\n * _.merge(object, other);\n * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] }\n */\n var merge = createAssigner(function(object, source, srcIndex) {\n baseMerge(object, source, srcIndex);\n });\n\n /**\n * This method is like `_.merge` except that it accepts `customizer` which\n * is invoked to produce the merged values of the destination and source\n * properties. If `customizer` returns `undefined`, merging is handled by the\n * method instead. The `customizer` is invoked with six arguments:\n * (objValue, srcValue, key, object, source, stack).\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Object\n * @param {Object} object The destination object.\n * @param {...Object} sources The source objects.\n * @param {Function} customizer The function to customize assigned values.\n * @returns {Object} Returns `object`.\n * @example\n *\n * function customizer(objValue, srcValue) {\n * if (_.isArray(objValue)) {\n * return objValue.concat(srcValue);\n * }\n * }\n *\n * var object = { 'a': [1], 'b': [2] };\n * var other = { 'a': [3], 'b': [4] };\n *\n * _.mergeWith(object, other, customizer);\n * // => { 'a': [1, 3], 'b': [2, 4] }\n */\n var mergeWith = createAssigner(function(object, source, srcIndex, customizer) {\n baseMerge(object, source, srcIndex, customizer);\n });\n\n /**\n * The opposite of `_.pick`; this method creates an object composed of the\n * own and inherited enumerable property paths of `object` that are not omitted.\n *\n * **Note:** This method is considerably slower than `_.pick`.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The source object.\n * @param {...(string|string[])} [paths] The property paths to omit.\n * @returns {Object} Returns the new object.\n * @example\n *\n * var object = { 'a': 1, 'b': '2', 'c': 3 };\n *\n * _.omit(object, ['a', 'c']);\n * // => { 'b': '2' }\n */\n var omit = flatRest(function(object, paths) {\n var result = {};\n if (object == null) {\n return result;\n }\n var isDeep = false;\n paths = arrayMap(paths, function(path) {\n path = castPath(path, object);\n isDeep || (isDeep = path.length > 1);\n return path;\n });\n copyObject(object, getAllKeysIn(object), result);\n if (isDeep) {\n result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone);\n }\n var length = paths.length;\n while (length--) {\n baseUnset(result, paths[length]);\n }\n return result;\n });\n\n /**\n * The opposite of `_.pickBy`; this method creates an object composed of\n * the own and inherited enumerable string keyed properties of `object` that\n * `predicate` doesn't return truthy for. The predicate is invoked with two\n * arguments: (value, key).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Object\n * @param {Object} object The source object.\n * @param {Function} [predicate=_.identity] The function invoked per property.\n * @returns {Object} Returns the new object.\n * @example\n *\n * var object = { 'a': 1, 'b': '2', 'c': 3 };\n *\n * _.omitBy(object, _.isNumber);\n * // => { 'b': '2' }\n */\n function omitBy(object, predicate) {\n return pickBy(object, negate(getIteratee(predicate)));\n }\n\n /**\n * Creates an object composed of the picked `object` properties.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The source object.\n * @param {...(string|string[])} [paths] The property paths to pick.\n * @returns {Object} Returns the new object.\n * @example\n *\n * var object = { 'a': 1, 'b': '2', 'c': 3 };\n *\n * _.pick(object, ['a', 'c']);\n * // => { 'a': 1, 'c': 3 }\n */\n var pick = flatRest(function(object, paths) {\n return object == null ? {} : basePick(object, paths);\n });\n\n /**\n * Creates an object composed of the `object` properties `predicate` returns\n * truthy for. The predicate is invoked with two arguments: (value, key).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Object\n * @param {Object} object The source object.\n * @param {Function} [predicate=_.identity] The function invoked per property.\n * @returns {Object} Returns the new object.\n * @example\n *\n * var object = { 'a': 1, 'b': '2', 'c': 3 };\n *\n * _.pickBy(object, _.isNumber);\n * // => { 'a': 1, 'c': 3 }\n */\n function pickBy(object, predicate) {\n if (object == null) {\n return {};\n }\n var props = arrayMap(getAllKeysIn(object), function(prop) {\n return [prop];\n });\n predicate = getIteratee(predicate);\n return basePickBy(object, props, function(value, path) {\n return predicate(value, path[0]);\n });\n }\n\n /**\n * This method is like `_.get` except that if the resolved value is a\n * function it's invoked with the `this` binding of its parent object and\n * its result is returned.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @param {Array|string} path The path of the property to resolve.\n * @param {*} [defaultValue] The value returned for `undefined` resolved values.\n * @returns {*} Returns the resolved value.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] };\n *\n * _.result(object, 'a[0].b.c1');\n * // => 3\n *\n * _.result(object, 'a[0].b.c2');\n * // => 4\n *\n * _.result(object, 'a[0].b.c3', 'default');\n * // => 'default'\n *\n * _.result(object, 'a[0].b.c3', _.constant('default'));\n * // => 'default'\n */\n function result(object, path, defaultValue) {\n path = castPath(path, object);\n\n var index = -1,\n length = path.length;\n\n // Ensure the loop is entered when path is empty.\n if (!length) {\n length = 1;\n object = undefined;\n }\n while (++index < length) {\n var value = object == null ? undefined : object[toKey(path[index])];\n if (value === undefined) {\n index = length;\n value = defaultValue;\n }\n object = isFunction(value) ? value.call(object) : value;\n }\n return object;\n }\n\n /**\n * Sets the value at `path` of `object`. If a portion of `path` doesn't exist,\n * it's created. Arrays are created for missing index properties while objects\n * are created for all other missing properties. Use `_.setWith` to customize\n * `path` creation.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 3.7.0\n * @category Object\n * @param {Object} object The object to modify.\n * @param {Array|string} path The path of the property to set.\n * @param {*} value The value to set.\n * @returns {Object} Returns `object`.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 3 } }] };\n *\n * _.set(object, 'a[0].b.c', 4);\n * console.log(object.a[0].b.c);\n * // => 4\n *\n * _.set(object, ['x', '0', 'y', 'z'], 5);\n * console.log(object.x[0].y.z);\n * // => 5\n */\n function set(object, path, value) {\n return object == null ? object : baseSet(object, path, value);\n }\n\n /**\n * This method is like `_.set` except that it accepts `customizer` which is\n * invoked to produce the objects of `path`. If `customizer` returns `undefined`\n * path creation is handled by the method instead. The `customizer` is invoked\n * with three arguments: (nsValue, key, nsObject).\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Object\n * @param {Object} object The object to modify.\n * @param {Array|string} path The path of the property to set.\n * @param {*} value The value to set.\n * @param {Function} [customizer] The function to customize assigned values.\n * @returns {Object} Returns `object`.\n * @example\n *\n * var object = {};\n *\n * _.setWith(object, '[0][1]', 'a', Object);\n * // => { '0': { '1': 'a' } }\n */\n function setWith(object, path, value, customizer) {\n customizer = typeof customizer == 'function' ? customizer : undefined;\n return object == null ? object : baseSet(object, path, value, customizer);\n }\n\n /**\n * Creates an array of own enumerable string keyed-value pairs for `object`\n * which can be consumed by `_.fromPairs`. If `object` is a map or set, its\n * entries are returned.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @alias entries\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the key-value pairs.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.toPairs(new Foo);\n * // => [['a', 1], ['b', 2]] (iteration order is not guaranteed)\n */\n var toPairs = createToPairs(keys);\n\n /**\n * Creates an array of own and inherited enumerable string keyed-value pairs\n * for `object` which can be consumed by `_.fromPairs`. If `object` is a map\n * or set, its entries are returned.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @alias entriesIn\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the key-value pairs.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.toPairsIn(new Foo);\n * // => [['a', 1], ['b', 2], ['c', 3]] (iteration order is not guaranteed)\n */\n var toPairsIn = createToPairs(keysIn);\n\n /**\n * An alternative to `_.reduce`; this method transforms `object` to a new\n * `accumulator` object which is the result of running each of its own\n * enumerable string keyed properties thru `iteratee`, with each invocation\n * potentially mutating the `accumulator` object. If `accumulator` is not\n * provided, a new object with the same `[[Prototype]]` will be used. The\n * iteratee is invoked with four arguments: (accumulator, value, key, object).\n * Iteratee functions may exit iteration early by explicitly returning `false`.\n *\n * @static\n * @memberOf _\n * @since 1.3.0\n * @category Object\n * @param {Object} object The object to iterate over.\n * @param {Function} [iteratee=_.identity] The function invoked per iteration.\n * @param {*} [accumulator] The custom accumulator value.\n * @returns {*} Returns the accumulated value.\n * @example\n *\n * _.transform([2, 3, 4], function(result, n) {\n * result.push(n *= n);\n * return n % 2 == 0;\n * }, []);\n * // => [4, 9]\n *\n * _.transform({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) {\n * (result[value] || (result[value] = [])).push(key);\n * }, {});\n * // => { '1': ['a', 'c'], '2': ['b'] }\n */\n function transform(object, iteratee, accumulator) {\n var isArr = isArray(object),\n isArrLike = isArr || isBuffer(object) || isTypedArray(object);\n\n iteratee = getIteratee(iteratee, 4);\n if (accumulator == null) {\n var Ctor = object && object.constructor;\n if (isArrLike) {\n accumulator = isArr ? new Ctor : [];\n }\n else if (isObject(object)) {\n accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {};\n }\n else {\n accumulator = {};\n }\n }\n (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) {\n return iteratee(accumulator, value, index, object);\n });\n return accumulator;\n }\n\n /**\n * Removes the property at `path` of `object`.\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Object\n * @param {Object} object The object to modify.\n * @param {Array|string} path The path of the property to unset.\n * @returns {boolean} Returns `true` if the property is deleted, else `false`.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 7 } }] };\n * _.unset(object, 'a[0].b.c');\n * // => true\n *\n * console.log(object);\n * // => { 'a': [{ 'b': {} }] };\n *\n * _.unset(object, ['a', '0', 'b', 'c']);\n * // => true\n *\n * console.log(object);\n * // => { 'a': [{ 'b': {} }] };\n */\n function unset(object, path) {\n return object == null ? true : baseUnset(object, path);\n }\n\n /**\n * This method is like `_.set` except that accepts `updater` to produce the\n * value to set. Use `_.updateWith` to customize `path` creation. The `updater`\n * is invoked with one argument: (value).\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 4.6.0\n * @category Object\n * @param {Object} object The object to modify.\n * @param {Array|string} path The path of the property to set.\n * @param {Function} updater The function to produce the updated value.\n * @returns {Object} Returns `object`.\n * @example\n *\n * var object = { 'a': [{ 'b': { 'c': 3 } }] };\n *\n * _.update(object, 'a[0].b.c', function(n) { return n * n; });\n * console.log(object.a[0].b.c);\n * // => 9\n *\n * _.update(object, 'x[0].y.z', function(n) { return n ? n + 1 : 0; });\n * console.log(object.x[0].y.z);\n * // => 0\n */\n function update(object, path, updater) {\n return object == null ? object : baseUpdate(object, path, castFunction(updater));\n }\n\n /**\n * This method is like `_.update` except that it accepts `customizer` which is\n * invoked to produce the objects of `path`. If `customizer` returns `undefined`\n * path creation is handled by the method instead. The `customizer` is invoked\n * with three arguments: (nsValue, key, nsObject).\n *\n * **Note:** This method mutates `object`.\n *\n * @static\n * @memberOf _\n * @since 4.6.0\n * @category Object\n * @param {Object} object The object to modify.\n * @param {Array|string} path The path of the property to set.\n * @param {Function} updater The function to produce the updated value.\n * @param {Function} [customizer] The function to customize assigned values.\n * @returns {Object} Returns `object`.\n * @example\n *\n * var object = {};\n *\n * _.updateWith(object, '[0][1]', _.constant('a'), Object);\n * // => { '0': { '1': 'a' } }\n */\n function updateWith(object, path, updater, customizer) {\n customizer = typeof customizer == 'function' ? customizer : undefined;\n return object == null ? object : baseUpdate(object, path, castFunction(updater), customizer);\n }\n\n /**\n * Creates an array of the own enumerable string keyed property values of `object`.\n *\n * **Note:** Non-object values are coerced to objects.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property values.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.values(new Foo);\n * // => [1, 2] (iteration order is not guaranteed)\n *\n * _.values('hi');\n * // => ['h', 'i']\n */\n function values(object) {\n return object == null ? [] : baseValues(object, keys(object));\n }\n\n /**\n * Creates an array of the own and inherited enumerable string keyed property\n * values of `object`.\n *\n * **Note:** Non-object values are coerced to objects.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category Object\n * @param {Object} object The object to query.\n * @returns {Array} Returns the array of property values.\n * @example\n *\n * function Foo() {\n * this.a = 1;\n * this.b = 2;\n * }\n *\n * Foo.prototype.c = 3;\n *\n * _.valuesIn(new Foo);\n * // => [1, 2, 3] (iteration order is not guaranteed)\n */\n function valuesIn(object) {\n return object == null ? [] : baseValues(object, keysIn(object));\n }\n\n /*------------------------------------------------------------------------*/\n\n /**\n * Clamps `number` within the inclusive `lower` and `upper` bounds.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category Number\n * @param {number} number The number to clamp.\n * @param {number} [lower] The lower bound.\n * @param {number} upper The upper bound.\n * @returns {number} Returns the clamped number.\n * @example\n *\n * _.clamp(-10, -5, 5);\n * // => -5\n *\n * _.clamp(10, -5, 5);\n * // => 5\n */\n function clamp(number, lower, upper) {\n if (upper === undefined) {\n upper = lower;\n lower = undefined;\n }\n if (upper !== undefined) {\n upper = toNumber(upper);\n upper = upper === upper ? upper : 0;\n }\n if (lower !== undefined) {\n lower = toNumber(lower);\n lower = lower === lower ? lower : 0;\n }\n return baseClamp(toNumber(number), lower, upper);\n }\n\n /**\n * Checks if `n` is between `start` and up to, but not including, `end`. If\n * `end` is not specified, it's set to `start` with `start` then set to `0`.\n * If `start` is greater than `end` the params are swapped to support\n * negative ranges.\n *\n * @static\n * @memberOf _\n * @since 3.3.0\n * @category Number\n * @param {number} number The number to check.\n * @param {number} [start=0] The start of the range.\n * @param {number} end The end of the range.\n * @returns {boolean} Returns `true` if `number` is in the range, else `false`.\n * @see _.range, _.rangeRight\n * @example\n *\n * _.inRange(3, 2, 4);\n * // => true\n *\n * _.inRange(4, 8);\n * // => true\n *\n * _.inRange(4, 2);\n * // => false\n *\n * _.inRange(2, 2);\n * // => false\n *\n * _.inRange(1.2, 2);\n * // => true\n *\n * _.inRange(5.2, 4);\n * // => false\n *\n * _.inRange(-3, -2, -6);\n * // => true\n */\n function inRange(number, start, end) {\n start = toFinite(start);\n if (end === undefined) {\n end = start;\n start = 0;\n } else {\n end = toFinite(end);\n }\n number = toNumber(number);\n return baseInRange(number, start, end);\n }\n\n /**\n * Produces a random number between the inclusive `lower` and `upper` bounds.\n * If only one argument is provided a number between `0` and the given number\n * is returned. If `floating` is `true`, or either `lower` or `upper` are\n * floats, a floating-point number is returned instead of an integer.\n *\n * **Note:** JavaScript follows the IEEE-754 standard for resolving\n * floating-point values which can produce unexpected results.\n *\n * @static\n * @memberOf _\n * @since 0.7.0\n * @category Number\n * @param {number} [lower=0] The lower bound.\n * @param {number} [upper=1] The upper bound.\n * @param {boolean} [floating] Specify returning a floating-point number.\n * @returns {number} Returns the random number.\n * @example\n *\n * _.random(0, 5);\n * // => an integer between 0 and 5\n *\n * _.random(5);\n * // => also an integer between 0 and 5\n *\n * _.random(5, true);\n * // => a floating-point number between 0 and 5\n *\n * _.random(1.2, 5.2);\n * // => a floating-point number between 1.2 and 5.2\n */\n function random(lower, upper, floating) {\n if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) {\n upper = floating = undefined;\n }\n if (floating === undefined) {\n if (typeof upper == 'boolean') {\n floating = upper;\n upper = undefined;\n }\n else if (typeof lower == 'boolean') {\n floating = lower;\n lower = undefined;\n }\n }\n if (lower === undefined && upper === undefined) {\n lower = 0;\n upper = 1;\n }\n else {\n lower = toFinite(lower);\n if (upper === undefined) {\n upper = lower;\n lower = 0;\n } else {\n upper = toFinite(upper);\n }\n }\n if (lower > upper) {\n var temp = lower;\n lower = upper;\n upper = temp;\n }\n if (floating || lower % 1 || upper % 1) {\n var rand = nativeRandom();\n return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper);\n }\n return baseRandom(lower, upper);\n }\n\n /*------------------------------------------------------------------------*/\n\n /**\n * Converts `string` to [camel case](https://en.wikipedia.org/wiki/CamelCase).\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to convert.\n * @returns {string} Returns the camel cased string.\n * @example\n *\n * _.camelCase('Foo Bar');\n * // => 'fooBar'\n *\n * _.camelCase('--foo-bar--');\n * // => 'fooBar'\n *\n * _.camelCase('__FOO_BAR__');\n * // => 'fooBar'\n */\n var camelCase = createCompounder(function(result, word, index) {\n word = word.toLowerCase();\n return result + (index ? capitalize(word) : word);\n });\n\n /**\n * Converts the first character of `string` to upper case and the remaining\n * to lower case.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to capitalize.\n * @returns {string} Returns the capitalized string.\n * @example\n *\n * _.capitalize('FRED');\n * // => 'Fred'\n */\n function capitalize(string) {\n return upperFirst(toString(string).toLowerCase());\n }\n\n /**\n * Deburrs `string` by converting\n * [Latin-1 Supplement](https://en.wikipedia.org/wiki/Latin-1_Supplement_(Unicode_block)#Character_table)\n * and [Latin Extended-A](https://en.wikipedia.org/wiki/Latin_Extended-A)\n * letters to basic Latin letters and removing\n * [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks).\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to deburr.\n * @returns {string} Returns the deburred string.\n * @example\n *\n * _.deburr('d\u00E9j\u00E0 vu');\n * // => 'deja vu'\n */\n function deburr(string) {\n string = toString(string);\n return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');\n }\n\n /**\n * Checks if `string` ends with the given target string.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to inspect.\n * @param {string} [target] The string to search for.\n * @param {number} [position=string.length] The position to search up to.\n * @returns {boolean} Returns `true` if `string` ends with `target`,\n * else `false`.\n * @example\n *\n * _.endsWith('abc', 'c');\n * // => true\n *\n * _.endsWith('abc', 'b');\n * // => false\n *\n * _.endsWith('abc', 'b', 2);\n * // => true\n */\n function endsWith(string, target, position) {\n string = toString(string);\n target = baseToString(target);\n\n var length = string.length;\n position = position === undefined\n ? length\n : baseClamp(toInteger(position), 0, length);\n\n var end = position;\n position -= target.length;\n return position >= 0 && string.slice(position, end) == target;\n }\n\n /**\n * Converts the characters \"&\", \"<\", \">\", '\"', and \"'\" in `string` to their\n * corresponding HTML entities.\n *\n * **Note:** No other characters are escaped. To escape additional\n * characters use a third-party library like [_he_](https://mths.be/he).\n *\n * Though the \">\" character is escaped for symmetry, characters like\n * \">\" and \"/\" don't need escaping in HTML and have no special meaning\n * unless they're part of a tag or unquoted attribute value. See\n * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands)\n * (under \"semi-related fun fact\") for more details.\n *\n * When working with HTML you should always\n * [quote attribute values](http://wonko.com/post/html-escaping) to reduce\n * XSS vectors.\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category String\n * @param {string} [string=''] The string to escape.\n * @returns {string} Returns the escaped string.\n * @example\n *\n * _.escape('fred, barney, & pebbles');\n * // => 'fred, barney, & pebbles'\n */\n function escape(string) {\n string = toString(string);\n return (string && reHasUnescapedHtml.test(string))\n ? string.replace(reUnescapedHtml, escapeHtmlChar)\n : string;\n }\n\n /**\n * Escapes the `RegExp` special characters \"^\", \"$\", \"\\\", \".\", \"*\", \"+\",\n * \"?\", \"(\", \")\", \"[\", \"]\", \"{\", \"}\", and \"|\" in `string`.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to escape.\n * @returns {string} Returns the escaped string.\n * @example\n *\n * _.escapeRegExp('[lodash](https://lodash.com/)');\n * // => '\\[lodash\\]\\(https://lodash\\.com/\\)'\n */\n function escapeRegExp(string) {\n string = toString(string);\n return (string && reHasRegExpChar.test(string))\n ? string.replace(reRegExpChar, '\\\\$&')\n : string;\n }\n\n /**\n * Converts `string` to\n * [kebab case](https://en.wikipedia.org/wiki/Letter_case#Special_case_styles).\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to convert.\n * @returns {string} Returns the kebab cased string.\n * @example\n *\n * _.kebabCase('Foo Bar');\n * // => 'foo-bar'\n *\n * _.kebabCase('fooBar');\n * // => 'foo-bar'\n *\n * _.kebabCase('__FOO_BAR__');\n * // => 'foo-bar'\n */\n var kebabCase = createCompounder(function(result, word, index) {\n return result + (index ? '-' : '') + word.toLowerCase();\n });\n\n /**\n * Converts `string`, as space separated words, to lower case.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category String\n * @param {string} [string=''] The string to convert.\n * @returns {string} Returns the lower cased string.\n * @example\n *\n * _.lowerCase('--Foo-Bar--');\n * // => 'foo bar'\n *\n * _.lowerCase('fooBar');\n * // => 'foo bar'\n *\n * _.lowerCase('__FOO_BAR__');\n * // => 'foo bar'\n */\n var lowerCase = createCompounder(function(result, word, index) {\n return result + (index ? ' ' : '') + word.toLowerCase();\n });\n\n /**\n * Converts the first character of `string` to lower case.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category String\n * @param {string} [string=''] The string to convert.\n * @returns {string} Returns the converted string.\n * @example\n *\n * _.lowerFirst('Fred');\n * // => 'fred'\n *\n * _.lowerFirst('FRED');\n * // => 'fRED'\n */\n var lowerFirst = createCaseFirst('toLowerCase');\n\n /**\n * Pads `string` on the left and right sides if it's shorter than `length`.\n * Padding characters are truncated if they can't be evenly divided by `length`.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to pad.\n * @param {number} [length=0] The padding length.\n * @param {string} [chars=' '] The string used as padding.\n * @returns {string} Returns the padded string.\n * @example\n *\n * _.pad('abc', 8);\n * // => ' abc '\n *\n * _.pad('abc', 8, '_-');\n * // => '_-abc_-_'\n *\n * _.pad('abc', 3);\n * // => 'abc'\n */\n function pad(string, length, chars) {\n string = toString(string);\n length = toInteger(length);\n\n var strLength = length ? stringSize(string) : 0;\n if (!length || strLength >= length) {\n return string;\n }\n var mid = (length - strLength) / 2;\n return (\n createPadding(nativeFloor(mid), chars) +\n string +\n createPadding(nativeCeil(mid), chars)\n );\n }\n\n /**\n * Pads `string` on the right side if it's shorter than `length`. Padding\n * characters are truncated if they exceed `length`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category String\n * @param {string} [string=''] The string to pad.\n * @param {number} [length=0] The padding length.\n * @param {string} [chars=' '] The string used as padding.\n * @returns {string} Returns the padded string.\n * @example\n *\n * _.padEnd('abc', 6);\n * // => 'abc '\n *\n * _.padEnd('abc', 6, '_-');\n * // => 'abc_-_'\n *\n * _.padEnd('abc', 3);\n * // => 'abc'\n */\n function padEnd(string, length, chars) {\n string = toString(string);\n length = toInteger(length);\n\n var strLength = length ? stringSize(string) : 0;\n return (length && strLength < length)\n ? (string + createPadding(length - strLength, chars))\n : string;\n }\n\n /**\n * Pads `string` on the left side if it's shorter than `length`. Padding\n * characters are truncated if they exceed `length`.\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category String\n * @param {string} [string=''] The string to pad.\n * @param {number} [length=0] The padding length.\n * @param {string} [chars=' '] The string used as padding.\n * @returns {string} Returns the padded string.\n * @example\n *\n * _.padStart('abc', 6);\n * // => ' abc'\n *\n * _.padStart('abc', 6, '_-');\n * // => '_-_abc'\n *\n * _.padStart('abc', 3);\n * // => 'abc'\n */\n function padStart(string, length, chars) {\n string = toString(string);\n length = toInteger(length);\n\n var strLength = length ? stringSize(string) : 0;\n return (length && strLength < length)\n ? (createPadding(length - strLength, chars) + string)\n : string;\n }\n\n /**\n * Converts `string` to an integer of the specified radix. If `radix` is\n * `undefined` or `0`, a `radix` of `10` is used unless `value` is a\n * hexadecimal, in which case a `radix` of `16` is used.\n *\n * **Note:** This method aligns with the\n * [ES5 implementation](https://es5.github.io/#x15.1.2.2) of `parseInt`.\n *\n * @static\n * @memberOf _\n * @since 1.1.0\n * @category String\n * @param {string} string The string to convert.\n * @param {number} [radix=10] The radix to interpret `value` by.\n * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.\n * @returns {number} Returns the converted integer.\n * @example\n *\n * _.parseInt('08');\n * // => 8\n *\n * _.map(['6', '08', '10'], _.parseInt);\n * // => [6, 8, 10]\n */\n function parseInt(string, radix, guard) {\n if (guard || radix == null) {\n radix = 0;\n } else if (radix) {\n radix = +radix;\n }\n return nativeParseInt(toString(string).replace(reTrimStart, ''), radix || 0);\n }\n\n /**\n * Repeats the given string `n` times.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to repeat.\n * @param {number} [n=1] The number of times to repeat the string.\n * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.\n * @returns {string} Returns the repeated string.\n * @example\n *\n * _.repeat('*', 3);\n * // => '***'\n *\n * _.repeat('abc', 2);\n * // => 'abcabc'\n *\n * _.repeat('abc', 0);\n * // => ''\n */\n function repeat(string, n, guard) {\n if ((guard ? isIterateeCall(string, n, guard) : n === undefined)) {\n n = 1;\n } else {\n n = toInteger(n);\n }\n return baseRepeat(toString(string), n);\n }\n\n /**\n * Replaces matches for `pattern` in `string` with `replacement`.\n *\n * **Note:** This method is based on\n * [`String#replace`](https://mdn.io/String/replace).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category String\n * @param {string} [string=''] The string to modify.\n * @param {RegExp|string} pattern The pattern to replace.\n * @param {Function|string} replacement The match replacement.\n * @returns {string} Returns the modified string.\n * @example\n *\n * _.replace('Hi Fred', 'Fred', 'Barney');\n * // => 'Hi Barney'\n */\n function replace() {\n var args = arguments,\n string = toString(args[0]);\n\n return args.length < 3 ? string : string.replace(args[1], args[2]);\n }\n\n /**\n * Converts `string` to\n * [snake case](https://en.wikipedia.org/wiki/Snake_case).\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to convert.\n * @returns {string} Returns the snake cased string.\n * @example\n *\n * _.snakeCase('Foo Bar');\n * // => 'foo_bar'\n *\n * _.snakeCase('fooBar');\n * // => 'foo_bar'\n *\n * _.snakeCase('--FOO-BAR--');\n * // => 'foo_bar'\n */\n var snakeCase = createCompounder(function(result, word, index) {\n return result + (index ? '_' : '') + word.toLowerCase();\n });\n\n /**\n * Splits `string` by `separator`.\n *\n * **Note:** This method is based on\n * [`String#split`](https://mdn.io/String/split).\n *\n * @static\n * @memberOf _\n * @since 4.0.0\n * @category String\n * @param {string} [string=''] The string to split.\n * @param {RegExp|string} separator The separator pattern to split by.\n * @param {number} [limit] The length to truncate results to.\n * @returns {Array} Returns the string segments.\n * @example\n *\n * _.split('a-b-c', '-', 2);\n * // => ['a', 'b']\n */\n function split(string, separator, limit) {\n if (limit && typeof limit != 'number' && isIterateeCall(string, separator, limit)) {\n separator = limit = undefined;\n }\n limit = limit === undefined ? MAX_ARRAY_LENGTH : limit >>> 0;\n if (!limit) {\n return [];\n }\n string = toString(string);\n if (string && (\n typeof separator == 'string' ||\n (separator != null && !isRegExp(separator))\n )) {\n separator = baseToString(separator);\n if (!separator && hasUnicode(string)) {\n return castSlice(stringToArray(string), 0, limit);\n }\n }\n return string.split(separator, limit);\n }\n\n /**\n * Converts `string` to\n * [start case](https://en.wikipedia.org/wiki/Letter_case#Stylistic_or_specialised_usage).\n *\n * @static\n * @memberOf _\n * @since 3.1.0\n * @category String\n * @param {string} [string=''] The string to convert.\n * @returns {string} Returns the start cased string.\n * @example\n *\n * _.startCase('--foo-bar--');\n * // => 'Foo Bar'\n *\n * _.startCase('fooBar');\n * // => 'Foo Bar'\n *\n * _.startCase('__FOO_BAR__');\n * // => 'FOO BAR'\n */\n var startCase = createCompounder(function(result, word, index) {\n return result + (index ? ' ' : '') + upperFirst(word);\n });\n\n /**\n * Checks if `string` starts with the given target string.\n *\n * @static\n * @memberOf _\n * @since 3.0.0\n * @category String\n * @param {string} [string=''] The string to inspect.\n * @param {string} [target] The string to search for.\n * @param {number} [position=0] The position to search from.\n * @returns {boolean} Returns `true` if `string` starts with `target`,\n * else `false`.\n * @example\n *\n * _.startsWith('abc', 'a');\n * // => true\n *\n * _.startsWith('abc', 'b');\n * // => false\n *\n * _.startsWith('abc', 'b', 1);\n * // => true\n */\n function startsWith(string, target, position) {\n string = toString(string);\n position = position == null\n ? 0\n : baseClamp(toInteger(position), 0, string.length);\n\n target = baseToString(target);\n return string.slice(position, position + target.length) == target;\n }\n\n /**\n * Creates a compiled template function that can interpolate data properties\n * in \"interpolate\" delimiters, HTML-escape interpolated data properties in\n * \"escape\" delimiters, and execute JavaScript in \"evaluate\" delimiters. Data\n * properties may be accessed as free variables in the template. If a setting\n * object is given, it takes precedence over `_.templateSettings` values.\n *\n * **Note:** In the development build `_.template` utilizes\n * [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl)\n * for easier debugging.\n *\n * For more information on precompiling templates see\n * [lodash's custom builds documentation](https://lodash.com/custom-builds).\n *\n * For more information on Chrome extension sandboxes see\n * [Chrome's extensions documentation](https://developer.chrome.com/extensions/sandboxingEval).\n *\n * @static\n * @since 0.1.0\n * @memberOf _\n * @category String\n * @param {string} [string=''] The template string.\n * @param {Object} [options={}] The options object.\n * @param {RegExp} [options.escape=_.templateSettings.escape]\n * The HTML \"escape\" delimiter.\n * @param {RegExp} [options.evaluate=_.templateSettings.evaluate]\n * The \"evaluate\" delimiter.\n * @param {Object} [options.imports=_.templateSettings.imports]\n * An object to import into the template as free variables.\n * @param {RegExp} [options.interpolate=_.templateSettings.interpolate]\n * The \"interpolate\" delimiter.\n * @param {string} [options.sourceURL='lodash.templateSources[n]']\n * The sourceURL of the compiled template.\n * @param {string} [options.variable='obj']\n * The data object variable name.\n * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`.\n * @returns {Function} Returns the compiled template function.\n * @example\n *\n * // Use the \"interpolate\" delimiter to create a compiled template.\n * var compiled = _.template('hello <%= user %>!');\n * compiled({ 'user': 'fred' });\n * // => 'hello fred!'\n *\n * // Use the HTML \"escape\" delimiter to escape data property values.\n * var compiled = _.template('<%- value %>');\n * compiled({ 'value': ' ';\n const directionality = editor.getBody().dir;\n const dirAttr = directionality ? ' dir=\"' + encode(directionality) + '\"' : '';\n const previewHtml = '' + '' + '' + headHtml + '' + '' + editor.getContent() + preventClicksOnLinksScript + '' + '';\n return previewHtml;\n };\n\n const open = editor => {\n const content = getPreviewHtml(editor);\n const dataApi = editor.windowManager.open({\n title: 'Preview',\n size: 'large',\n body: {\n type: 'panel',\n items: [{\n name: 'preview',\n type: 'iframe',\n sandboxed: true,\n transparent: false\n }]\n },\n buttons: [{\n type: 'cancel',\n name: 'close',\n text: 'Close',\n primary: true\n }],\n initialData: { preview: content }\n });\n dataApi.focus('close');\n };\n\n const register$1 = editor => {\n editor.addCommand('mcePreview', () => {\n open(editor);\n });\n };\n\n const register = editor => {\n const onAction = () => editor.execCommand('mcePreview');\n editor.ui.registry.addButton('preview', {\n icon: 'preview',\n tooltip: 'Preview',\n onAction,\n context: 'any'\n });\n editor.ui.registry.addMenuItem('preview', {\n icon: 'preview',\n text: 'Preview',\n onAction,\n context: 'any'\n });\n };\n\n var Plugin = () => {\n global$2.add('preview', editor => {\n register$1(editor);\n register(editor);\n });\n };\n\n Plugin();\n\n})();\n", "/**\n * TinyMCE version 7.5.0 (2024-11-06)\n */\n\n(function () {\n 'use strict';\n\n var global$3 = tinymce.util.Tools.resolve('tinymce.PluginManager');\n\n const hasProto = (v, constructor, predicate) => {\n var _a;\n if (predicate(v, constructor.prototype)) {\n return true;\n } else {\n return ((_a = v.constructor) === null || _a === void 0 ? void 0 : _a.name) === constructor.name;\n }\n };\n const typeOf = x => {\n const t = typeof x;\n if (x === null) {\n return 'null';\n } else if (t === 'object' && Array.isArray(x)) {\n return 'array';\n } else if (t === 'object' && hasProto(x, String, (o, proto) => proto.isPrototypeOf(o))) {\n return 'string';\n } else {\n return t;\n }\n };\n const isType$1 = type => value => typeOf(value) === type;\n const isSimpleType = type => value => typeof value === type;\n const eq$1 = t => a => t === a;\n const isString = isType$1('string');\n const isArray = isType$1('array');\n const isBoolean = isSimpleType('boolean');\n const isUndefined = eq$1(undefined);\n const isNullable = a => a === null || a === undefined;\n const isNonNullable = a => !isNullable(a);\n const isFunction = isSimpleType('function');\n const isNumber = isSimpleType('number');\n\n const noop = () => {\n };\n const compose1 = (fbc, fab) => a => fbc(fab(a));\n const constant = value => {\n return () => {\n return value;\n };\n };\n const identity = x => {\n return x;\n };\n const tripleEquals = (a, b) => {\n return a === b;\n };\n function curry(fn, ...initialArgs) {\n return (...restArgs) => {\n const all = initialArgs.concat(restArgs);\n return fn.apply(null, all);\n };\n }\n const call = f => {\n f();\n };\n const never = constant(false);\n const always = constant(true);\n\n class Optional {\n constructor(tag, value) {\n this.tag = tag;\n this.value = value;\n }\n static some(value) {\n return new Optional(true, value);\n }\n static none() {\n return Optional.singletonNone;\n }\n fold(onNone, onSome) {\n if (this.tag) {\n return onSome(this.value);\n } else {\n return onNone();\n }\n }\n isSome() {\n return this.tag;\n }\n isNone() {\n return !this.tag;\n }\n map(mapper) {\n if (this.tag) {\n return Optional.some(mapper(this.value));\n } else {\n return Optional.none();\n }\n }\n bind(binder) {\n if (this.tag) {\n return binder(this.value);\n } else {\n return Optional.none();\n }\n }\n exists(predicate) {\n return this.tag && predicate(this.value);\n }\n forall(predicate) {\n return !this.tag || predicate(this.value);\n }\n filter(predicate) {\n if (!this.tag || predicate(this.value)) {\n return this;\n } else {\n return Optional.none();\n }\n }\n getOr(replacement) {\n return this.tag ? this.value : replacement;\n }\n or(replacement) {\n return this.tag ? this : replacement;\n }\n getOrThunk(thunk) {\n return this.tag ? this.value : thunk();\n }\n orThunk(thunk) {\n return this.tag ? this : thunk();\n }\n getOrDie(message) {\n if (!this.tag) {\n throw new Error(message !== null && message !== void 0 ? message : 'Called getOrDie on None');\n } else {\n return this.value;\n }\n }\n static from(value) {\n return isNonNullable(value) ? Optional.some(value) : Optional.none();\n }\n getOrNull() {\n return this.tag ? this.value : null;\n }\n getOrUndefined() {\n return this.value;\n }\n each(worker) {\n if (this.tag) {\n worker(this.value);\n }\n }\n toArray() {\n return this.tag ? [this.value] : [];\n }\n toString() {\n return this.tag ? `some(${ this.value })` : 'none()';\n }\n }\n Optional.singletonNone = new Optional(false);\n\n const keys = Object.keys;\n const hasOwnProperty = Object.hasOwnProperty;\n const each$1 = (obj, f) => {\n const props = keys(obj);\n for (let k = 0, len = props.length; k < len; k++) {\n const i = props[k];\n const x = obj[i];\n f(x, i);\n }\n };\n const objAcc = r => (x, i) => {\n r[i] = x;\n };\n const internalFilter = (obj, pred, onTrue, onFalse) => {\n each$1(obj, (x, i) => {\n (pred(x, i) ? onTrue : onFalse)(x, i);\n });\n };\n const filter$1 = (obj, pred) => {\n const t = {};\n internalFilter(obj, pred, objAcc(t), noop);\n return t;\n };\n const mapToArray = (obj, f) => {\n const r = [];\n each$1(obj, (value, name) => {\n r.push(f(value, name));\n });\n return r;\n };\n const values = obj => {\n return mapToArray(obj, identity);\n };\n const size = obj => {\n return keys(obj).length;\n };\n const get$4 = (obj, key) => {\n return has(obj, key) ? Optional.from(obj[key]) : Optional.none();\n };\n const has = (obj, key) => hasOwnProperty.call(obj, key);\n const hasNonNullableKey = (obj, key) => has(obj, key) && obj[key] !== undefined && obj[key] !== null;\n const isEmpty$1 = r => {\n for (const x in r) {\n if (hasOwnProperty.call(r, x)) {\n return false;\n }\n }\n return true;\n };\n\n const nativeIndexOf = Array.prototype.indexOf;\n const nativePush = Array.prototype.push;\n const rawIndexOf = (ts, t) => nativeIndexOf.call(ts, t);\n const contains = (xs, x) => rawIndexOf(xs, x) > -1;\n const exists = (xs, pred) => {\n for (let i = 0, len = xs.length; i < len; i++) {\n const x = xs[i];\n if (pred(x, i)) {\n return true;\n }\n }\n return false;\n };\n const range = (num, f) => {\n const r = [];\n for (let i = 0; i < num; i++) {\n r.push(f(i));\n }\n return r;\n };\n const map = (xs, f) => {\n const len = xs.length;\n const r = new Array(len);\n for (let i = 0; i < len; i++) {\n const x = xs[i];\n r[i] = f(x, i);\n }\n return r;\n };\n const each = (xs, f) => {\n for (let i = 0, len = xs.length; i < len; i++) {\n const x = xs[i];\n f(x, i);\n }\n };\n const eachr = (xs, f) => {\n for (let i = xs.length - 1; i >= 0; i--) {\n const x = xs[i];\n f(x, i);\n }\n };\n const partition = (xs, pred) => {\n const pass = [];\n const fail = [];\n for (let i = 0, len = xs.length; i < len; i++) {\n const x = xs[i];\n const arr = pred(x, i) ? pass : fail;\n arr.push(x);\n }\n return {\n pass,\n fail\n };\n };\n const filter = (xs, pred) => {\n const r = [];\n for (let i = 0, len = xs.length; i < len; i++) {\n const x = xs[i];\n if (pred(x, i)) {\n r.push(x);\n }\n }\n return r;\n };\n const foldr = (xs, f, acc) => {\n eachr(xs, (x, i) => {\n acc = f(acc, x, i);\n });\n return acc;\n };\n const foldl = (xs, f, acc) => {\n each(xs, (x, i) => {\n acc = f(acc, x, i);\n });\n return acc;\n };\n const findUntil = (xs, pred, until) => {\n for (let i = 0, len = xs.length; i < len; i++) {\n const x = xs[i];\n if (pred(x, i)) {\n return Optional.some(x);\n } else if (until(x, i)) {\n break;\n }\n }\n return Optional.none();\n };\n const find = (xs, pred) => {\n return findUntil(xs, pred, never);\n };\n const flatten$1 = xs => {\n const r = [];\n for (let i = 0, len = xs.length; i < len; ++i) {\n if (!isArray(xs[i])) {\n throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);\n }\n nativePush.apply(r, xs[i]);\n }\n return r;\n };\n const bind = (xs, f) => flatten$1(map(xs, f));\n const forall = (xs, pred) => {\n for (let i = 0, len = xs.length; i < len; ++i) {\n const x = xs[i];\n if (pred(x, i) !== true) {\n return false;\n }\n }\n return true;\n };\n const mapToObject = (xs, f) => {\n const r = {};\n for (let i = 0, len = xs.length; i < len; i++) {\n const x = xs[i];\n r[String(x)] = f(x, i);\n }\n return r;\n };\n const get$3 = (xs, i) => i >= 0 && i < xs.length ? Optional.some(xs[i]) : Optional.none();\n const head = xs => get$3(xs, 0);\n const last = xs => get$3(xs, xs.length - 1);\n const findMap = (arr, f) => {\n for (let i = 0; i < arr.length; i++) {\n const r = f(arr[i], i);\n if (r.isSome()) {\n return r;\n }\n }\n return Optional.none();\n };\n\n const COMMENT = 8;\n const DOCUMENT = 9;\n const DOCUMENT_FRAGMENT = 11;\n const ELEMENT = 1;\n const TEXT = 3;\n\n const fromHtml = (html, scope) => {\n const doc = scope || document;\n const div = doc.createElement('div');\n div.innerHTML = html;\n if (!div.hasChildNodes() || div.childNodes.length > 1) {\n const message = 'HTML does not have a single root node';\n console.error(message, html);\n throw new Error(message);\n }\n return fromDom$1(div.childNodes[0]);\n };\n const fromTag = (tag, scope) => {\n const doc = scope || document;\n const node = doc.createElement(tag);\n return fromDom$1(node);\n };\n const fromText = (text, scope) => {\n const doc = scope || document;\n const node = doc.createTextNode(text);\n return fromDom$1(node);\n };\n const fromDom$1 = node => {\n if (node === null || node === undefined) {\n throw new Error('Node cannot be null or undefined');\n }\n return { dom: node };\n };\n const fromPoint = (docElm, x, y) => Optional.from(docElm.dom.elementFromPoint(x, y)).map(fromDom$1);\n const SugarElement = {\n fromHtml,\n fromTag,\n fromText,\n fromDom: fromDom$1,\n fromPoint\n };\n\n const is$2 = (element, selector) => {\n const dom = element.dom;\n if (dom.nodeType !== ELEMENT) {\n return false;\n } else {\n const elem = dom;\n if (elem.matches !== undefined) {\n return elem.matches(selector);\n } else if (elem.msMatchesSelector !== undefined) {\n return elem.msMatchesSelector(selector);\n } else if (elem.webkitMatchesSelector !== undefined) {\n return elem.webkitMatchesSelector(selector);\n } else if (elem.mozMatchesSelector !== undefined) {\n return elem.mozMatchesSelector(selector);\n } else {\n throw new Error('Browser lacks native selectors');\n }\n }\n };\n const bypassSelector = dom => dom.nodeType !== ELEMENT && dom.nodeType !== DOCUMENT && dom.nodeType !== DOCUMENT_FRAGMENT || dom.childElementCount === 0;\n const all$1 = (selector, scope) => {\n const base = scope === undefined ? document : scope.dom;\n return bypassSelector(base) ? [] : map(base.querySelectorAll(selector), SugarElement.fromDom);\n };\n const one = (selector, scope) => {\n const base = scope === undefined ? document : scope.dom;\n return bypassSelector(base) ? Optional.none() : Optional.from(base.querySelector(selector)).map(SugarElement.fromDom);\n };\n\n const eq = (e1, e2) => e1.dom === e2.dom;\n const is$1 = is$2;\n\n typeof window !== 'undefined' ? window : Function('return this;')();\n\n const name = element => {\n const r = element.dom.nodeName;\n return r.toLowerCase();\n };\n const type = element => element.dom.nodeType;\n const isType = t => element => type(element) === t;\n const isComment = element => type(element) === COMMENT || name(element) === '#comment';\n const isElement = isType(ELEMENT);\n const isText = isType(TEXT);\n const isDocument = isType(DOCUMENT);\n const isDocumentFragment = isType(DOCUMENT_FRAGMENT);\n const isTag = tag => e => isElement(e) && name(e) === tag;\n\n const owner = element => SugarElement.fromDom(element.dom.ownerDocument);\n const documentOrOwner = dos => isDocument(dos) ? dos : owner(dos);\n const parent = element => Optional.from(element.dom.parentNode).map(SugarElement.fromDom);\n const parents = (element, isRoot) => {\n const stop = isFunction(isRoot) ? isRoot : never;\n let dom = element.dom;\n const ret = [];\n while (dom.parentNode !== null && dom.parentNode !== undefined) {\n const rawParent = dom.parentNode;\n const p = SugarElement.fromDom(rawParent);\n ret.push(p);\n if (stop(p) === true) {\n break;\n } else {\n dom = rawParent;\n }\n }\n return ret;\n };\n const prevSibling = element => Optional.from(element.dom.previousSibling).map(SugarElement.fromDom);\n const nextSibling = element => Optional.from(element.dom.nextSibling).map(SugarElement.fromDom);\n const children$3 = element => map(element.dom.childNodes, SugarElement.fromDom);\n const child$3 = (element, index) => {\n const cs = element.dom.childNodes;\n return Optional.from(cs[index]).map(SugarElement.fromDom);\n };\n const firstChild = element => child$3(element, 0);\n\n const isShadowRoot = dos => isDocumentFragment(dos) && isNonNullable(dos.dom.host);\n const getRootNode = e => SugarElement.fromDom(e.dom.getRootNode());\n const getShadowRoot = e => {\n const r = getRootNode(e);\n return isShadowRoot(r) ? Optional.some(r) : Optional.none();\n };\n const getShadowHost = e => SugarElement.fromDom(e.dom.host);\n\n const inBody = element => {\n const dom = isText(element) ? element.dom.parentNode : element.dom;\n if (dom === undefined || dom === null || dom.ownerDocument === null) {\n return false;\n }\n const doc = dom.ownerDocument;\n return getShadowRoot(SugarElement.fromDom(dom)).fold(() => doc.body.contains(dom), compose1(inBody, getShadowHost));\n };\n\n var ClosestOrAncestor = (is, ancestor, scope, a, isRoot) => {\n if (is(scope, a)) {\n return Optional.some(scope);\n } else if (isFunction(isRoot) && isRoot(scope)) {\n return Optional.none();\n } else {\n return ancestor(scope, a, isRoot);\n }\n };\n\n const ancestor$1 = (scope, predicate, isRoot) => {\n let element = scope.dom;\n const stop = isFunction(isRoot) ? isRoot : never;\n while (element.parentNode) {\n element = element.parentNode;\n const el = SugarElement.fromDom(element);\n if (predicate(el)) {\n return Optional.some(el);\n } else if (stop(el)) {\n break;\n }\n }\n return Optional.none();\n };\n const closest$2 = (scope, predicate, isRoot) => {\n const is = (s, test) => test(s);\n return ClosestOrAncestor(is, ancestor$1, scope, predicate, isRoot);\n };\n const child$2 = (scope, predicate) => {\n const pred = node => predicate(SugarElement.fromDom(node));\n const result = find(scope.dom.childNodes, pred);\n return result.map(SugarElement.fromDom);\n };\n\n const ancestor = (scope, selector, isRoot) => ancestor$1(scope, e => is$2(e, selector), isRoot);\n const child$1 = (scope, selector) => child$2(scope, e => is$2(e, selector));\n const descendant = (scope, selector) => one(selector, scope);\n const closest$1 = (scope, selector, isRoot) => {\n const is = (element, selector) => is$2(element, selector);\n return ClosestOrAncestor(is, ancestor, scope, selector, isRoot);\n };\n\n const closest = target => closest$1(target, '[contenteditable]');\n const isEditable = (element, assumeEditable = false) => {\n if (inBody(element)) {\n return element.dom.isContentEditable;\n } else {\n return closest(element).fold(constant(assumeEditable), editable => getRaw$1(editable) === 'true');\n }\n };\n const getRaw$1 = element => element.dom.contentEditable;\n\n const getNodeName = elm => elm.nodeName.toLowerCase();\n const getBody = editor => SugarElement.fromDom(editor.getBody());\n const getIsRoot = editor => element => eq(element, getBody(editor));\n const removePxSuffix = size => size ? size.replace(/px$/, '') : '';\n const addPxSuffix = size => /^\\d+(\\.\\d+)?$/.test(size) ? size + 'px' : size;\n const getSelectionStart = editor => SugarElement.fromDom(editor.selection.getStart());\n const getSelectionEnd = editor => SugarElement.fromDom(editor.selection.getEnd());\n const isInEditableContext = cell => closest$2(cell, isTag('table')).forall(isEditable);\n\n const children$2 = (scope, predicate) => filter(children$3(scope), predicate);\n const descendants$1 = (scope, predicate) => {\n let result = [];\n each(children$3(scope), x => {\n if (predicate(x)) {\n result = result.concat([x]);\n }\n result = result.concat(descendants$1(x, predicate));\n });\n return result;\n };\n\n const children$1 = (scope, selector) => children$2(scope, e => is$2(e, selector));\n const descendants = (scope, selector) => all$1(selector, scope);\n\n const rawSet = (dom, key, value) => {\n if (isString(value) || isBoolean(value) || isNumber(value)) {\n dom.setAttribute(key, value + '');\n } else {\n console.error('Invalid call to Attribute.set. Key ', key, ':: Value ', value, ':: Element ', dom);\n throw new Error('Attribute value was not simple');\n }\n };\n const set$2 = (element, key, value) => {\n rawSet(element.dom, key, value);\n };\n const setAll = (element, attrs) => {\n const dom = element.dom;\n each$1(attrs, (v, k) => {\n rawSet(dom, k, v);\n });\n };\n const get$2 = (element, key) => {\n const v = element.dom.getAttribute(key);\n return v === null ? undefined : v;\n };\n const getOpt = (element, key) => Optional.from(get$2(element, key));\n const remove$2 = (element, key) => {\n element.dom.removeAttribute(key);\n };\n const clone = element => foldl(element.dom.attributes, (acc, attr) => {\n acc[attr.name] = attr.value;\n return acc;\n }, {});\n\n const is = (lhs, rhs, comparator = tripleEquals) => lhs.exists(left => comparator(left, rhs));\n const cat = arr => {\n const r = [];\n const push = x => {\n r.push(x);\n };\n for (let i = 0; i < arr.length; i++) {\n arr[i].each(push);\n }\n return r;\n };\n const lift2 = (oa, ob, f) => oa.isSome() && ob.isSome() ? Optional.some(f(oa.getOrDie(), ob.getOrDie())) : Optional.none();\n const flatten = oot => oot.bind(identity);\n const someIf = (b, a) => b ? Optional.some(a) : Optional.none();\n\n const removeFromStart = (str, numChars) => {\n return str.substring(numChars);\n };\n\n const checkRange = (str, substr, start) => substr === '' || str.length >= substr.length && str.substr(start, start + substr.length) === substr;\n const removeLeading = (str, prefix) => {\n return startsWith(str, prefix) ? removeFromStart(str, prefix.length) : str;\n };\n const startsWith = (str, prefix) => {\n return checkRange(str, prefix, 0);\n };\n const blank = r => s => s.replace(r, '');\n const trim = blank(/^\\s+|\\s+$/g);\n const isNotEmpty = s => s.length > 0;\n const isEmpty = s => !isNotEmpty(s);\n const toInt = (value, radix = 10) => {\n const num = parseInt(value, radix);\n return isNaN(num) ? Optional.none() : Optional.some(num);\n };\n const toFloat = value => {\n const num = parseFloat(value);\n return isNaN(num) ? Optional.none() : Optional.some(num);\n };\n\n const isSupported = dom => dom.style !== undefined && isFunction(dom.style.getPropertyValue);\n\n const internalSet = (dom, property, value) => {\n if (!isString(value)) {\n console.error('Invalid call to CSS.set. Property ', property, ':: Value ', value, ':: Element ', dom);\n throw new Error('CSS value must be a string: ' + value);\n }\n if (isSupported(dom)) {\n dom.style.setProperty(property, value);\n }\n };\n const internalRemove = (dom, property) => {\n if (isSupported(dom)) {\n dom.style.removeProperty(property);\n }\n };\n const set$1 = (element, property, value) => {\n const dom = element.dom;\n internalSet(dom, property, value);\n };\n const get$1 = (element, property) => {\n const dom = element.dom;\n const styles = window.getComputedStyle(dom);\n const r = styles.getPropertyValue(property);\n return r === '' && !inBody(element) ? getUnsafeProperty(dom, property) : r;\n };\n const getUnsafeProperty = (dom, property) => isSupported(dom) ? dom.style.getPropertyValue(property) : '';\n const getRaw = (element, property) => {\n const dom = element.dom;\n const raw = getUnsafeProperty(dom, property);\n return Optional.from(raw).filter(r => r.length > 0);\n };\n const remove$1 = (element, property) => {\n const dom = element.dom;\n internalRemove(dom, property);\n if (is(getOpt(element, 'style').map(trim), '')) {\n remove$2(element, 'style');\n }\n };\n\n const getAttrValue = (cell, name, fallback = 0) => getOpt(cell, name).map(value => parseInt(value, 10)).getOr(fallback);\n\n const firstLayer = (scope, selector) => {\n return filterFirstLayer(scope, selector, always);\n };\n const filterFirstLayer = (scope, selector, predicate) => {\n return bind(children$3(scope), x => {\n if (is$2(x, selector)) {\n return predicate(x) ? [x] : [];\n } else {\n return filterFirstLayer(x, selector, predicate);\n }\n });\n };\n\n const validSectionList = [\n 'tfoot',\n 'thead',\n 'tbody',\n 'colgroup'\n ];\n const isValidSection = parentName => contains(validSectionList, parentName);\n const grid = (rows, columns) => ({\n rows,\n columns\n });\n const detail = (element, rowspan, colspan) => ({\n element,\n rowspan,\n colspan\n });\n const extended = (element, rowspan, colspan, row, column, isLocked) => ({\n element,\n rowspan,\n colspan,\n row,\n column,\n isLocked\n });\n const rowdetail = (element, cells, section) => ({\n element,\n cells,\n section\n });\n const bounds = (startRow, startCol, finishRow, finishCol) => ({\n startRow,\n startCol,\n finishRow,\n finishCol\n });\n const columnext = (element, colspan, column) => ({\n element,\n colspan,\n column\n });\n const colgroup = (element, columns) => ({\n element,\n columns\n });\n\n const lookup = (tags, element, isRoot = never) => {\n if (isRoot(element)) {\n return Optional.none();\n }\n if (contains(tags, name(element))) {\n return Optional.some(element);\n }\n const isRootOrUpperTable = elm => is$2(elm, 'table') || isRoot(elm);\n return ancestor(element, tags.join(','), isRootOrUpperTable);\n };\n const cell = (element, isRoot) => lookup([\n 'td',\n 'th'\n ], element, isRoot);\n const cells = ancestor => firstLayer(ancestor, 'th,td');\n const columns = ancestor => {\n if (is$2(ancestor, 'colgroup')) {\n return children$1(ancestor, 'col');\n } else {\n return bind(columnGroups(ancestor), columnGroup => children$1(columnGroup, 'col'));\n }\n };\n const table = (element, isRoot) => closest$1(element, 'table', isRoot);\n const rows = ancestor => firstLayer(ancestor, 'tr');\n const columnGroups = ancestor => table(ancestor).fold(constant([]), table => children$1(table, 'colgroup'));\n\n const fromRowsOrColGroups = (elems, getSection) => map(elems, row => {\n if (name(row) === 'colgroup') {\n const cells = map(columns(row), column => {\n const colspan = getAttrValue(column, 'span', 1);\n return detail(column, 1, colspan);\n });\n return rowdetail(row, cells, 'colgroup');\n } else {\n const cells$1 = map(cells(row), cell => {\n const rowspan = getAttrValue(cell, 'rowspan', 1);\n const colspan = getAttrValue(cell, 'colspan', 1);\n return detail(cell, rowspan, colspan);\n });\n return rowdetail(row, cells$1, getSection(row));\n }\n });\n const getParentSection = group => parent(group).map(parent => {\n const parentName = name(parent);\n return isValidSection(parentName) ? parentName : 'tbody';\n }).getOr('tbody');\n const fromTable$1 = table => {\n const rows$1 = rows(table);\n const columnGroups$1 = columnGroups(table);\n const elems = [\n ...columnGroups$1,\n ...rows$1\n ];\n return fromRowsOrColGroups(elems, getParentSection);\n };\n\n const LOCKED_COL_ATTR = 'data-snooker-locked-cols';\n const getLockedColumnsFromTable = table => getOpt(table, LOCKED_COL_ATTR).bind(lockedColStr => Optional.from(lockedColStr.match(/\\d+/g))).map(lockedCols => mapToObject(lockedCols, always));\n\n const key = (row, column) => {\n return row + ',' + column;\n };\n const getAt = (warehouse, row, column) => Optional.from(warehouse.access[key(row, column)]);\n const findItem = (warehouse, item, comparator) => {\n const filtered = filterItems(warehouse, detail => {\n return comparator(item, detail.element);\n });\n return filtered.length > 0 ? Optional.some(filtered[0]) : Optional.none();\n };\n const filterItems = (warehouse, predicate) => {\n const all = bind(warehouse.all, r => {\n return r.cells;\n });\n return filter(all, predicate);\n };\n const generateColumns = rowData => {\n const columnsGroup = {};\n let index = 0;\n each(rowData.cells, column => {\n const colspan = column.colspan;\n range(colspan, columnIndex => {\n const colIndex = index + columnIndex;\n columnsGroup[colIndex] = columnext(column.element, colspan, colIndex);\n });\n index += colspan;\n });\n return columnsGroup;\n };\n const generate$1 = list => {\n const access = {};\n const cells = [];\n const tableOpt = head(list).map(rowData => rowData.element).bind(table);\n const lockedColumns = tableOpt.bind(getLockedColumnsFromTable).getOr({});\n let maxRows = 0;\n let maxColumns = 0;\n let rowCount = 0;\n const {\n pass: colgroupRows,\n fail: rows\n } = partition(list, rowData => rowData.section === 'colgroup');\n each(rows, rowData => {\n const currentRow = [];\n each(rowData.cells, rowCell => {\n let start = 0;\n while (access[key(rowCount, start)] !== undefined) {\n start++;\n }\n const isLocked = hasNonNullableKey(lockedColumns, start.toString());\n const current = extended(rowCell.element, rowCell.rowspan, rowCell.colspan, rowCount, start, isLocked);\n for (let occupiedColumnPosition = 0; occupiedColumnPosition < rowCell.colspan; occupiedColumnPosition++) {\n for (let occupiedRowPosition = 0; occupiedRowPosition < rowCell.rowspan; occupiedRowPosition++) {\n const rowPosition = rowCount + occupiedRowPosition;\n const columnPosition = start + occupiedColumnPosition;\n const newpos = key(rowPosition, columnPosition);\n access[newpos] = current;\n maxColumns = Math.max(maxColumns, columnPosition + 1);\n }\n }\n currentRow.push(current);\n });\n maxRows++;\n cells.push(rowdetail(rowData.element, currentRow, rowData.section));\n rowCount++;\n });\n const {columns, colgroups} = last(colgroupRows).map(rowData => {\n const columns = generateColumns(rowData);\n const colgroup$1 = colgroup(rowData.element, values(columns));\n return {\n colgroups: [colgroup$1],\n columns\n };\n }).getOrThunk(() => ({\n colgroups: [],\n columns: {}\n }));\n const grid$1 = grid(maxRows, maxColumns);\n return {\n grid: grid$1,\n access,\n all: cells,\n columns,\n colgroups\n };\n };\n const fromTable = table => {\n const list = fromTable$1(table);\n return generate$1(list);\n };\n const justCells = warehouse => bind(warehouse.all, w => w.cells);\n const justColumns = warehouse => values(warehouse.columns);\n const hasColumns = warehouse => keys(warehouse.columns).length > 0;\n const getColumnAt = (warehouse, columnIndex) => Optional.from(warehouse.columns[columnIndex]);\n const Warehouse = {\n fromTable,\n generate: generate$1,\n getAt,\n findItem,\n filterItems,\n justCells,\n justColumns,\n hasColumns,\n getColumnAt\n };\n\n var global$2 = tinymce.util.Tools.resolve('tinymce.util.Tools');\n\n const getTDTHOverallStyle = (dom, elm, name) => {\n const cells = dom.select('td,th', elm);\n let firstChildStyle;\n for (let i = 0; i < cells.length; i++) {\n const currentStyle = dom.getStyle(cells[i], name);\n if (isUndefined(firstChildStyle)) {\n firstChildStyle = currentStyle;\n }\n if (firstChildStyle !== currentStyle) {\n return '';\n }\n }\n return firstChildStyle;\n };\n const setAlign = (editor, elm, name) => {\n global$2.each('left center right'.split(' '), align => {\n if (align !== name) {\n editor.formatter.remove('align' + align, {}, elm);\n }\n });\n if (name) {\n editor.formatter.apply('align' + name, {}, elm);\n }\n };\n const setVAlign = (editor, elm, name) => {\n global$2.each('top middle bottom'.split(' '), align => {\n if (align !== name) {\n editor.formatter.remove('valign' + align, {}, elm);\n }\n });\n if (name) {\n editor.formatter.apply('valign' + name, {}, elm);\n }\n };\n\n const fireTableModified = (editor, table, data) => {\n editor.dispatch('TableModified', {\n ...data,\n table\n });\n };\n\n const toNumber = (px, fallback) => toFloat(px).getOr(fallback);\n const getProp = (element, name, fallback) => toNumber(get$1(element, name), fallback);\n const calcContentBoxSize = (element, size, upper, lower) => {\n const paddingUpper = getProp(element, `padding-${ upper }`, 0);\n const paddingLower = getProp(element, `padding-${ lower }`, 0);\n const borderUpper = getProp(element, `border-${ upper }-width`, 0);\n const borderLower = getProp(element, `border-${ lower }-width`, 0);\n return size - paddingUpper - paddingLower - borderUpper - borderLower;\n };\n const getCalculatedWidth = (element, boxSizing) => {\n const dom = element.dom;\n const width = dom.getBoundingClientRect().width || dom.offsetWidth;\n return boxSizing === 'border-box' ? width : calcContentBoxSize(element, width, 'left', 'right');\n };\n const getInnerWidth = element => getCalculatedWidth(element, 'content-box');\n\n const getInner = getInnerWidth;\n\n var global$1 = tinymce.util.Tools.resolve('tinymce.Env');\n\n const defaultTableToolbar = 'tableprops tabledelete | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol';\n const defaultCellBorderWidths = range(5, i => {\n const size = `${ i + 1 }px`;\n return {\n title: size,\n value: size\n };\n });\n const defaultCellBorderStyles = map([\n 'Solid',\n 'Dotted',\n 'Dashed',\n 'Double',\n 'Groove',\n 'Ridge',\n 'Inset',\n 'Outset',\n 'None',\n 'Hidden'\n ], type => {\n return {\n title: type,\n value: type.toLowerCase()\n };\n });\n const defaultWidth = '100%';\n const getPixelForcedWidth = editor => {\n var _a;\n const dom = editor.dom;\n const parentBlock = (_a = dom.getParent(editor.selection.getStart(), dom.isBlock)) !== null && _a !== void 0 ? _a : editor.getBody();\n return getInner(SugarElement.fromDom(parentBlock)) + 'px';\n };\n const determineDefaultStyles = (editor, defaultStyles) => {\n if (isResponsiveForced(editor) || !shouldStyleWithCss(editor)) {\n return defaultStyles;\n } else if (isPixelsForced(editor)) {\n return {\n ...defaultStyles,\n width: getPixelForcedWidth(editor)\n };\n } else {\n return {\n ...defaultStyles,\n width: defaultWidth\n };\n }\n };\n const determineDefaultAttributes = (editor, defaultAttributes) => {\n if (isResponsiveForced(editor) || shouldStyleWithCss(editor)) {\n return defaultAttributes;\n } else if (isPixelsForced(editor)) {\n return {\n ...defaultAttributes,\n width: getPixelForcedWidth(editor)\n };\n } else {\n return {\n ...defaultAttributes,\n width: defaultWidth\n };\n }\n };\n const option = name => editor => editor.options.get(name);\n const register = editor => {\n const registerOption = editor.options.register;\n registerOption('table_border_widths', {\n processor: 'object[]',\n default: defaultCellBorderWidths\n });\n registerOption('table_border_styles', {\n processor: 'object[]',\n default: defaultCellBorderStyles\n });\n registerOption('table_cell_advtab', {\n processor: 'boolean',\n default: true\n });\n registerOption('table_row_advtab', {\n processor: 'boolean',\n default: true\n });\n registerOption('table_advtab', {\n processor: 'boolean',\n default: true\n });\n registerOption('table_appearance_options', {\n processor: 'boolean',\n default: true\n });\n registerOption('table_grid', {\n processor: 'boolean',\n default: !global$1.deviceType.isTouch()\n });\n registerOption('table_cell_class_list', {\n processor: 'object[]',\n default: []\n });\n registerOption('table_row_class_list', {\n processor: 'object[]',\n default: []\n });\n registerOption('table_class_list', {\n processor: 'object[]',\n default: []\n });\n registerOption('table_toolbar', {\n processor: 'string',\n default: defaultTableToolbar\n });\n registerOption('table_background_color_map', {\n processor: 'object[]',\n default: []\n });\n registerOption('table_border_color_map', {\n processor: 'object[]',\n default: []\n });\n };\n const getTableSizingMode = option('table_sizing_mode');\n const getTableBorderWidths = option('table_border_widths');\n const getTableBorderStyles = option('table_border_styles');\n const hasAdvancedCellTab = option('table_cell_advtab');\n const hasAdvancedRowTab = option('table_row_advtab');\n const hasAdvancedTableTab = option('table_advtab');\n const hasAppearanceOptions = option('table_appearance_options');\n const hasTableGrid = option('table_grid');\n const shouldStyleWithCss = option('table_style_by_css');\n const getCellClassList = option('table_cell_class_list');\n const getRowClassList = option('table_row_class_list');\n const getTableClassList = option('table_class_list');\n const getToolbar = option('table_toolbar');\n const getTableBackgroundColorMap = option('table_background_color_map');\n const getTableBorderColorMap = option('table_border_color_map');\n const isPixelsForced = editor => getTableSizingMode(editor) === 'fixed';\n const isResponsiveForced = editor => getTableSizingMode(editor) === 'responsive';\n const getDefaultStyles = editor => {\n const options = editor.options;\n const defaultStyles = options.get('table_default_styles');\n return options.isSet('table_default_styles') ? defaultStyles : determineDefaultStyles(editor, defaultStyles);\n };\n const getDefaultAttributes = editor => {\n const options = editor.options;\n const defaultAttributes = options.get('table_default_attributes');\n return options.isSet('table_default_attributes') ? defaultAttributes : determineDefaultAttributes(editor, defaultAttributes);\n };\n\n const isWithin = (bounds, detail) => {\n return detail.column >= bounds.startCol && detail.column + detail.colspan - 1 <= bounds.finishCol && detail.row >= bounds.startRow && detail.row + detail.rowspan - 1 <= bounds.finishRow;\n };\n const isRectangular = (warehouse, bounds) => {\n let isRect = true;\n const detailIsWithin = curry(isWithin, bounds);\n for (let i = bounds.startRow; i <= bounds.finishRow; i++) {\n for (let j = bounds.startCol; j <= bounds.finishCol; j++) {\n isRect = isRect && Warehouse.getAt(warehouse, i, j).exists(detailIsWithin);\n }\n }\n return isRect ? Optional.some(bounds) : Optional.none();\n };\n\n const getBounds = (detailA, detailB) => {\n return bounds(Math.min(detailA.row, detailB.row), Math.min(detailA.column, detailB.column), Math.max(detailA.row + detailA.rowspan - 1, detailB.row + detailB.rowspan - 1), Math.max(detailA.column + detailA.colspan - 1, detailB.column + detailB.colspan - 1));\n };\n const getAnyBox = (warehouse, startCell, finishCell) => {\n const startCoords = Warehouse.findItem(warehouse, startCell, eq);\n const finishCoords = Warehouse.findItem(warehouse, finishCell, eq);\n return startCoords.bind(sc => {\n return finishCoords.map(fc => {\n return getBounds(sc, fc);\n });\n });\n };\n const getBox$1 = (warehouse, startCell, finishCell) => {\n return getAnyBox(warehouse, startCell, finishCell).bind(bounds => {\n return isRectangular(warehouse, bounds);\n });\n };\n\n const getBox = (table, first, last) => {\n const warehouse = getWarehouse(table);\n return getBox$1(warehouse, first, last);\n };\n const getWarehouse = Warehouse.fromTable;\n\n const before = (marker, element) => {\n const parent$1 = parent(marker);\n parent$1.each(v => {\n v.dom.insertBefore(element.dom, marker.dom);\n });\n };\n const after$1 = (marker, element) => {\n const sibling = nextSibling(marker);\n sibling.fold(() => {\n const parent$1 = parent(marker);\n parent$1.each(v => {\n append$1(v, element);\n });\n }, v => {\n before(v, element);\n });\n };\n const prepend = (parent, element) => {\n const firstChild$1 = firstChild(parent);\n firstChild$1.fold(() => {\n append$1(parent, element);\n }, v => {\n parent.dom.insertBefore(element.dom, v.dom);\n });\n };\n const append$1 = (parent, element) => {\n parent.dom.appendChild(element.dom);\n };\n const wrap = (element, wrapper) => {\n before(element, wrapper);\n append$1(wrapper, element);\n };\n\n const after = (marker, elements) => {\n each(elements, (x, i) => {\n const e = i === 0 ? marker : elements[i - 1];\n after$1(e, x);\n });\n };\n const append = (parent, elements) => {\n each(elements, x => {\n append$1(parent, x);\n });\n };\n\n const remove = element => {\n const dom = element.dom;\n if (dom.parentNode !== null) {\n dom.parentNode.removeChild(dom);\n }\n };\n const unwrap = wrapper => {\n const children = children$3(wrapper);\n if (children.length > 0) {\n after(wrapper, children);\n }\n remove(wrapper);\n };\n\n const NodeValue = (is, name) => {\n const get = element => {\n if (!is(element)) {\n throw new Error('Can only get ' + name + ' value of a ' + name + ' node');\n }\n return getOption(element).getOr('');\n };\n const getOption = element => is(element) ? Optional.from(element.dom.nodeValue) : Optional.none();\n const set = (element, value) => {\n if (!is(element)) {\n throw new Error('Can only set raw ' + name + ' value of a ' + name + ' node');\n }\n element.dom.nodeValue = value;\n };\n return {\n get,\n getOption,\n set\n };\n };\n\n const api = NodeValue(isText, 'text');\n const get = element => api.get(element);\n const set = (element, value) => api.set(element, value);\n\n var TagBoundaries = [\n 'body',\n 'p',\n 'div',\n 'article',\n 'aside',\n 'figcaption',\n 'figure',\n 'footer',\n 'header',\n 'nav',\n 'section',\n 'ol',\n 'ul',\n 'li',\n 'table',\n 'thead',\n 'tbody',\n 'tfoot',\n 'caption',\n 'tr',\n 'td',\n 'th',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'blockquote',\n 'pre',\n 'address'\n ];\n\n var DomUniverse = () => {\n const clone$1 = element => {\n return SugarElement.fromDom(element.dom.cloneNode(false));\n };\n const document = element => documentOrOwner(element).dom;\n const isBoundary = element => {\n if (!isElement(element)) {\n return false;\n }\n if (name(element) === 'body') {\n return true;\n }\n return contains(TagBoundaries, name(element));\n };\n const isEmptyTag = element => {\n if (!isElement(element)) {\n return false;\n }\n return contains([\n 'br',\n 'img',\n 'hr',\n 'input'\n ], name(element));\n };\n const isNonEditable = element => isElement(element) && get$2(element, 'contenteditable') === 'false';\n const comparePosition = (element, other) => {\n return element.dom.compareDocumentPosition(other.dom);\n };\n const copyAttributesTo = (source, destination) => {\n const as = clone(source);\n setAll(destination, as);\n };\n const isSpecial = element => {\n const tag = name(element);\n return contains([\n 'script',\n 'noscript',\n 'iframe',\n 'noframes',\n 'noembed',\n 'title',\n 'style',\n 'textarea',\n 'xmp'\n ], tag);\n };\n const getLanguage = element => isElement(element) ? getOpt(element, 'lang') : Optional.none();\n return {\n up: constant({\n selector: ancestor,\n closest: closest$1,\n predicate: ancestor$1,\n all: parents\n }),\n down: constant({\n selector: descendants,\n predicate: descendants$1\n }),\n styles: constant({\n get: get$1,\n getRaw: getRaw,\n set: set$1,\n remove: remove$1\n }),\n attrs: constant({\n get: get$2,\n set: set$2,\n remove: remove$2,\n copyTo: copyAttributesTo\n }),\n insert: constant({\n before: before,\n after: after$1,\n afterAll: after,\n append: append$1,\n appendAll: append,\n prepend: prepend,\n wrap: wrap\n }),\n remove: constant({\n unwrap: unwrap,\n remove: remove\n }),\n create: constant({\n nu: SugarElement.fromTag,\n clone: clone$1,\n text: SugarElement.fromText\n }),\n query: constant({\n comparePosition,\n prevSibling: prevSibling,\n nextSibling: nextSibling\n }),\n property: constant({\n children: children$3,\n name: name,\n parent: parent,\n document,\n isText: isText,\n isComment: isComment,\n isElement: isElement,\n isSpecial,\n getLanguage,\n getText: get,\n setText: set,\n isBoundary,\n isEmptyTag,\n isNonEditable\n }),\n eq: eq,\n is: is$1\n };\n };\n\n const all = (universe, look, elements, f) => {\n const head = elements[0];\n const tail = elements.slice(1);\n return f(universe, look, head, tail);\n };\n const oneAll = (universe, look, elements) => {\n return elements.length > 0 ? all(universe, look, elements, unsafeOne) : Optional.none();\n };\n const unsafeOne = (universe, look, head, tail) => {\n const start = look(universe, head);\n return foldr(tail, (b, a) => {\n const current = look(universe, a);\n return commonElement(universe, b, current);\n }, start);\n };\n const commonElement = (universe, start, end) => {\n return start.bind(s => {\n return end.filter(curry(universe.eq, s));\n });\n };\n\n const sharedOne$1 = oneAll;\n\n const universe = DomUniverse();\n const sharedOne = (look, elements) => {\n return sharedOne$1(universe, (_universe, element) => {\n return look(element);\n }, elements);\n };\n\n const lookupTable = container => {\n return ancestor(container, 'table');\n };\n const retrieve$1 = (container, selector) => {\n const sels = descendants(container, selector);\n return sels.length > 0 ? Optional.some(sels) : Optional.none();\n };\n const getEdges = (container, firstSelectedSelector, lastSelectedSelector) => {\n return descendant(container, firstSelectedSelector).bind(first => {\n return descendant(container, lastSelectedSelector).bind(last => {\n return sharedOne(lookupTable, [\n first,\n last\n ]).map(table => {\n return {\n first,\n last,\n table\n };\n });\n });\n });\n };\n\n const retrieve = (container, selector) => {\n return retrieve$1(container, selector);\n };\n const retrieveBox = (container, firstSelectedSelector, lastSelectedSelector) => {\n return getEdges(container, firstSelectedSelector, lastSelectedSelector).bind(edges => {\n const isRoot = ancestor => {\n return eq(container, ancestor);\n };\n const sectionSelector = 'thead,tfoot,tbody,table';\n const firstAncestor = ancestor(edges.first, sectionSelector, isRoot);\n const lastAncestor = ancestor(edges.last, sectionSelector, isRoot);\n return firstAncestor.bind(fA => {\n return lastAncestor.bind(lA => {\n return eq(fA, lA) ? getBox(edges.table, edges.first, edges.last) : Optional.none();\n });\n });\n });\n };\n\n const fromDom = nodes => map(nodes, SugarElement.fromDom);\n\n const strSelected = 'data-mce-selected';\n const strSelectedSelector = 'td[' + strSelected + '],th[' + strSelected + ']';\n const strFirstSelected = 'data-mce-first-selected';\n const strFirstSelectedSelector = 'td[' + strFirstSelected + '],th[' + strFirstSelected + ']';\n const strLastSelected = 'data-mce-last-selected';\n const strLastSelectedSelector = 'td[' + strLastSelected + '],th[' + strLastSelected + ']';\n const ephemera = {\n selected: strSelected,\n selectedSelector: strSelectedSelector,\n firstSelected: strFirstSelected,\n firstSelectedSelector: strFirstSelectedSelector,\n lastSelected: strLastSelected,\n lastSelectedSelector: strLastSelectedSelector\n };\n\n const getSelectionCellFallback = element => table(element).bind(table => retrieve(table, ephemera.firstSelectedSelector)).fold(constant(element), cells => cells[0]);\n const getSelectionFromSelector = selector => (initCell, isRoot) => {\n const cellName = name(initCell);\n const cell = cellName === 'col' || cellName === 'colgroup' ? getSelectionCellFallback(initCell) : initCell;\n return closest$1(cell, selector, isRoot);\n };\n const getSelectionCellOrCaption = getSelectionFromSelector('th,td,caption');\n const getSelectionCell = getSelectionFromSelector('th,td');\n const getCellsFromSelection = editor => fromDom(editor.model.table.getSelectedCells());\n const getRowsFromSelection = (selected, selector) => {\n const cellOpt = getSelectionCell(selected);\n const rowsOpt = cellOpt.bind(cell => table(cell)).map(table => rows(table));\n return lift2(cellOpt, rowsOpt, (cell, rows) => filter(rows, row => exists(fromDom(row.dom.cells), rowCell => get$2(rowCell, selector) === '1' || eq(rowCell, cell)))).getOr([]);\n };\n\n const verticalAlignValues = [\n {\n text: 'None',\n value: ''\n },\n {\n text: 'Top',\n value: 'top'\n },\n {\n text: 'Middle',\n value: 'middle'\n },\n {\n text: 'Bottom',\n value: 'bottom'\n }\n ];\n\n const hexColour = value => ({ value: normalizeHex(value) });\n const shorthandRegex = /^#?([a-f\\d])([a-f\\d])([a-f\\d])$/i;\n const longformRegex = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i;\n const isHexString = hex => shorthandRegex.test(hex) || longformRegex.test(hex);\n const normalizeHex = hex => removeLeading(hex, '#').toUpperCase();\n const fromString$1 = hex => isHexString(hex) ? Optional.some({ value: normalizeHex(hex) }) : Optional.none();\n const toHex = component => {\n const hex = component.toString(16);\n return (hex.length === 1 ? '0' + hex : hex).toUpperCase();\n };\n const fromRgba = rgbaColour => {\n const value = toHex(rgbaColour.red) + toHex(rgbaColour.green) + toHex(rgbaColour.blue);\n return hexColour(value);\n };\n\n const rgbRegex = /^\\s*rgb\\s*\\(\\s*(\\d+)\\s*[,\\s]\\s*(\\d+)\\s*[,\\s]\\s*(\\d+)\\s*\\)\\s*$/i;\n const rgbaRegex = /^\\s*rgba\\s*\\(\\s*(\\d+)\\s*[,\\s]\\s*(\\d+)\\s*[,\\s]\\s*(\\d+)\\s*[,\\s]\\s*((?:\\d?\\.\\d+|\\d+)%?)\\s*\\)\\s*$/i;\n const rgbaColour = (red, green, blue, alpha) => ({\n red,\n green,\n blue,\n alpha\n });\n const fromStringValues = (red, green, blue, alpha) => {\n const r = parseInt(red, 10);\n const g = parseInt(green, 10);\n const b = parseInt(blue, 10);\n const a = parseFloat(alpha);\n return rgbaColour(r, g, b, a);\n };\n const fromString = rgbaString => {\n const rgbMatch = rgbRegex.exec(rgbaString);\n if (rgbMatch !== null) {\n return Optional.some(fromStringValues(rgbMatch[1], rgbMatch[2], rgbMatch[3], '1'));\n }\n const rgbaMatch = rgbaRegex.exec(rgbaString);\n if (rgbaMatch !== null) {\n return Optional.some(fromStringValues(rgbaMatch[1], rgbaMatch[2], rgbaMatch[3], rgbaMatch[4]));\n }\n return Optional.none();\n };\n\n const anyToHex = color => fromString$1(color).orThunk(() => fromString(color).map(fromRgba)).getOrThunk(() => {\n const canvas = document.createElement('canvas');\n canvas.height = 1;\n canvas.width = 1;\n const canvasContext = canvas.getContext('2d');\n canvasContext.clearRect(0, 0, canvas.width, canvas.height);\n canvasContext.fillStyle = '#FFFFFF';\n canvasContext.fillStyle = color;\n canvasContext.fillRect(0, 0, 1, 1);\n const rgba = canvasContext.getImageData(0, 0, 1, 1).data;\n const r = rgba[0];\n const g = rgba[1];\n const b = rgba[2];\n const a = rgba[3];\n return fromRgba(rgbaColour(r, g, b, a));\n });\n const rgbaToHexString = color => fromString(color).map(fromRgba).map(h => '#' + h.value).getOr(color);\n\n const Cell = initial => {\n let value = initial;\n const get = () => {\n return value;\n };\n const set = v => {\n value = v;\n };\n return {\n get,\n set\n };\n };\n\n const singleton = doRevoke => {\n const subject = Cell(Optional.none());\n const revoke = () => subject.get().each(doRevoke);\n const clear = () => {\n revoke();\n subject.set(Optional.none());\n };\n const isSet = () => subject.get().isSome();\n const get = () => subject.get();\n const set = s => {\n revoke();\n subject.set(Optional.some(s));\n };\n return {\n clear,\n isSet,\n get,\n set\n };\n };\n const unbindable = () => singleton(s => s.unbind());\n\n const onSetupToggle = (editor, formatName, formatValue) => {\n return api => {\n const boundCallback = unbindable();\n const isNone = isEmpty(formatValue);\n const init = () => {\n const selectedCells = getCellsFromSelection(editor);\n const checkNode = cell => editor.formatter.match(formatName, { value: formatValue }, cell.dom, isNone);\n if (isNone) {\n api.setActive(!exists(selectedCells, checkNode));\n boundCallback.set(editor.formatter.formatChanged(formatName, match => api.setActive(!match), true));\n } else {\n api.setActive(forall(selectedCells, checkNode));\n boundCallback.set(editor.formatter.formatChanged(formatName, api.setActive, false, { value: formatValue }));\n }\n };\n editor.initialized ? init() : editor.on('init', init);\n return boundCallback.clear;\n };\n };\n const isListGroup = item => hasNonNullableKey(item, 'menu');\n const buildListItems = items => map(items, item => {\n const text = item.text || item.title || '';\n if (isListGroup(item)) {\n return {\n text,\n items: buildListItems(item.menu)\n };\n } else {\n return {\n text,\n value: item.value\n };\n }\n });\n const buildClassList = classList => {\n if (!classList.length) {\n return Optional.none();\n }\n return Optional.some(buildListItems([\n {\n text: 'Select...',\n value: 'mce-no-match'\n },\n ...classList\n ]));\n };\n const buildMenuItems = (editor, items, format, onAction) => map(items, item => {\n const text = item.text || item.title;\n if (isListGroup(item)) {\n return {\n type: 'nestedmenuitem',\n text,\n getSubmenuItems: () => buildMenuItems(editor, item.menu, format, onAction)\n };\n } else {\n return {\n text,\n type: 'togglemenuitem',\n onAction: () => onAction(item.value),\n onSetup: onSetupToggle(editor, format, item.value)\n };\n }\n });\n const applyTableCellStyle = (editor, style) => value => {\n editor.execCommand('mceTableApplyCellStyle', false, { [style]: value });\n };\n const filterNoneItem = list => bind(list, item => {\n if (isListGroup(item)) {\n return [{\n ...item,\n menu: filterNoneItem(item.menu)\n }];\n } else {\n return isNotEmpty(item.value) ? [item] : [];\n }\n });\n const generateMenuItemsCallback = (editor, items, format, onAction) => callback => callback(buildMenuItems(editor, items, format, onAction));\n const buildColorMenu = (editor, colorList, style) => {\n const colorMap = map(colorList, entry => ({\n text: entry.title,\n value: '#' + anyToHex(entry.value).value,\n type: 'choiceitem'\n }));\n return [{\n type: 'fancymenuitem',\n fancytype: 'colorswatch',\n initData: {\n colors: colorMap.length > 0 ? colorMap : undefined,\n allowCustomColors: false\n },\n onAction: data => {\n const value = data.value === 'remove' ? '' : data.value;\n editor.execCommand('mceTableApplyCellStyle', false, { [style]: value });\n }\n }];\n };\n const changeRowHeader = editor => () => {\n const currentType = editor.queryCommandValue('mceTableRowType');\n const newType = currentType === 'header' ? 'body' : 'header';\n editor.execCommand('mceTableRowType', false, { type: newType });\n };\n const changeColumnHeader = editor => () => {\n const currentType = editor.queryCommandValue('mceTableColType');\n const newType = currentType === 'th' ? 'td' : 'th';\n editor.execCommand('mceTableColType', false, { type: newType });\n };\n\n const getClassList$1 = editor => buildClassList(getCellClassList(editor)).map(items => ({\n name: 'class',\n type: 'listbox',\n label: 'Class',\n items\n }));\n const children = [\n {\n name: 'width',\n type: 'input',\n label: 'Width'\n },\n {\n name: 'celltype',\n type: 'listbox',\n label: 'Cell type',\n items: [\n {\n text: 'Cell',\n value: 'td'\n },\n {\n text: 'Header cell',\n value: 'th'\n }\n ]\n },\n {\n name: 'scope',\n type: 'listbox',\n label: 'Scope',\n items: [\n {\n text: 'None',\n value: ''\n },\n {\n text: 'Row',\n value: 'row'\n },\n {\n text: 'Column',\n value: 'col'\n },\n {\n text: 'Row group',\n value: 'rowgroup'\n },\n {\n text: 'Column group',\n value: 'colgroup'\n }\n ]\n },\n {\n name: 'halign',\n type: 'listbox',\n label: 'Horizontal align',\n items: [\n {\n text: 'None',\n value: ''\n },\n {\n text: 'Left',\n value: 'left'\n },\n {\n text: 'Center',\n value: 'center'\n },\n {\n text: 'Right',\n value: 'right'\n }\n ]\n },\n {\n name: 'valign',\n type: 'listbox',\n label: 'Vertical align',\n items: verticalAlignValues\n }\n ];\n const getItems$2 = editor => children.concat(getClassList$1(editor).toArray());\n\n const getAdvancedTab = (editor, dialogName) => {\n const emptyBorderStyle = [{\n text: 'Select...',\n value: ''\n }];\n const advTabItems = [\n {\n name: 'borderstyle',\n type: 'listbox',\n label: 'Border style',\n items: emptyBorderStyle.concat(buildListItems(getTableBorderStyles(editor)))\n },\n {\n name: 'bordercolor',\n type: 'colorinput',\n label: 'Border color'\n },\n {\n name: 'backgroundcolor',\n type: 'colorinput',\n label: 'Background color'\n }\n ];\n const borderWidth = {\n name: 'borderwidth',\n type: 'input',\n label: 'Border width'\n };\n const items = dialogName === 'cell' ? [borderWidth].concat(advTabItems) : advTabItems;\n return {\n title: 'Advanced',\n name: 'advanced',\n items\n };\n };\n\n const normal = (editor, element) => {\n const dom = editor.dom;\n const setAttrib = (attr, value) => {\n dom.setAttrib(element, attr, value);\n };\n const setStyle = (prop, value) => {\n dom.setStyle(element, prop, value);\n };\n const setFormat = (formatName, value) => {\n if (value === '') {\n editor.formatter.remove(formatName, { value: null }, element, true);\n } else {\n editor.formatter.apply(formatName, { value }, element);\n }\n };\n return {\n setAttrib,\n setStyle,\n setFormat\n };\n };\n const DomModifier = { normal };\n\n const isHeaderCell = isTag('th');\n const getRowHeaderType = (isHeaderRow, isHeaderCells) => {\n if (isHeaderRow && isHeaderCells) {\n return 'sectionCells';\n } else if (isHeaderRow) {\n return 'section';\n } else {\n return 'cells';\n }\n };\n const getRowType$1 = row => {\n const isHeaderRow = row.section === 'thead';\n const isHeaderCells = is(findCommonCellType(row.cells), 'th');\n if (row.section === 'tfoot') {\n return { type: 'footer' };\n } else if (isHeaderRow || isHeaderCells) {\n return {\n type: 'header',\n subType: getRowHeaderType(isHeaderRow, isHeaderCells)\n };\n } else {\n return { type: 'body' };\n }\n };\n const findCommonCellType = cells => {\n const headerCells = filter(cells, cell => isHeaderCell(cell.element));\n if (headerCells.length === 0) {\n return Optional.some('td');\n } else if (headerCells.length === cells.length) {\n return Optional.some('th');\n } else {\n return Optional.none();\n }\n };\n const findCommonRowType = rows => {\n const rowTypes = map(rows, row => getRowType$1(row).type);\n const hasHeader = contains(rowTypes, 'header');\n const hasFooter = contains(rowTypes, 'footer');\n if (!hasHeader && !hasFooter) {\n return Optional.some('body');\n } else {\n const hasBody = contains(rowTypes, 'body');\n if (hasHeader && !hasBody && !hasFooter) {\n return Optional.some('header');\n } else if (!hasHeader && !hasBody && hasFooter) {\n return Optional.some('footer');\n } else {\n return Optional.none();\n }\n }\n };\n\n const cached = f => {\n let called = false;\n let r;\n return (...args) => {\n if (!called) {\n called = true;\n r = f.apply(null, args);\n }\n return r;\n };\n };\n\n const findInWarehouse = (warehouse, element) => findMap(warehouse.all, r => find(r.cells, e => eq(element, e.element)));\n const extractCells = (warehouse, target, predicate) => {\n const details = map(target.selection, cell$1 => {\n return cell(cell$1).bind(lc => findInWarehouse(warehouse, lc)).filter(predicate);\n });\n const cells = cat(details);\n return someIf(cells.length > 0, cells);\n };\n const onMergable = (_warehouse, target) => target.mergable;\n const onUnmergable = (_warehouse, target) => target.unmergable;\n const onCells = (warehouse, target) => extractCells(warehouse, target, always);\n const isUnlockedTableCell = (warehouse, cell) => findInWarehouse(warehouse, cell).exists(detail => !detail.isLocked);\n const allUnlocked = (warehouse, cells) => forall(cells, cell => isUnlockedTableCell(warehouse, cell));\n const onUnlockedMergable = (warehouse, target) => onMergable(warehouse, target).filter(mergeable => allUnlocked(warehouse, mergeable.cells));\n const onUnlockedUnmergable = (warehouse, target) => onUnmergable(warehouse, target).filter(cells => allUnlocked(warehouse, cells));\n\n const generate = cases => {\n if (!isArray(cases)) {\n throw new Error('cases must be an array');\n }\n if (cases.length === 0) {\n throw new Error('there must be at least one case');\n }\n const constructors = [];\n const adt = {};\n each(cases, (acase, count) => {\n const keys$1 = keys(acase);\n if (keys$1.length !== 1) {\n throw new Error('one and only one name per case');\n }\n const key = keys$1[0];\n const value = acase[key];\n if (adt[key] !== undefined) {\n throw new Error('duplicate key detected:' + key);\n } else if (key === 'cata') {\n throw new Error('cannot have a case named cata (sorry)');\n } else if (!isArray(value)) {\n throw new Error('case arguments must be an array');\n }\n constructors.push(key);\n adt[key] = (...args) => {\n const argLength = args.length;\n if (argLength !== value.length) {\n throw new Error('Wrong number of arguments to case ' + key + '. Expected ' + value.length + ' (' + value + '), got ' + argLength);\n }\n const match = branches => {\n const branchKeys = keys(branches);\n if (constructors.length !== branchKeys.length) {\n throw new Error('Wrong number of arguments to match. Expected: ' + constructors.join(',') + '\\nActual: ' + branchKeys.join(','));\n }\n const allReqd = forall(constructors, reqKey => {\n return contains(branchKeys, reqKey);\n });\n if (!allReqd) {\n throw new Error('Not all branches were specified when using match. Specified: ' + branchKeys.join(', ') + '\\nRequired: ' + constructors.join(', '));\n }\n return branches[key].apply(null, args);\n };\n return {\n fold: (...foldArgs) => {\n if (foldArgs.length !== cases.length) {\n throw new Error('Wrong number of arguments to fold. Expected ' + cases.length + ', got ' + foldArgs.length);\n }\n const target = foldArgs[count];\n return target.apply(null, args);\n },\n match,\n log: label => {\n console.log(label, {\n constructors,\n constructor: key,\n params: args\n });\n }\n };\n };\n });\n return adt;\n };\n const Adt = { generate };\n\n const adt = Adt.generate([\n { none: [] },\n { only: ['index'] },\n {\n left: [\n 'index',\n 'next'\n ]\n },\n {\n middle: [\n 'prev',\n 'index',\n 'next'\n ]\n },\n {\n right: [\n 'prev',\n 'index'\n ]\n }\n ]);\n ({ ...adt });\n\n const opGetRowsType = (table, target) => {\n const house = Warehouse.fromTable(table);\n const details = onCells(house, target);\n return details.bind(selectedCells => {\n const lastSelectedCell = selectedCells[selectedCells.length - 1];\n const minRowRange = selectedCells[0].row;\n const maxRowRange = lastSelectedCell.row + lastSelectedCell.rowspan;\n const selectedRows = house.all.slice(minRowRange, maxRowRange);\n return findCommonRowType(selectedRows);\n }).getOr('');\n };\n const getRowsType = opGetRowsType;\n\n const rgbToHex = value => startsWith(value, 'rgb') ? rgbaToHexString(value) : value;\n const extractAdvancedStyles = elm => {\n const element = SugarElement.fromDom(elm);\n return {\n borderwidth: getRaw(element, 'border-width').getOr(''),\n borderstyle: getRaw(element, 'border-style').getOr(''),\n bordercolor: getRaw(element, 'border-color').map(rgbToHex).getOr(''),\n backgroundcolor: getRaw(element, 'background-color').map(rgbToHex).getOr('')\n };\n };\n const getSharedValues = data => {\n const baseData = data[0];\n const comparisonData = data.slice(1);\n each(comparisonData, items => {\n each(keys(baseData), key => {\n each$1(items, (itemValue, itemKey) => {\n const comparisonValue = baseData[key];\n if (comparisonValue !== '' && key === itemKey) {\n if (comparisonValue !== itemValue) {\n baseData[key] = key === 'class' ? 'mce-no-match' : '';\n }\n }\n });\n });\n });\n return baseData;\n };\n const getAlignment = (formats, formatName, editor, elm) => find(formats, name => !isUndefined(editor.formatter.matchNode(elm, formatName + name))).getOr('');\n const getHAlignment = curry(getAlignment, [\n 'left',\n 'center',\n 'right'\n ], 'align');\n const getVAlignment = curry(getAlignment, [\n 'top',\n 'middle',\n 'bottom'\n ], 'valign');\n const extractDataFromSettings = (editor, hasAdvTableTab) => {\n const style = getDefaultStyles(editor);\n const attrs = getDefaultAttributes(editor);\n const extractAdvancedStyleData = () => ({\n borderstyle: get$4(style, 'border-style').getOr(''),\n bordercolor: rgbToHex(get$4(style, 'border-color').getOr('')),\n backgroundcolor: rgbToHex(get$4(style, 'background-color').getOr(''))\n });\n const defaultData = {\n height: '',\n width: '100%',\n cellspacing: '',\n cellpadding: '',\n caption: false,\n class: '',\n align: '',\n border: ''\n };\n const getBorder = () => {\n const borderWidth = style['border-width'];\n if (shouldStyleWithCss(editor) && borderWidth) {\n return { border: borderWidth };\n }\n return get$4(attrs, 'border').fold(() => ({}), border => ({ border }));\n };\n const advStyle = hasAdvTableTab ? extractAdvancedStyleData() : {};\n const getCellPaddingCellSpacing = () => {\n const spacing = get$4(style, 'border-spacing').or(get$4(attrs, 'cellspacing')).fold(() => ({}), cellspacing => ({ cellspacing }));\n const padding = get$4(style, 'border-padding').or(get$4(attrs, 'cellpadding')).fold(() => ({}), cellpadding => ({ cellpadding }));\n return {\n ...spacing,\n ...padding\n };\n };\n const data = {\n ...defaultData,\n ...style,\n ...attrs,\n ...advStyle,\n ...getBorder(),\n ...getCellPaddingCellSpacing()\n };\n return data;\n };\n const getRowType = elm => table(SugarElement.fromDom(elm)).map(table => {\n const target = { selection: fromDom(elm.cells) };\n return getRowsType(table, target);\n }).getOr('');\n const extractDataFromTableElement = (editor, elm, hasAdvTableTab) => {\n const getBorder = (dom, elm) => {\n const optBorderWidth = getRaw(SugarElement.fromDom(elm), 'border-width');\n if (shouldStyleWithCss(editor) && optBorderWidth.isSome()) {\n return optBorderWidth.getOr('');\n }\n return dom.getAttrib(elm, 'border') || getTDTHOverallStyle(editor.dom, elm, 'border-width') || getTDTHOverallStyle(editor.dom, elm, 'border') || '';\n };\n const dom = editor.dom;\n const cellspacing = shouldStyleWithCss(editor) ? dom.getStyle(elm, 'border-spacing') || dom.getAttrib(elm, 'cellspacing') : dom.getAttrib(elm, 'cellspacing') || dom.getStyle(elm, 'border-spacing');\n const cellpadding = shouldStyleWithCss(editor) ? getTDTHOverallStyle(dom, elm, 'padding') || dom.getAttrib(elm, 'cellpadding') : dom.getAttrib(elm, 'cellpadding') || getTDTHOverallStyle(dom, elm, 'padding');\n return {\n width: dom.getStyle(elm, 'width') || dom.getAttrib(elm, 'width'),\n height: dom.getStyle(elm, 'height') || dom.getAttrib(elm, 'height'),\n cellspacing: cellspacing !== null && cellspacing !== void 0 ? cellspacing : '',\n cellpadding: cellpadding !== null && cellpadding !== void 0 ? cellpadding : '',\n border: getBorder(dom, elm),\n caption: !!dom.select('caption', elm)[0],\n class: dom.getAttrib(elm, 'class', ''),\n align: getHAlignment(editor, elm),\n ...hasAdvTableTab ? extractAdvancedStyles(elm) : {}\n };\n };\n const extractDataFromRowElement = (editor, elm, hasAdvancedRowTab) => {\n const dom = editor.dom;\n return {\n height: dom.getStyle(elm, 'height') || dom.getAttrib(elm, 'height'),\n class: dom.getAttrib(elm, 'class', ''),\n type: getRowType(elm),\n align: getHAlignment(editor, elm),\n ...hasAdvancedRowTab ? extractAdvancedStyles(elm) : {}\n };\n };\n const extractDataFromCellElement = (editor, cell, hasAdvancedCellTab, column) => {\n const dom = editor.dom;\n const colElm = column.getOr(cell);\n const getStyle = (element, style) => dom.getStyle(element, style) || dom.getAttrib(element, style);\n return {\n width: getStyle(colElm, 'width'),\n scope: dom.getAttrib(cell, 'scope'),\n celltype: getNodeName(cell),\n class: dom.getAttrib(cell, 'class', ''),\n halign: getHAlignment(editor, cell),\n valign: getVAlignment(editor, cell),\n ...hasAdvancedCellTab ? extractAdvancedStyles(cell) : {}\n };\n };\n\n const getSelectedCells = (table, cells) => {\n const warehouse = Warehouse.fromTable(table);\n const allCells = Warehouse.justCells(warehouse);\n const filtered = filter(allCells, cellA => exists(cells, cellB => eq(cellA.element, cellB)));\n return map(filtered, cell => ({\n element: cell.element.dom,\n column: Warehouse.getColumnAt(warehouse, cell.column).map(col => col.element.dom)\n }));\n };\n const updateSimpleProps$1 = (modifier, colModifier, data, shouldUpdate) => {\n if (shouldUpdate('scope')) {\n modifier.setAttrib('scope', data.scope);\n }\n if (shouldUpdate('class') && data.class !== 'mce-no-match') {\n modifier.setAttrib('class', data.class);\n }\n if (shouldUpdate('width')) {\n colModifier.setStyle('width', addPxSuffix(data.width));\n }\n };\n const updateAdvancedProps$1 = (modifier, data, shouldUpdate) => {\n if (shouldUpdate('backgroundcolor')) {\n modifier.setFormat('tablecellbackgroundcolor', data.backgroundcolor);\n }\n if (shouldUpdate('bordercolor')) {\n modifier.setFormat('tablecellbordercolor', data.bordercolor);\n }\n if (shouldUpdate('borderstyle')) {\n modifier.setFormat('tablecellborderstyle', data.borderstyle);\n }\n if (shouldUpdate('borderwidth')) {\n modifier.setFormat('tablecellborderwidth', addPxSuffix(data.borderwidth));\n }\n };\n const applyStyleData$1 = (editor, cells, data, wasChanged) => {\n const isSingleCell = cells.length === 1;\n each(cells, item => {\n const cellElm = item.element;\n const shouldOverrideCurrentValue = isSingleCell ? always : wasChanged;\n const modifier = DomModifier.normal(editor, cellElm);\n const colModifier = item.column.map(col => DomModifier.normal(editor, col)).getOr(modifier);\n updateSimpleProps$1(modifier, colModifier, data, shouldOverrideCurrentValue);\n if (hasAdvancedCellTab(editor)) {\n updateAdvancedProps$1(modifier, data, shouldOverrideCurrentValue);\n }\n if (wasChanged('halign')) {\n setAlign(editor, cellElm, data.halign);\n }\n if (wasChanged('valign')) {\n setVAlign(editor, cellElm, data.valign);\n }\n });\n };\n const applyStructureData$1 = (editor, data) => {\n editor.execCommand('mceTableCellType', false, {\n type: data.celltype,\n no_events: true\n });\n };\n const applyCellData = (editor, cells, oldData, data) => {\n const modifiedData = filter$1(data, (value, key) => oldData[key] !== value);\n if (size(modifiedData) > 0 && cells.length >= 1) {\n table(cells[0]).each(table => {\n const selectedCells = getSelectedCells(table, cells);\n const styleModified = size(filter$1(modifiedData, (_value, key) => key !== 'scope' && key !== 'celltype')) > 0;\n const structureModified = has(modifiedData, 'celltype');\n if (styleModified || has(modifiedData, 'scope')) {\n applyStyleData$1(editor, selectedCells, data, curry(has, modifiedData));\n }\n if (structureModified) {\n applyStructureData$1(editor, data);\n }\n fireTableModified(editor, table.dom, {\n structure: structureModified,\n style: styleModified\n });\n });\n }\n };\n const onSubmitCellForm = (editor, cells, oldData, api) => {\n const data = api.getData();\n api.close();\n editor.undoManager.transact(() => {\n applyCellData(editor, cells, oldData, data);\n editor.focus();\n });\n };\n const getData$1 = (editor, cells) => {\n const cellsData = table(cells[0]).map(table => map(getSelectedCells(table, cells), item => extractDataFromCellElement(editor, item.element, hasAdvancedCellTab(editor), item.column)));\n return getSharedValues(cellsData.getOrDie());\n };\n const open$2 = editor => {\n const cells = getCellsFromSelection(editor);\n if (cells.length === 0) {\n return;\n }\n const data = getData$1(editor, cells);\n const dialogTabPanel = {\n type: 'tabpanel',\n tabs: [\n {\n title: 'General',\n name: 'general',\n items: getItems$2(editor)\n },\n getAdvancedTab(editor, 'cell')\n ]\n };\n const dialogPanel = {\n type: 'panel',\n items: [{\n type: 'grid',\n columns: 2,\n items: getItems$2(editor)\n }]\n };\n editor.windowManager.open({\n title: 'Cell Properties',\n size: 'normal',\n body: hasAdvancedCellTab(editor) ? dialogTabPanel : dialogPanel,\n buttons: [\n {\n type: 'cancel',\n name: 'cancel',\n text: 'Cancel'\n },\n {\n type: 'submit',\n name: 'save',\n text: 'Save',\n primary: true\n }\n ],\n initialData: data,\n onSubmit: curry(onSubmitCellForm, editor, cells, data)\n });\n };\n\n const getClassList = editor => buildClassList(getRowClassList(editor)).map(items => ({\n name: 'class',\n type: 'listbox',\n label: 'Class',\n items\n }));\n const formChildren = [\n {\n type: 'listbox',\n name: 'type',\n label: 'Row type',\n items: [\n {\n text: 'Header',\n value: 'header'\n },\n {\n text: 'Body',\n value: 'body'\n },\n {\n text: 'Footer',\n value: 'footer'\n }\n ]\n },\n {\n type: 'listbox',\n name: 'align',\n label: 'Alignment',\n items: [\n {\n text: 'None',\n value: ''\n },\n {\n text: 'Left',\n value: 'left'\n },\n {\n text: 'Center',\n value: 'center'\n },\n {\n text: 'Right',\n value: 'right'\n }\n ]\n },\n {\n label: 'Height',\n name: 'height',\n type: 'input'\n }\n ];\n const getItems$1 = editor => formChildren.concat(getClassList(editor).toArray());\n\n const updateSimpleProps = (modifier, data, shouldUpdate) => {\n if (shouldUpdate('class') && data.class !== 'mce-no-match') {\n modifier.setAttrib('class', data.class);\n }\n if (shouldUpdate('height')) {\n modifier.setStyle('height', addPxSuffix(data.height));\n }\n };\n const updateAdvancedProps = (modifier, data, shouldUpdate) => {\n if (shouldUpdate('backgroundcolor')) {\n modifier.setStyle('background-color', data.backgroundcolor);\n }\n if (shouldUpdate('bordercolor')) {\n modifier.setStyle('border-color', data.bordercolor);\n }\n if (shouldUpdate('borderstyle')) {\n modifier.setStyle('border-style', data.borderstyle);\n }\n };\n const applyStyleData = (editor, rows, data, wasChanged) => {\n const isSingleRow = rows.length === 1;\n const shouldOverrideCurrentValue = isSingleRow ? always : wasChanged;\n each(rows, rowElm => {\n const rowCells = children$1(SugarElement.fromDom(rowElm), 'td,th');\n const modifier = DomModifier.normal(editor, rowElm);\n updateSimpleProps(modifier, data, shouldOverrideCurrentValue);\n if (hasAdvancedRowTab(editor)) {\n updateAdvancedProps(modifier, data, shouldOverrideCurrentValue);\n }\n if (wasChanged('height')) {\n each(rowCells, cell => {\n editor.dom.setStyle(cell.dom, 'height', null);\n });\n }\n if (wasChanged('align')) {\n setAlign(editor, rowElm, data.align);\n }\n });\n };\n const applyStructureData = (editor, data) => {\n editor.execCommand('mceTableRowType', false, {\n type: data.type,\n no_events: true\n });\n };\n const applyRowData = (editor, rows, oldData, data) => {\n const modifiedData = filter$1(data, (value, key) => oldData[key] !== value);\n if (size(modifiedData) > 0) {\n const typeModified = has(modifiedData, 'type');\n const styleModified = typeModified ? size(modifiedData) > 1 : true;\n if (styleModified) {\n applyStyleData(editor, rows, data, curry(has, modifiedData));\n }\n if (typeModified) {\n applyStructureData(editor, data);\n }\n table(SugarElement.fromDom(rows[0])).each(table => fireTableModified(editor, table.dom, {\n structure: typeModified,\n style: styleModified\n }));\n }\n };\n const onSubmitRowForm = (editor, rows, oldData, api) => {\n const data = api.getData();\n api.close();\n editor.undoManager.transact(() => {\n applyRowData(editor, rows, oldData, data);\n editor.focus();\n });\n };\n const open$1 = editor => {\n const rows = getRowsFromSelection(getSelectionStart(editor), ephemera.selected);\n if (rows.length === 0) {\n return;\n }\n const rowsData = map(rows, rowElm => extractDataFromRowElement(editor, rowElm.dom, hasAdvancedRowTab(editor)));\n const data = getSharedValues(rowsData);\n const dialogTabPanel = {\n type: 'tabpanel',\n tabs: [\n {\n title: 'General',\n name: 'general',\n items: getItems$1(editor)\n },\n getAdvancedTab(editor, 'row')\n ]\n };\n const dialogPanel = {\n type: 'panel',\n items: [{\n type: 'grid',\n columns: 2,\n items: getItems$1(editor)\n }]\n };\n editor.windowManager.open({\n title: 'Row Properties',\n size: 'normal',\n body: hasAdvancedRowTab(editor) ? dialogTabPanel : dialogPanel,\n buttons: [\n {\n type: 'cancel',\n name: 'cancel',\n text: 'Cancel'\n },\n {\n type: 'submit',\n name: 'save',\n text: 'Save',\n primary: true\n }\n ],\n initialData: data,\n onSubmit: curry(onSubmitRowForm, editor, map(rows, r => r.dom), data)\n });\n };\n\n const getItems = (editor, classes, insertNewTable) => {\n const rowColCountItems = !insertNewTable ? [] : [\n {\n type: 'input',\n name: 'cols',\n label: 'Cols',\n inputMode: 'numeric'\n },\n {\n type: 'input',\n name: 'rows',\n label: 'Rows',\n inputMode: 'numeric'\n }\n ];\n const alwaysItems = [\n {\n type: 'input',\n name: 'width',\n label: 'Width'\n },\n {\n type: 'input',\n name: 'height',\n label: 'Height'\n }\n ];\n const appearanceItems = hasAppearanceOptions(editor) ? [\n {\n type: 'input',\n name: 'cellspacing',\n label: 'Cell spacing',\n inputMode: 'numeric'\n },\n {\n type: 'input',\n name: 'cellpadding',\n label: 'Cell padding',\n inputMode: 'numeric'\n },\n {\n type: 'input',\n name: 'border',\n label: 'Border width'\n },\n {\n type: 'label',\n label: 'Caption',\n items: [{\n type: 'checkbox',\n name: 'caption',\n label: 'Show caption'\n }]\n }\n ] : [];\n const alignmentItem = [{\n type: 'listbox',\n name: 'align',\n label: 'Alignment',\n items: [\n {\n text: 'None',\n value: ''\n },\n {\n text: 'Left',\n value: 'left'\n },\n {\n text: 'Center',\n value: 'center'\n },\n {\n text: 'Right',\n value: 'right'\n }\n ]\n }];\n const classListItem = classes.length > 0 ? [{\n name: 'class',\n type: 'listbox',\n label: 'Class',\n items: classes\n }] : [];\n return rowColCountItems.concat(alwaysItems).concat(appearanceItems).concat(alignmentItem).concat(classListItem);\n };\n\n const styleTDTH = (dom, elm, name, value) => {\n if (elm.tagName === 'TD' || elm.tagName === 'TH') {\n if (isString(name) && isNonNullable(value)) {\n dom.setStyle(elm, name, value);\n } else {\n dom.setStyles(elm, name);\n }\n } else {\n if (elm.children) {\n for (let i = 0; i < elm.children.length; i++) {\n styleTDTH(dom, elm.children[i], name, value);\n }\n }\n }\n };\n const applyDataToElement = (editor, tableElm, data, shouldApplyOnCell) => {\n const dom = editor.dom;\n const attrs = {};\n const styles = {};\n const shouldStyleWithCss$1 = shouldStyleWithCss(editor);\n const hasAdvancedTableTab$1 = hasAdvancedTableTab(editor);\n const borderIsZero = parseFloat(data.border) === 0;\n if (!isUndefined(data.class) && data.class !== 'mce-no-match') {\n attrs.class = data.class;\n }\n styles.height = addPxSuffix(data.height);\n if (shouldStyleWithCss$1) {\n styles.width = addPxSuffix(data.width);\n } else if (dom.getAttrib(tableElm, 'width')) {\n attrs.width = removePxSuffix(data.width);\n }\n if (shouldStyleWithCss$1) {\n if (borderIsZero) {\n attrs.border = 0;\n styles['border-width'] = '';\n } else {\n styles['border-width'] = addPxSuffix(data.border);\n attrs.border = 1;\n }\n styles['border-spacing'] = addPxSuffix(data.cellspacing);\n } else {\n attrs.border = borderIsZero ? 0 : data.border;\n attrs.cellpadding = data.cellpadding;\n attrs.cellspacing = data.cellspacing;\n }\n if (shouldStyleWithCss$1 && tableElm.children) {\n const cellStyles = {};\n if (borderIsZero) {\n cellStyles['border-width'] = '';\n } else if (shouldApplyOnCell.border) {\n cellStyles['border-width'] = addPxSuffix(data.border);\n }\n if (shouldApplyOnCell.cellpadding) {\n cellStyles.padding = addPxSuffix(data.cellpadding);\n }\n if (hasAdvancedTableTab$1 && shouldApplyOnCell.bordercolor) {\n cellStyles['border-color'] = data.bordercolor;\n }\n if (!isEmpty$1(cellStyles)) {\n for (let i = 0; i < tableElm.children.length; i++) {\n styleTDTH(dom, tableElm.children[i], cellStyles);\n }\n }\n }\n if (hasAdvancedTableTab$1) {\n const advData = data;\n styles['background-color'] = advData.backgroundcolor;\n styles['border-color'] = advData.bordercolor;\n styles['border-style'] = advData.borderstyle;\n }\n dom.setStyles(tableElm, {\n ...getDefaultStyles(editor),\n ...styles\n });\n dom.setAttribs(tableElm, {\n ...getDefaultAttributes(editor),\n ...attrs\n });\n };\n const onSubmitTableForm = (editor, tableElm, oldData, api) => {\n const dom = editor.dom;\n const data = api.getData();\n const modifiedData = filter$1(data, (value, key) => oldData[key] !== value);\n api.close();\n editor.undoManager.transact(() => {\n if (!tableElm) {\n const cols = toInt(data.cols).getOr(1);\n const rows = toInt(data.rows).getOr(1);\n editor.execCommand('mceInsertTable', false, {\n rows,\n columns: cols\n });\n tableElm = getSelectionCell(getSelectionStart(editor), getIsRoot(editor)).bind(cell => table(cell, getIsRoot(editor))).map(table => table.dom).getOrDie();\n }\n if (size(modifiedData) > 0) {\n const applicableCellProperties = {\n border: has(modifiedData, 'border'),\n bordercolor: has(modifiedData, 'bordercolor'),\n cellpadding: has(modifiedData, 'cellpadding')\n };\n applyDataToElement(editor, tableElm, data, applicableCellProperties);\n const captionElm = dom.select('caption', tableElm)[0];\n if (captionElm && !data.caption || !captionElm && data.caption) {\n editor.execCommand('mceTableToggleCaption');\n }\n setAlign(editor, tableElm, data.align);\n }\n editor.focus();\n editor.addVisual();\n if (size(modifiedData) > 0) {\n const captionModified = has(modifiedData, 'caption');\n const styleModified = captionModified ? size(modifiedData) > 1 : true;\n fireTableModified(editor, tableElm, {\n structure: captionModified,\n style: styleModified\n });\n }\n });\n };\n const open = (editor, insertNewTable) => {\n const dom = editor.dom;\n let tableElm;\n let data = extractDataFromSettings(editor, hasAdvancedTableTab(editor));\n if (insertNewTable) {\n data.cols = '1';\n data.rows = '1';\n if (hasAdvancedTableTab(editor)) {\n data.borderstyle = '';\n data.bordercolor = '';\n data.backgroundcolor = '';\n }\n } else {\n tableElm = dom.getParent(editor.selection.getStart(), 'table', editor.getBody());\n if (tableElm) {\n data = extractDataFromTableElement(editor, tableElm, hasAdvancedTableTab(editor));\n } else {\n if (hasAdvancedTableTab(editor)) {\n data.borderstyle = '';\n data.bordercolor = '';\n data.backgroundcolor = '';\n }\n }\n }\n const classes = buildClassList(getTableClassList(editor));\n if (classes.isSome()) {\n if (data.class) {\n data.class = data.class.replace(/\\s*mce\\-item\\-table\\s*/g, '');\n }\n }\n const generalPanel = {\n type: 'grid',\n columns: 2,\n items: getItems(editor, classes.getOr([]), insertNewTable)\n };\n const nonAdvancedForm = () => ({\n type: 'panel',\n items: [generalPanel]\n });\n const advancedForm = () => ({\n type: 'tabpanel',\n tabs: [\n {\n title: 'General',\n name: 'general',\n items: [generalPanel]\n },\n getAdvancedTab(editor, 'table')\n ]\n });\n const dialogBody = hasAdvancedTableTab(editor) ? advancedForm() : nonAdvancedForm();\n editor.windowManager.open({\n title: 'Table Properties',\n size: 'normal',\n body: dialogBody,\n onSubmit: curry(onSubmitTableForm, editor, tableElm, data),\n buttons: [\n {\n type: 'cancel',\n name: 'cancel',\n text: 'Cancel'\n },\n {\n type: 'submit',\n name: 'save',\n text: 'Save',\n primary: true\n }\n ],\n initialData: data\n });\n };\n\n const registerCommands = editor => {\n const runAction = f => {\n if (isInEditableContext(getSelectionStart(editor))) {\n f();\n }\n };\n each$1({\n mceTableProps: curry(open, editor, false),\n mceTableRowProps: curry(open$1, editor),\n mceTableCellProps: curry(open$2, editor),\n mceInsertTableDialog: curry(open, editor, true)\n }, (func, name) => editor.addCommand(name, () => runAction(func)));\n };\n\n const child = (scope, selector) => child$1(scope, selector).isSome();\n\n const selection = identity;\n const unmergable = selectedCells => {\n const hasSpan = (elem, type) => getOpt(elem, type).exists(span => parseInt(span, 10) > 1);\n const hasRowOrColSpan = elem => hasSpan(elem, 'rowspan') || hasSpan(elem, 'colspan');\n return selectedCells.length > 0 && forall(selectedCells, hasRowOrColSpan) ? Optional.some(selectedCells) : Optional.none();\n };\n const mergable = (table, selectedCells, ephemera) => {\n if (selectedCells.length <= 1) {\n return Optional.none();\n } else {\n return retrieveBox(table, ephemera.firstSelectedSelector, ephemera.lastSelectedSelector).map(bounds => ({\n bounds,\n cells: selectedCells\n }));\n }\n };\n\n const noMenu = cell => ({\n element: cell,\n mergable: Optional.none(),\n unmergable: Optional.none(),\n selection: [cell]\n });\n const forMenu = (selectedCells, table, cell) => ({\n element: cell,\n mergable: mergable(table, selectedCells, ephemera),\n unmergable: unmergable(selectedCells),\n selection: selection(selectedCells)\n });\n\n const getSelectionTargets = editor => {\n const targets = Cell(Optional.none());\n const changeHandlers = Cell([]);\n let selectionDetails = Optional.none();\n const isCaption = isTag('caption');\n const isDisabledForSelection = key => selectionDetails.forall(details => !details[key]);\n const getStart = () => getSelectionCellOrCaption(getSelectionStart(editor), getIsRoot(editor));\n const getEnd = () => getSelectionCellOrCaption(getSelectionEnd(editor), getIsRoot(editor));\n const findTargets = () => getStart().bind(startCellOrCaption => flatten(lift2(table(startCellOrCaption), getEnd().bind(table), (startTable, endTable) => {\n if (eq(startTable, endTable)) {\n if (isCaption(startCellOrCaption)) {\n return Optional.some(noMenu(startCellOrCaption));\n } else {\n return Optional.some(forMenu(getCellsFromSelection(editor), startTable, startCellOrCaption));\n }\n }\n return Optional.none();\n })));\n const getExtractedDetails = targets => {\n const tableOpt = table(targets.element);\n return tableOpt.map(table => {\n const warehouse = Warehouse.fromTable(table);\n const selectedCells = onCells(warehouse, targets).getOr([]);\n const locked = foldl(selectedCells, (acc, cell) => {\n if (cell.isLocked) {\n acc.onAny = true;\n if (cell.column === 0) {\n acc.onFirst = true;\n } else if (cell.column + cell.colspan >= warehouse.grid.columns) {\n acc.onLast = true;\n }\n }\n return acc;\n }, {\n onAny: false,\n onFirst: false,\n onLast: false\n });\n return {\n mergeable: onUnlockedMergable(warehouse, targets).isSome(),\n unmergeable: onUnlockedUnmergable(warehouse, targets).isSome(),\n locked\n };\n });\n };\n const resetTargets = () => {\n targets.set(cached(findTargets)());\n selectionDetails = targets.get().bind(getExtractedDetails);\n each(changeHandlers.get(), call);\n };\n const setupHandler = handler => {\n handler();\n changeHandlers.set(changeHandlers.get().concat([handler]));\n return () => {\n changeHandlers.set(filter(changeHandlers.get(), h => h !== handler));\n };\n };\n const onSetup = (api, isDisabled) => setupHandler(() => targets.get().fold(() => {\n api.setEnabled(false);\n }, targets => {\n api.setEnabled(!isDisabled(targets) && editor.selection.isEditable());\n }));\n const onSetupWithToggle = (api, isDisabled, isActive) => setupHandler(() => targets.get().fold(() => {\n api.setEnabled(false);\n api.setActive(false);\n }, targets => {\n api.setEnabled(!isDisabled(targets) && editor.selection.isEditable());\n api.setActive(isActive(targets));\n }));\n const isDisabledFromLocked = lockedDisable => selectionDetails.exists(details => details.locked[lockedDisable]);\n const onSetupTable = api => onSetup(api, _ => false);\n const onSetupCellOrRow = api => onSetup(api, targets => isCaption(targets.element));\n const onSetupColumn = lockedDisable => api => onSetup(api, targets => isCaption(targets.element) || isDisabledFromLocked(lockedDisable));\n const onSetupPasteable = getClipboardData => api => onSetup(api, targets => isCaption(targets.element) || getClipboardData().isNone());\n const onSetupPasteableColumn = (getClipboardData, lockedDisable) => api => onSetup(api, targets => isCaption(targets.element) || getClipboardData().isNone() || isDisabledFromLocked(lockedDisable));\n const onSetupMergeable = api => onSetup(api, _targets => isDisabledForSelection('mergeable'));\n const onSetupUnmergeable = api => onSetup(api, _targets => isDisabledForSelection('unmergeable'));\n const onSetupTableWithCaption = api => {\n return onSetupWithToggle(api, never, targets => {\n const tableOpt = table(targets.element, getIsRoot(editor));\n return tableOpt.exists(table => child(table, 'caption'));\n });\n };\n const onSetupTableHeaders = (command, headerType) => api => {\n return onSetupWithToggle(api, targets => isCaption(targets.element), () => editor.queryCommandValue(command) === headerType);\n };\n const onSetupTableRowHeaders = onSetupTableHeaders('mceTableRowType', 'header');\n const onSetupTableColumnHeaders = onSetupTableHeaders('mceTableColType', 'th');\n editor.on('NodeChange ExecCommand TableSelectorChange', resetTargets);\n return {\n onSetupTable,\n onSetupCellOrRow,\n onSetupColumn,\n onSetupPasteable,\n onSetupPasteableColumn,\n onSetupMergeable,\n onSetupUnmergeable,\n resetTargets,\n onSetupTableWithCaption,\n onSetupTableRowHeaders,\n onSetupTableColumnHeaders,\n targets: targets.get\n };\n };\n\n var global = tinymce.util.Tools.resolve('tinymce.FakeClipboard');\n\n const tableTypeBase = 'x-tinymce/dom-table-';\n const tableTypeRow = tableTypeBase + 'rows';\n const tableTypeColumn = tableTypeBase + 'columns';\n const getData = type => {\n var _a;\n const items = (_a = global.read()) !== null && _a !== void 0 ? _a : [];\n return findMap(items, item => Optional.from(item.getType(type)));\n };\n const getRows = () => getData(tableTypeRow);\n const getColumns = () => getData(tableTypeColumn);\n\n const onSetupEditable$1 = editor => api => {\n const nodeChanged = () => {\n api.setEnabled(editor.selection.isEditable());\n };\n editor.on('NodeChange', nodeChanged);\n nodeChanged();\n return () => {\n editor.off('NodeChange', nodeChanged);\n };\n };\n const addButtons = (editor, selectionTargets) => {\n editor.ui.registry.addMenuButton('table', {\n tooltip: 'Table',\n icon: 'table',\n onSetup: onSetupEditable$1(editor),\n fetch: callback => callback('inserttable | cell row column | advtablesort | tableprops deletetable')\n });\n const cmd = command => () => editor.execCommand(command);\n const addButtonIfRegistered = (name, spec) => {\n if (editor.queryCommandSupported(spec.command)) {\n editor.ui.registry.addButton(name, {\n ...spec,\n onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)\n });\n }\n };\n const addToggleButtonIfRegistered = (name, spec) => {\n if (editor.queryCommandSupported(spec.command)) {\n editor.ui.registry.addToggleButton(name, {\n ...spec,\n onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)\n });\n }\n };\n addButtonIfRegistered('tableprops', {\n tooltip: 'Table properties',\n command: 'mceTableProps',\n icon: 'table',\n onSetup: selectionTargets.onSetupTable\n });\n addButtonIfRegistered('tabledelete', {\n tooltip: 'Delete table',\n command: 'mceTableDelete',\n icon: 'table-delete-table',\n onSetup: selectionTargets.onSetupTable\n });\n addButtonIfRegistered('tablecellprops', {\n tooltip: 'Cell properties',\n command: 'mceTableCellProps',\n icon: 'table-cell-properties',\n onSetup: selectionTargets.onSetupCellOrRow\n });\n addButtonIfRegistered('tablemergecells', {\n tooltip: 'Merge cells',\n command: 'mceTableMergeCells',\n icon: 'table-merge-cells',\n onSetup: selectionTargets.onSetupMergeable\n });\n addButtonIfRegistered('tablesplitcells', {\n tooltip: 'Split cell',\n command: 'mceTableSplitCells',\n icon: 'table-split-cells',\n onSetup: selectionTargets.onSetupUnmergeable\n });\n addButtonIfRegistered('tableinsertrowbefore', {\n tooltip: 'Insert row before',\n command: 'mceTableInsertRowBefore',\n icon: 'table-insert-row-above',\n onSetup: selectionTargets.onSetupCellOrRow\n });\n addButtonIfRegistered('tableinsertrowafter', {\n tooltip: 'Insert row after',\n command: 'mceTableInsertRowAfter',\n icon: 'table-insert-row-after',\n onSetup: selectionTargets.onSetupCellOrRow\n });\n addButtonIfRegistered('tabledeleterow', {\n tooltip: 'Delete row',\n command: 'mceTableDeleteRow',\n icon: 'table-delete-row',\n onSetup: selectionTargets.onSetupCellOrRow\n });\n addButtonIfRegistered('tablerowprops', {\n tooltip: 'Row properties',\n command: 'mceTableRowProps',\n icon: 'table-row-properties',\n onSetup: selectionTargets.onSetupCellOrRow\n });\n addButtonIfRegistered('tableinsertcolbefore', {\n tooltip: 'Insert column before',\n command: 'mceTableInsertColBefore',\n icon: 'table-insert-column-before',\n onSetup: selectionTargets.onSetupColumn('onFirst')\n });\n addButtonIfRegistered('tableinsertcolafter', {\n tooltip: 'Insert column after',\n command: 'mceTableInsertColAfter',\n icon: 'table-insert-column-after',\n onSetup: selectionTargets.onSetupColumn('onLast')\n });\n addButtonIfRegistered('tabledeletecol', {\n tooltip: 'Delete column',\n command: 'mceTableDeleteCol',\n icon: 'table-delete-column',\n onSetup: selectionTargets.onSetupColumn('onAny')\n });\n addButtonIfRegistered('tablecutrow', {\n tooltip: 'Cut row',\n command: 'mceTableCutRow',\n icon: 'cut-row',\n onSetup: selectionTargets.onSetupCellOrRow\n });\n addButtonIfRegistered('tablecopyrow', {\n tooltip: 'Copy row',\n command: 'mceTableCopyRow',\n icon: 'duplicate-row',\n onSetup: selectionTargets.onSetupCellOrRow\n });\n addButtonIfRegistered('tablepasterowbefore', {\n tooltip: 'Paste row before',\n command: 'mceTablePasteRowBefore',\n icon: 'paste-row-before',\n onSetup: selectionTargets.onSetupPasteable(getRows)\n });\n addButtonIfRegistered('tablepasterowafter', {\n tooltip: 'Paste row after',\n command: 'mceTablePasteRowAfter',\n icon: 'paste-row-after',\n onSetup: selectionTargets.onSetupPasteable(getRows)\n });\n addButtonIfRegistered('tablecutcol', {\n tooltip: 'Cut column',\n command: 'mceTableCutCol',\n icon: 'cut-column',\n onSetup: selectionTargets.onSetupColumn('onAny')\n });\n addButtonIfRegistered('tablecopycol', {\n tooltip: 'Copy column',\n command: 'mceTableCopyCol',\n icon: 'duplicate-column',\n onSetup: selectionTargets.onSetupColumn('onAny')\n });\n addButtonIfRegistered('tablepastecolbefore', {\n tooltip: 'Paste column before',\n command: 'mceTablePasteColBefore',\n icon: 'paste-column-before',\n onSetup: selectionTargets.onSetupPasteableColumn(getColumns, 'onFirst')\n });\n addButtonIfRegistered('tablepastecolafter', {\n tooltip: 'Paste column after',\n command: 'mceTablePasteColAfter',\n icon: 'paste-column-after',\n onSetup: selectionTargets.onSetupPasteableColumn(getColumns, 'onLast')\n });\n addButtonIfRegistered('tableinsertdialog', {\n tooltip: 'Insert table',\n command: 'mceInsertTableDialog',\n icon: 'table',\n onSetup: onSetupEditable$1(editor)\n });\n const tableClassList = filterNoneItem(getTableClassList(editor));\n if (tableClassList.length !== 0 && editor.queryCommandSupported('mceTableToggleClass')) {\n editor.ui.registry.addMenuButton('tableclass', {\n icon: 'table-classes',\n tooltip: 'Table styles',\n fetch: generateMenuItemsCallback(editor, tableClassList, 'tableclass', value => editor.execCommand('mceTableToggleClass', false, value)),\n onSetup: selectionTargets.onSetupTable\n });\n }\n const tableCellClassList = filterNoneItem(getCellClassList(editor));\n if (tableCellClassList.length !== 0 && editor.queryCommandSupported('mceTableCellToggleClass')) {\n editor.ui.registry.addMenuButton('tablecellclass', {\n icon: 'table-cell-classes',\n tooltip: 'Cell styles',\n fetch: generateMenuItemsCallback(editor, tableCellClassList, 'tablecellclass', value => editor.execCommand('mceTableCellToggleClass', false, value)),\n onSetup: selectionTargets.onSetupCellOrRow\n });\n }\n if (editor.queryCommandSupported('mceTableApplyCellStyle')) {\n editor.ui.registry.addMenuButton('tablecellvalign', {\n icon: 'vertical-align',\n tooltip: 'Vertical align',\n fetch: generateMenuItemsCallback(editor, verticalAlignValues, 'tablecellverticalalign', applyTableCellStyle(editor, 'vertical-align')),\n onSetup: selectionTargets.onSetupCellOrRow\n });\n editor.ui.registry.addMenuButton('tablecellborderwidth', {\n icon: 'border-width',\n tooltip: 'Border width',\n fetch: generateMenuItemsCallback(editor, getTableBorderWidths(editor), 'tablecellborderwidth', applyTableCellStyle(editor, 'border-width')),\n onSetup: selectionTargets.onSetupCellOrRow\n });\n editor.ui.registry.addMenuButton('tablecellborderstyle', {\n icon: 'border-style',\n tooltip: 'Border style',\n fetch: generateMenuItemsCallback(editor, getTableBorderStyles(editor), 'tablecellborderstyle', applyTableCellStyle(editor, 'border-style')),\n onSetup: selectionTargets.onSetupCellOrRow\n });\n editor.ui.registry.addMenuButton('tablecellbackgroundcolor', {\n icon: 'cell-background-color',\n tooltip: 'Background color',\n fetch: callback => callback(buildColorMenu(editor, getTableBackgroundColorMap(editor), 'background-color')),\n onSetup: selectionTargets.onSetupCellOrRow\n });\n editor.ui.registry.addMenuButton('tablecellbordercolor', {\n icon: 'cell-border-color',\n tooltip: 'Border color',\n fetch: callback => callback(buildColorMenu(editor, getTableBorderColorMap(editor), 'border-color')),\n onSetup: selectionTargets.onSetupCellOrRow\n });\n }\n addToggleButtonIfRegistered('tablecaption', {\n tooltip: 'Table caption',\n icon: 'table-caption',\n command: 'mceTableToggleCaption',\n onSetup: selectionTargets.onSetupTableWithCaption\n });\n addToggleButtonIfRegistered('tablerowheader', {\n tooltip: 'Row header',\n icon: 'table-top-header',\n command: 'mceTableRowType',\n onAction: changeRowHeader(editor),\n onSetup: selectionTargets.onSetupTableRowHeaders\n });\n addToggleButtonIfRegistered('tablecolheader', {\n tooltip: 'Column header',\n icon: 'table-left-header',\n command: 'mceTableColType',\n onAction: changeColumnHeader(editor),\n onSetup: selectionTargets.onSetupTableColumnHeaders\n });\n };\n const addToolbars = editor => {\n const isEditableTable = table => editor.dom.is(table, 'table') && editor.getBody().contains(table) && editor.dom.isEditable(table.parentNode);\n const toolbar = getToolbar(editor);\n if (toolbar.length > 0) {\n editor.ui.registry.addContextToolbar('table', {\n predicate: isEditableTable,\n items: toolbar,\n scope: 'node',\n position: 'node'\n });\n }\n };\n\n const onSetupEditable = editor => api => {\n const nodeChanged = () => {\n api.setEnabled(editor.selection.isEditable());\n };\n editor.on('NodeChange', nodeChanged);\n nodeChanged();\n return () => {\n editor.off('NodeChange', nodeChanged);\n };\n };\n const addMenuItems = (editor, selectionTargets) => {\n const cmd = command => () => editor.execCommand(command);\n const addMenuIfRegistered = (name, spec) => {\n if (editor.queryCommandSupported(spec.command)) {\n editor.ui.registry.addMenuItem(name, {\n ...spec,\n onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)\n });\n return true;\n } else {\n return false;\n }\n };\n const addToggleMenuIfRegistered = (name, spec) => {\n if (editor.queryCommandSupported(spec.command)) {\n editor.ui.registry.addToggleMenuItem(name, {\n ...spec,\n onAction: isFunction(spec.onAction) ? spec.onAction : cmd(spec.command)\n });\n }\n };\n const insertTableAction = data => {\n editor.execCommand('mceInsertTable', false, {\n rows: data.numRows,\n columns: data.numColumns\n });\n };\n const hasRowMenuItems = [\n addMenuIfRegistered('tableinsertrowbefore', {\n text: 'Insert row before',\n icon: 'table-insert-row-above',\n command: 'mceTableInsertRowBefore',\n onSetup: selectionTargets.onSetupCellOrRow\n }),\n addMenuIfRegistered('tableinsertrowafter', {\n text: 'Insert row after',\n icon: 'table-insert-row-after',\n command: 'mceTableInsertRowAfter',\n onSetup: selectionTargets.onSetupCellOrRow\n }),\n addMenuIfRegistered('tabledeleterow', {\n text: 'Delete row',\n icon: 'table-delete-row',\n command: 'mceTableDeleteRow',\n onSetup: selectionTargets.onSetupCellOrRow\n }),\n addMenuIfRegistered('tablerowprops', {\n text: 'Row properties',\n icon: 'table-row-properties',\n command: 'mceTableRowProps',\n onSetup: selectionTargets.onSetupCellOrRow\n }),\n addMenuIfRegistered('tablecutrow', {\n text: 'Cut row',\n icon: 'cut-row',\n command: 'mceTableCutRow',\n onSetup: selectionTargets.onSetupCellOrRow\n }),\n addMenuIfRegistered('tablecopyrow', {\n text: 'Copy row',\n icon: 'duplicate-row',\n command: 'mceTableCopyRow',\n onSetup: selectionTargets.onSetupCellOrRow\n }),\n addMenuIfRegistered('tablepasterowbefore', {\n text: 'Paste row before',\n icon: 'paste-row-before',\n command: 'mceTablePasteRowBefore',\n onSetup: selectionTargets.onSetupPasteable(getRows)\n }),\n addMenuIfRegistered('tablepasterowafter', {\n text: 'Paste row after',\n icon: 'paste-row-after',\n command: 'mceTablePasteRowAfter',\n onSetup: selectionTargets.onSetupPasteable(getRows)\n })\n ];\n const hasColumnMenuItems = [\n addMenuIfRegistered('tableinsertcolumnbefore', {\n text: 'Insert column before',\n icon: 'table-insert-column-before',\n command: 'mceTableInsertColBefore',\n onSetup: selectionTargets.onSetupColumn('onFirst')\n }),\n addMenuIfRegistered('tableinsertcolumnafter', {\n text: 'Insert column after',\n icon: 'table-insert-column-after',\n command: 'mceTableInsertColAfter',\n onSetup: selectionTargets.onSetupColumn('onLast')\n }),\n addMenuIfRegistered('tabledeletecolumn', {\n text: 'Delete column',\n icon: 'table-delete-column',\n command: 'mceTableDeleteCol',\n onSetup: selectionTargets.onSetupColumn('onAny')\n }),\n addMenuIfRegistered('tablecutcolumn', {\n text: 'Cut column',\n icon: 'cut-column',\n command: 'mceTableCutCol',\n onSetup: selectionTargets.onSetupColumn('onAny')\n }),\n addMenuIfRegistered('tablecopycolumn', {\n text: 'Copy column',\n icon: 'duplicate-column',\n command: 'mceTableCopyCol',\n onSetup: selectionTargets.onSetupColumn('onAny')\n }),\n addMenuIfRegistered('tablepastecolumnbefore', {\n text: 'Paste column before',\n icon: 'paste-column-before',\n command: 'mceTablePasteColBefore',\n onSetup: selectionTargets.onSetupPasteableColumn(getColumns, 'onFirst')\n }),\n addMenuIfRegistered('tablepastecolumnafter', {\n text: 'Paste column after',\n icon: 'paste-column-after',\n command: 'mceTablePasteColAfter',\n onSetup: selectionTargets.onSetupPasteableColumn(getColumns, 'onLast')\n })\n ];\n const hasCellMenuItems = [\n addMenuIfRegistered('tablecellprops', {\n text: 'Cell properties',\n icon: 'table-cell-properties',\n command: 'mceTableCellProps',\n onSetup: selectionTargets.onSetupCellOrRow\n }),\n addMenuIfRegistered('tablemergecells', {\n text: 'Merge cells',\n icon: 'table-merge-cells',\n command: 'mceTableMergeCells',\n onSetup: selectionTargets.onSetupMergeable\n }),\n addMenuIfRegistered('tablesplitcells', {\n text: 'Split cell',\n icon: 'table-split-cells',\n command: 'mceTableSplitCells',\n onSetup: selectionTargets.onSetupUnmergeable\n })\n ];\n if (!hasTableGrid(editor)) {\n editor.ui.registry.addMenuItem('inserttable', {\n text: 'Table',\n icon: 'table',\n onAction: cmd('mceInsertTableDialog'),\n onSetup: onSetupEditable(editor)\n });\n } else {\n editor.ui.registry.addNestedMenuItem('inserttable', {\n text: 'Table',\n icon: 'table',\n getSubmenuItems: () => [{\n type: 'fancymenuitem',\n fancytype: 'inserttable',\n onAction: insertTableAction\n }],\n onSetup: onSetupEditable(editor)\n });\n }\n editor.ui.registry.addMenuItem('inserttabledialog', {\n text: 'Insert table',\n icon: 'table',\n onAction: cmd('mceInsertTableDialog'),\n onSetup: onSetupEditable(editor)\n });\n addMenuIfRegistered('tableprops', {\n text: 'Table properties',\n onSetup: selectionTargets.onSetupTable,\n command: 'mceTableProps'\n });\n addMenuIfRegistered('deletetable', {\n text: 'Delete table',\n icon: 'table-delete-table',\n onSetup: selectionTargets.onSetupTable,\n command: 'mceTableDelete'\n });\n if (contains(hasRowMenuItems, true)) {\n editor.ui.registry.addNestedMenuItem('row', {\n type: 'nestedmenuitem',\n text: 'Row',\n getSubmenuItems: constant('tableinsertrowbefore tableinsertrowafter tabledeleterow tablerowprops | tablecutrow tablecopyrow tablepasterowbefore tablepasterowafter')\n });\n }\n if (contains(hasColumnMenuItems, true)) {\n editor.ui.registry.addNestedMenuItem('column', {\n type: 'nestedmenuitem',\n text: 'Column',\n getSubmenuItems: constant('tableinsertcolumnbefore tableinsertcolumnafter tabledeletecolumn | tablecutcolumn tablecopycolumn tablepastecolumnbefore tablepastecolumnafter')\n });\n }\n if (contains(hasCellMenuItems, true)) {\n editor.ui.registry.addNestedMenuItem('cell', {\n type: 'nestedmenuitem',\n text: 'Cell',\n getSubmenuItems: constant('tablecellprops tablemergecells tablesplitcells')\n });\n }\n editor.ui.registry.addContextMenu('table', {\n update: () => {\n selectionTargets.resetTargets();\n return selectionTargets.targets().fold(constant(''), targets => {\n if (name(targets.element) === 'caption') {\n return 'tableprops deletetable';\n } else {\n return 'cell row column | advtablesort | tableprops deletetable';\n }\n });\n }\n });\n const tableClassList = filterNoneItem(getTableClassList(editor));\n if (tableClassList.length !== 0 && editor.queryCommandSupported('mceTableToggleClass')) {\n editor.ui.registry.addNestedMenuItem('tableclass', {\n icon: 'table-classes',\n text: 'Table styles',\n getSubmenuItems: () => buildMenuItems(editor, tableClassList, 'tableclass', value => editor.execCommand('mceTableToggleClass', false, value)),\n onSetup: selectionTargets.onSetupTable\n });\n }\n const tableCellClassList = filterNoneItem(getCellClassList(editor));\n if (tableCellClassList.length !== 0 && editor.queryCommandSupported('mceTableCellToggleClass')) {\n editor.ui.registry.addNestedMenuItem('tablecellclass', {\n icon: 'table-cell-classes',\n text: 'Cell styles',\n getSubmenuItems: () => buildMenuItems(editor, tableCellClassList, 'tablecellclass', value => editor.execCommand('mceTableCellToggleClass', false, value)),\n onSetup: selectionTargets.onSetupCellOrRow\n });\n }\n if (editor.queryCommandSupported('mceTableApplyCellStyle')) {\n editor.ui.registry.addNestedMenuItem('tablecellvalign', {\n icon: 'vertical-align',\n text: 'Vertical align',\n getSubmenuItems: () => buildMenuItems(editor, verticalAlignValues, 'tablecellverticalalign', applyTableCellStyle(editor, 'vertical-align')),\n onSetup: selectionTargets.onSetupCellOrRow\n });\n editor.ui.registry.addNestedMenuItem('tablecellborderwidth', {\n icon: 'border-width',\n text: 'Border width',\n getSubmenuItems: () => buildMenuItems(editor, getTableBorderWidths(editor), 'tablecellborderwidth', applyTableCellStyle(editor, 'border-width')),\n onSetup: selectionTargets.onSetupCellOrRow\n });\n editor.ui.registry.addNestedMenuItem('tablecellborderstyle', {\n icon: 'border-style',\n text: 'Border style',\n getSubmenuItems: () => buildMenuItems(editor, getTableBorderStyles(editor), 'tablecellborderstyle', applyTableCellStyle(editor, 'border-style')),\n onSetup: selectionTargets.onSetupCellOrRow\n });\n editor.ui.registry.addNestedMenuItem('tablecellbackgroundcolor', {\n icon: 'cell-background-color',\n text: 'Background color',\n getSubmenuItems: () => buildColorMenu(editor, getTableBackgroundColorMap(editor), 'background-color'),\n onSetup: selectionTargets.onSetupCellOrRow\n });\n editor.ui.registry.addNestedMenuItem('tablecellbordercolor', {\n icon: 'cell-border-color',\n text: 'Border color',\n getSubmenuItems: () => buildColorMenu(editor, getTableBorderColorMap(editor), 'border-color'),\n onSetup: selectionTargets.onSetupCellOrRow\n });\n }\n addToggleMenuIfRegistered('tablecaption', {\n icon: 'table-caption',\n text: 'Table caption',\n command: 'mceTableToggleCaption',\n onSetup: selectionTargets.onSetupTableWithCaption\n });\n addToggleMenuIfRegistered('tablerowheader', {\n text: 'Row header',\n icon: 'table-top-header',\n command: 'mceTableRowType',\n onAction: changeRowHeader(editor),\n onSetup: selectionTargets.onSetupTableRowHeaders\n });\n addToggleMenuIfRegistered('tablecolheader', {\n text: 'Column header',\n icon: 'table-left-header',\n command: 'mceTableColType',\n onAction: changeColumnHeader(editor),\n onSetup: selectionTargets.onSetupTableRowHeaders\n });\n };\n\n const Plugin = editor => {\n const selectionTargets = getSelectionTargets(editor);\n register(editor);\n registerCommands(editor);\n addMenuItems(editor, selectionTargets);\n addButtons(editor, selectionTargets);\n addToolbars(editor);\n };\n var Plugin$1 = () => {\n global$3.add('table', Plugin);\n };\n\n Plugin$1();\n\n})();\n", "/**\n * TinyMCE version 7.5.0 (2024-11-06)\n */\n\n(function () {\n 'use strict';\n\n var global$2 = tinymce.util.Tools.resolve('tinymce.PluginManager');\n\n const eq = t => a => t === a;\n const isNull = eq(null);\n\n const identity = x => {\n return x;\n };\n\n const map = (xs, f) => {\n const len = xs.length;\n const r = new Array(len);\n for (let i = 0; i < len; i++) {\n const x = xs[i];\n r[i] = f(x, i);\n }\n return r;\n };\n\n const punctuationStr = `[~\\u2116|!-*+-\\\\/:;?@\\\\[-\\`{}\\u00A1\\u00AB\\u00B7\\u00BB\\u00BF;\\u00B7\\u055A-\\u055F\\u0589\\u058A\\u05BE\\u05C0\\u05C3\\u05C6\\u05F3\\u05F4\\u0609\\u060A\\u060C\\u060D\\u061B\\u061E\\u061F\\u066A-\\u066D\\u06D4\\u0700-\\u070D\\u07F7-\\u07F9\\u0830-\\u083E\\u085E\\u0964\\u0965\\u0970\\u0DF4\\u0E4F\\u0E5A\\u0E5B\\u0F04-\\u0F12\\u0F3A-\\u0F3D\\u0F85\\u0FD0-\\u0FD4\\u0FD9\\u0FDA\\u104A-\\u104F\\u10FB\\u1361-\\u1368\\u1400\\u166D\\u166E\\u169B\\u169C\\u16EB-\\u16ED\\u1735\\u1736\\u17D4-\\u17D6\\u17D8-\\u17DA\\u1800-\\u180A\\u1944\\u1945\\u1A1E\\u1A1F\\u1AA0-\\u1AA6\\u1AA8-\\u1AAD\\u1B5A-\\u1B60\\u1BFC-\\u1BFF\\u1C3B-\\u1C3F\\u1C7E\\u1C7F\\u1CD3\\u2010-\\u2027\\u2030-\\u2043\\u2045-\\u2051\\u2053-\\u205E\\u207D\\u207E\\u208D\\u208E\\u3008\\u3009\\u2768-\\u2775\\u27C5\\u27C6\\u27E6-\\u27EF\\u2983-\\u2998\\u29D8-\\u29DB\\u29FC\\u29FD\\u2CF9-\\u2CFC\\u2CFE\\u2CFF\\u2D70\\u2E00-\\u2E2E\\u2E30\\u2E31\\u3001-\\u3003\\u3008-\\u3011\\u3014-\\u301F\\u3030\\u303D\\u30A0\\u30FB\\uA4FE\\uA4FF\\uA60D-\\uA60F\\uA673\\uA67E\\uA6F2-\\uA6F7\\uA874-\\uA877\\uA8CE\\uA8CF\\uA8F8-\\uA8FA\\uA92E\\uA92F\\uA95F\\uA9C1-\\uA9CD\\uA9DE\\uA9DF\\uAA5C-\\uAA5F\\uAADE\\uAADF\\uABEB\\uFD3E\\uFD3F\\uFE10-\\uFE19\\uFE30-\\uFE52\\uFE54-\\uFE61\\uFE63\\uFE68\\uFE6A\\uFE6B\\uFF01-\\uFF03\\uFF05-\\uFF0A\\uFF0C-\\uFF0F\\uFF1A\\uFF1B\\uFF1F\\uFF20\\uFF3B-\\uFF3D\\uFF3F\\uFF5B\\uFF5D\\uFF5F-\\uFF65]`;\n const regExps = {\n aletter: '[A-Za-z\\xaa\\xb5\\xba\\xc0-\\xd6\\xd8-\\xf6\\xf8-\\u02c1\\u02c6-\\u02d1\\u02e0-\\u02e4\\u02ec\\u02ee\\u0370-\\u0374\\u0376\\u0377\\u037a-\\u037d\\u0386\\u0388-\\u038a\\u038c\\u038e-\\u03a1\\u03a3-\\u03f5\\u03f7-\\u0481\\u048a-\\u0527\\u0531-\\u0556\\u0559\\u0561-\\u0587\\u05d0-\\u05ea\\u05f0-\\u05F3\\u0620-\\u064a\\u066e\\u066f\\u0671-\\u06d3\\u06d5\\u06e5\\u06e6\\u06ee\\u06ef\\u06fa-\\u06fc\\u06ff\\u0710\\u0712-\\u072f\\u074d-\\u07a5\\u07b1\\u07ca-\\u07ea\\u07f4\\u07f5\\u07fa\\u0800-\\u0815\\u081a\\u0824\\u0828\\u0840-\\u0858\\u0904-\\u0939\\u093d\\u0950\\u0958-\\u0961\\u0971-\\u0977\\u0979-\\u097f\\u0985-\\u098c\\u098f\\u0990\\u0993-\\u09a8\\u09aa-\\u09b0\\u09b2\\u09b6-\\u09b9\\u09bd\\u09ce\\u09dc\\u09dd\\u09df-\\u09e1\\u09f0\\u09f1\\u0a05-\\u0a0a\\u0a0f\\u0a10\\u0a13-\\u0a28\\u0a2a-\\u0a30\\u0a32\\u0a33\\u0a35\\u0a36\\u0a38\\u0a39\\u0a59-\\u0a5c\\u0a5e\\u0a72-\\u0a74\\u0a85-\\u0a8d\\u0a8f-\\u0a91\\u0a93-\\u0aa8\\u0aaa-\\u0ab0\\u0ab2\\u0ab3\\u0ab5-\\u0ab9\\u0abd\\u0ad0\\u0ae0\\u0ae1\\u0b05-\\u0b0c\\u0b0f\\u0b10\\u0b13-\\u0b28\\u0b2a-\\u0b30\\u0b32\\u0b33\\u0b35-\\u0b39\\u0b3d\\u0b5c\\u0b5d\\u0b5f-\\u0b61\\u0b71\\u0b83\\u0b85-\\u0b8a\\u0b8e-\\u0b90\\u0b92-\\u0b95\\u0b99\\u0b9a\\u0b9c\\u0b9e\\u0b9f\\u0ba3\\u0ba4\\u0ba8-\\u0baa\\u0bae-\\u0bb9\\u0bd0\\u0c05-\\u0c0c\\u0c0e-\\u0c10\\u0c12-\\u0c28\\u0c2a-\\u0c33\\u0c35-\\u0c39\\u0c3d\\u0c58\\u0c59\\u0c60\\u0c61\\u0c85-\\u0c8c\\u0c8e-\\u0c90\\u0c92-\\u0ca8\\u0caa-\\u0cb3\\u0cb5-\\u0cb9\\u0cbd\\u0cde\\u0ce0\\u0ce1\\u0cf1\\u0cf2\\u0d05-\\u0d0c\\u0d0e-\\u0d10\\u0d12-\\u0d3a\\u0d3d\\u0d4e\\u0d60\\u0d61\\u0d7a-\\u0d7f\\u0d85-\\u0d96\\u0d9a-\\u0db1\\u0db3-\\u0dbb\\u0dbd\\u0dc0-\\u0dc6\\u0f00\\u0f40-\\u0f47\\u0f49-\\u0f6c\\u0f88-\\u0f8c\\u10a0-\\u10c5\\u10d0-\\u10fa\\u10fc\\u1100-\\u1248\\u124a-\\u124d\\u1250-\\u1256\\u1258\\u125a-\\u125d\\u1260-\\u1288\\u128a-\\u128d\\u1290-\\u12b0\\u12b2-\\u12b5\\u12b8-\\u12be\\u12c0\\u12c2-\\u12c5\\u12c8-\\u12d6\\u12d8-\\u1310\\u1312-\\u1315\\u1318-\\u135a\\u1380-\\u138f\\u13a0-\\u13f4\\u1401-\\u166c\\u166f-\\u167f\\u1681-\\u169a\\u16a0-\\u16ea\\u16ee-\\u16f0\\u1700-\\u170c\\u170e-\\u1711\\u1720-\\u1731\\u1740-\\u1751\\u1760-\\u176c\\u176e-\\u1770\\u1820-\\u1877\\u1880-\\u18a8\\u18aa\\u18b0-\\u18f5\\u1900-\\u191c\\u1a00-\\u1a16\\u1b05-\\u1b33\\u1b45-\\u1b4b\\u1b83-\\u1ba0\\u1bae\\u1baf\\u1bc0-\\u1be5\\u1c00-\\u1c23\\u1c4d-\\u1c4f\\u1c5a-\\u1c7d\\u1ce9-\\u1cec\\u1cee-\\u1cf1\\u1d00-\\u1dbf\\u1e00-\\u1f15\\u1f18-\\u1f1d\\u1f20-\\u1f45\\u1f48-\\u1f4d\\u1f50-\\u1f57\\u1f59\\u1f5b\\u1f5d\\u1f5f-\\u1f7d\\u1f80-\\u1fb4\\u1fb6-\\u1fbc\\u1fbe\\u1fc2-\\u1fc4\\u1fc6-\\u1fcc\\u1fd0-\\u1fd3\\u1fd6-\\u1fdb\\u1fe0-\\u1fec\\u1ff2-\\u1ff4\\u1ff6-\\u1ffc\\u2071\\u207f\\u2090-\\u209c\\u2102\\u2107\\u210a-\\u2113\\u2115\\u2119-\\u211d\\u2124\\u2126\\u2128\\u212a-\\u212d\\u212f-\\u2139\\u213c-\\u213f\\u2145-\\u2149\\u214e\\u2160-\\u2188\\u24B6-\\u24E9\\u2c00-\\u2c2e\\u2c30-\\u2c5e\\u2c60-\\u2ce4\\u2ceb-\\u2cee\\u2d00-\\u2d25\\u2d30-\\u2d65\\u2d6f\\u2d80-\\u2d96\\u2da0-\\u2da6\\u2da8-\\u2dae\\u2db0-\\u2db6\\u2db8-\\u2dbe\\u2dc0-\\u2dc6\\u2dc8-\\u2dce\\u2dd0-\\u2dd6\\u2dd8-\\u2dde\\u2e2f\\u3005\\u303b\\u303c\\u3105-\\u312d\\u3131-\\u318e\\u31a0-\\u31ba\\ua000-\\ua48c\\ua4d0-\\ua4fd\\ua500-\\ua60c\\ua610-\\ua61f\\ua62a\\ua62b\\ua640-\\ua66e\\ua67f-\\ua697\\ua6a0-\\ua6ef\\ua717-\\ua71f\\ua722-\\ua788\\ua78b-\\ua78e\\ua790\\ua791\\ua7a0-\\ua7a9\\ua7fa-\\ua801\\ua803-\\ua805\\ua807-\\ua80a\\ua80c-\\ua822\\ua840-\\ua873\\ua882-\\ua8b3\\ua8f2-\\ua8f7\\ua8fb\\ua90a-\\ua925\\ua930-\\ua946\\ua960-\\ua97c\\ua984-\\ua9b2\\ua9cf\\uaa00-\\uaa28\\uaa40-\\uaa42\\uaa44-\\uaa4b\\uab01-\\uab06\\uab09-\\uab0e\\uab11-\\uab16\\uab20-\\uab26\\uab28-\\uab2e\\uabc0-\\uabe2\\uac00-\\ud7a3\\ud7b0-\\ud7c6\\ud7cb-\\ud7fb\\ufb00-\\ufb06\\ufb13-\\ufb17\\ufb1d\\ufb1f-\\ufb28\\ufb2a-\\ufb36\\ufb38-\\ufb3c\\ufb3e\\ufb40\\ufb41\\ufb43\\ufb44\\ufb46-\\ufbb1\\ufbd3-\\ufd3d\\ufd50-\\ufd8f\\ufd92-\\ufdc7\\ufdf0-\\ufdfb\\ufe70-\\ufe74\\ufe76-\\ufefc\\uff21-\\uff3a\\uff41-\\uff5a\\uffa0-\\uffbe\\uffc2-\\uffc7\\uffca-\\uffcf\\uffd2-\\uffd7\\uffda-\\uffdc]',\n midnumlet: `[-'\\\\.\\u2018\\u2019\\u2024\\uFE52\\uFF07\\uFF0E]`,\n midletter: '[:\\xB7\\xB7\\u05F4\\u2027\\uFE13\\uFE55\\uFF1A]',\n midnum: '[\\xB1+*/,;;\\u0589\\u060C\\u060D\\u066C\\u07F8\\u2044\\uFE10\\uFE14\\uFE50\\uFE54\\uFF0C\\uFF1B]',\n numeric: '[0-9\\u0660-\\u0669\\u066B\\u06f0-\\u06f9\\u07c0-\\u07c9\\u0966-\\u096f\\u09e6-\\u09ef\\u0a66-\\u0a6f\\u0ae6-\\u0aef\\u0b66-\\u0b6f\\u0be6-\\u0bef\\u0c66-\\u0c6f\\u0ce6-\\u0cef\\u0d66-\\u0d6f\\u0e50-\\u0e59\\u0ed0-\\u0ed9\\u0f20-\\u0f29\\u1040-\\u1049\\u1090-\\u1099\\u17e0-\\u17e9\\u1810-\\u1819\\u1946-\\u194f\\u19d0-\\u19d9\\u1a80-\\u1a89\\u1a90-\\u1a99\\u1b50-\\u1b59\\u1bb0-\\u1bb9\\u1c40-\\u1c49\\u1c50-\\u1c59\\ua620-\\ua629\\ua8d0-\\ua8d9\\ua900-\\ua909\\ua9d0-\\ua9d9\\uaa50-\\uaa59\\uabf0-\\uabf9]',\n cr: '\\\\r',\n lf: '\\\\n',\n newline: '[\\x0B\\f\\x85\\u2028\\u2029]',\n extend: '[\\u0300-\\u036f\\u0483-\\u0489\\u0591-\\u05bd\\u05bf\\u05c1\\u05c2\\u05c4\\u05c5\\u05c7\\u0610-\\u061a\\u064b-\\u065f\\u0670\\u06d6-\\u06dc\\u06df-\\u06e4\\u06e7\\u06e8\\u06ea-\\u06ed\\u0711\\u0730-\\u074a\\u07a6-\\u07b0\\u07eb-\\u07f3\\u0816-\\u0819\\u081b-\\u0823\\u0825-\\u0827\\u0829-\\u082d\\u0859-\\u085b\\u0900-\\u0903\\u093a-\\u093c\\u093e-\\u094f\\u0951-\\u0957\\u0962\\u0963\\u0981-\\u0983\\u09bc\\u09be-\\u09c4\\u09c7\\u09c8\\u09cb-\\u09cd\\u09d7\\u09e2\\u09e3\\u0a01-\\u0a03\\u0a3c\\u0a3e-\\u0a42\\u0a47\\u0a48\\u0a4b-\\u0a4d\\u0a51\\u0a70\\u0a71\\u0a75\\u0a81-\\u0a83\\u0abc\\u0abe-\\u0ac5\\u0ac7-\\u0ac9\\u0acb-\\u0acd\\u0ae2\\u0ae3\\u0b01-\\u0b03\\u0b3c\\u0b3e-\\u0b44\\u0b47\\u0b48\\u0b4b-\\u0b4d\\u0b56\\u0b57\\u0b62\\u0b63\\u0b82\\u0bbe-\\u0bc2\\u0bc6-\\u0bc8\\u0bca-\\u0bcd\\u0bd7\\u0c01-\\u0c03\\u0c3e-\\u0c44\\u0c46-\\u0c48\\u0c4a-\\u0c4d\\u0c55\\u0c56\\u0c62\\u0c63\\u0c82\\u0c83\\u0cbc\\u0cbe-\\u0cc4\\u0cc6-\\u0cc8\\u0cca-\\u0ccd\\u0cd5\\u0cd6\\u0ce2\\u0ce3\\u0d02\\u0d03\\u0d3e-\\u0d44\\u0d46-\\u0d48\\u0d4a-\\u0d4d\\u0d57\\u0d62\\u0d63\\u0d82\\u0d83\\u0dca\\u0dcf-\\u0dd4\\u0dd6\\u0dd8-\\u0ddf\\u0df2\\u0df3\\u0e31\\u0e34-\\u0e3a\\u0e47-\\u0e4e\\u0eb1\\u0eb4-\\u0eb9\\u0ebb\\u0ebc\\u0ec8-\\u0ecd\\u0f18\\u0f19\\u0f35\\u0f37\\u0f39\\u0f3e\\u0f3f\\u0f71-\\u0f84\\u0f86\\u0f87\\u0f8d-\\u0f97\\u0f99-\\u0fbc\\u0fc6\\u102b-\\u103e\\u1056-\\u1059\\u105e-\\u1060\\u1062-\\u1064\\u1067-\\u106d\\u1071-\\u1074\\u1082-\\u108d\\u108f\\u109a-\\u109d\\u135d-\\u135f\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17b6-\\u17d3\\u17dd\\u180b-\\u180d\\u18a9\\u1920-\\u192b\\u1930-\\u193b\\u19b0-\\u19c0\\u19c8\\u19c9\\u1a17-\\u1a1b\\u1a55-\\u1a5e\\u1a60-\\u1a7c\\u1a7f\\u1b00-\\u1b04\\u1b34-\\u1b44\\u1b6b-\\u1b73\\u1b80-\\u1b82\\u1ba1-\\u1baa\\u1be6-\\u1bf3\\u1c24-\\u1c37\\u1cd0-\\u1cd2\\u1cd4-\\u1ce8\\u1ced\\u1cf2\\u1dc0-\\u1de6\\u1dfc-\\u1dff\\u200c\\u200d\\u20d0-\\u20f0\\u2cef-\\u2cf1\\u2d7f\\u2de0-\\u2dff\\u302a-\\u302f\\u3099\\u309a\\ua66f-\\uA672\\ua67c\\ua67d\\ua6f0\\ua6f1\\ua802\\ua806\\ua80b\\ua823-\\ua827\\ua880\\ua881\\ua8b4-\\ua8c4\\ua8e0-\\ua8f1\\ua926-\\ua92d\\ua947-\\ua953\\ua980-\\ua983\\ua9b3-\\ua9c0\\uaa29-\\uaa36\\uaa43\\uaa4c\\uaa4d\\uaa7b\\uaab0\\uaab2-\\uaab4\\uaab7\\uaab8\\uaabe\\uaabf\\uaac1\\uabe3-\\uabea\\uabec\\uabed\\ufb1e\\ufe00-\\ufe0f\\ufe20-\\ufe26\\uff9e\\uff9f]',\n format: '[\\xAD\\u0600-\\u0603\\u06DD\\u070F\\u17b4\\u17b5\\u200E\\u200F\\u202A-\\u202E\\u2060-\\u2064\\u206A-\\u206F\\uFEFF\\uFFF9-\\uFFFB]',\n katakana: '[\\u3031-\\u3035\\u309B\\u309C\\u30A0-\\u30fa\\u30fc-\\u30ff\\u31f0-\\u31ff\\u32D0-\\u32FE\\u3300-\\u3357\\uff66-\\uff9d]',\n extendnumlet: '[=_\\u203f\\u2040\\u2054\\ufe33\\ufe34\\ufe4d-\\ufe4f\\uff3f\\u2200-\\u22FF<>]',\n punctuation: punctuationStr\n };\n const characterIndices = {\n ALETTER: 0,\n MIDNUMLET: 1,\n MIDLETTER: 2,\n MIDNUM: 3,\n NUMERIC: 4,\n CR: 5,\n LF: 6,\n NEWLINE: 7,\n EXTEND: 8,\n FORMAT: 9,\n KATAKANA: 10,\n EXTENDNUMLET: 11,\n AT: 12,\n OTHER: 13\n };\n const SETS$1 = [\n new RegExp(regExps.aletter),\n new RegExp(regExps.midnumlet),\n new RegExp(regExps.midletter),\n new RegExp(regExps.midnum),\n new RegExp(regExps.numeric),\n new RegExp(regExps.cr),\n new RegExp(regExps.lf),\n new RegExp(regExps.newline),\n new RegExp(regExps.extend),\n new RegExp(regExps.format),\n new RegExp(regExps.katakana),\n new RegExp(regExps.extendnumlet),\n new RegExp('@')\n ];\n const EMPTY_STRING$1 = '';\n const PUNCTUATION$1 = new RegExp('^' + regExps.punctuation + '$');\n const WHITESPACE$1 = /^\\s+$/;\n\n const SETS = SETS$1;\n const OTHER = characterIndices.OTHER;\n const getType = char => {\n let type = OTHER;\n const setsLength = SETS.length;\n for (let j = 0; j < setsLength; ++j) {\n const set = SETS[j];\n if (set && set.test(char)) {\n type = j;\n break;\n }\n }\n return type;\n };\n const memoize = func => {\n const cache = {};\n return char => {\n if (cache[char]) {\n return cache[char];\n } else {\n const result = func(char);\n cache[char] = result;\n return result;\n }\n };\n };\n const classify = characters => {\n const memoized = memoize(getType);\n return map(characters, memoized);\n };\n\n const isWordBoundary = (map, index) => {\n const type = map[index];\n const nextType = map[index + 1];\n if (index < 0 || index > map.length - 1 && index !== 0) {\n return false;\n }\n if (type === characterIndices.ALETTER && nextType === characterIndices.ALETTER) {\n return false;\n }\n const nextNextType = map[index + 2];\n if (type === characterIndices.ALETTER && (nextType === characterIndices.MIDLETTER || nextType === characterIndices.MIDNUMLET || nextType === characterIndices.AT) && nextNextType === characterIndices.ALETTER) {\n return false;\n }\n const prevType = map[index - 1];\n if ((type === characterIndices.MIDLETTER || type === characterIndices.MIDNUMLET || nextType === characterIndices.AT) && nextType === characterIndices.ALETTER && prevType === characterIndices.ALETTER) {\n return false;\n }\n if ((type === characterIndices.NUMERIC || type === characterIndices.ALETTER) && (nextType === characterIndices.NUMERIC || nextType === characterIndices.ALETTER)) {\n return false;\n }\n if ((type === characterIndices.MIDNUM || type === characterIndices.MIDNUMLET) && nextType === characterIndices.NUMERIC && prevType === characterIndices.NUMERIC) {\n return false;\n }\n if (type === characterIndices.NUMERIC && (nextType === characterIndices.MIDNUM || nextType === characterIndices.MIDNUMLET) && nextNextType === characterIndices.NUMERIC) {\n return false;\n }\n if ((type === characterIndices.EXTEND || type === characterIndices.FORMAT) && (nextType === characterIndices.ALETTER || nextType === characterIndices.NUMERIC || nextType === characterIndices.KATAKANA || nextType === characterIndices.EXTEND || nextType === characterIndices.FORMAT) || (nextType === characterIndices.EXTEND || nextType === characterIndices.FORMAT && (nextNextType === characterIndices.ALETTER || nextNextType === characterIndices.NUMERIC || nextNextType === characterIndices.KATAKANA || nextNextType === characterIndices.EXTEND || nextNextType === characterIndices.FORMAT)) && (type === characterIndices.ALETTER || type === characterIndices.NUMERIC || type === characterIndices.KATAKANA || type === characterIndices.EXTEND || type === characterIndices.FORMAT)) {\n return false;\n }\n if (type === characterIndices.CR && nextType === characterIndices.LF) {\n return false;\n }\n if (type === characterIndices.NEWLINE || type === characterIndices.CR || type === characterIndices.LF) {\n return true;\n }\n if (nextType === characterIndices.NEWLINE || nextType === characterIndices.CR || nextType === characterIndices.LF) {\n return true;\n }\n if (type === characterIndices.KATAKANA && nextType === characterIndices.KATAKANA) {\n return false;\n }\n if (nextType === characterIndices.EXTENDNUMLET && (type === characterIndices.ALETTER || type === characterIndices.NUMERIC || type === characterIndices.KATAKANA || type === characterIndices.EXTENDNUMLET)) {\n return false;\n }\n if (type === characterIndices.EXTENDNUMLET && (nextType === characterIndices.ALETTER || nextType === characterIndices.NUMERIC || nextType === characterIndices.KATAKANA)) {\n return false;\n }\n if (type === characterIndices.AT) {\n return false;\n }\n return true;\n };\n\n const EMPTY_STRING = EMPTY_STRING$1;\n const WHITESPACE = WHITESPACE$1;\n const PUNCTUATION = PUNCTUATION$1;\n const isProtocol = str => str === 'http' || str === 'https';\n const findWordEnd = (characters, startIndex) => {\n let i;\n for (i = startIndex; i < characters.length; i++) {\n if (WHITESPACE.test(characters[i])) {\n break;\n }\n }\n return i;\n };\n const findUrlEnd = (characters, startIndex) => {\n const endIndex = findWordEnd(characters, startIndex + 1);\n const peakedWord = characters.slice(startIndex + 1, endIndex).join(EMPTY_STRING);\n return peakedWord.substr(0, 3) === '://' ? endIndex : startIndex;\n };\n const findWordsWithIndices = (chars, sChars, characterMap, options) => {\n const words = [];\n const indices = [];\n let word = [];\n for (let i = 0; i < characterMap.length; ++i) {\n word.push(chars[i]);\n if (isWordBoundary(characterMap, i)) {\n const ch = sChars[i];\n if ((options.includeWhitespace || !WHITESPACE.test(ch)) && (options.includePunctuation || !PUNCTUATION.test(ch))) {\n const startOfWord = i - word.length + 1;\n const endOfWord = i + 1;\n const str = sChars.slice(startOfWord, endOfWord).join(EMPTY_STRING);\n if (isProtocol(str)) {\n const endOfUrl = findUrlEnd(sChars, i);\n const url = chars.slice(endOfWord, endOfUrl);\n Array.prototype.push.apply(word, url);\n i = endOfUrl;\n }\n if (sChars[i + 1] === '.' && /^([a-zA-Z]\\.)+$/.test(str + '.')) {\n word.push(chars[i + 1]);\n indices.push({\n start: startOfWord,\n end: endOfWord + 1\n });\n } else {\n indices.push({\n start: startOfWord,\n end: endOfWord\n });\n }\n words.push(word);\n }\n word = [];\n }\n }\n return {\n words,\n indices\n };\n };\n const getDefaultOptions = () => ({\n includeWhitespace: false,\n includePunctuation: false\n });\n const getWordsWithIndices = (chars, extract, options) => {\n options = {\n ...getDefaultOptions(),\n ...options\n };\n const extractedChars = map(chars, extract);\n const characterMap = classify(extractedChars);\n return findWordsWithIndices(chars, extractedChars, characterMap, options);\n };\n const getWords$1 = (chars, extract, options) => getWordsWithIndices(chars, extract, options).words;\n\n const getWords = getWords$1;\n\n const removeZwsp$1 = s => s.replace(/\\uFEFF/g, '');\n\n var global$1 = tinymce.util.Tools.resolve('tinymce.dom.TreeWalker');\n\n const getText = (node, schema) => {\n const blockElements = schema.getBlockElements();\n const voidElements = schema.getVoidElements();\n const isNewline = node => blockElements[node.nodeName] || voidElements[node.nodeName];\n const textBlocks = [];\n let txt = '';\n const treeWalker = new global$1(node, node);\n let tempNode;\n while (tempNode = treeWalker.next()) {\n if (tempNode.nodeType === 3) {\n txt += removeZwsp$1(tempNode.data);\n } else if (isNewline(tempNode) && txt.length) {\n textBlocks.push(txt);\n txt = '';\n }\n }\n if (txt.length) {\n textBlocks.push(txt);\n }\n return textBlocks;\n };\n\n const removeZwsp = text => text.replace(/\\u200B/g, '');\n const strLen = str => str.replace(/[\\uD800-\\uDBFF][\\uDC00-\\uDFFF]/g, '_').length;\n const countWords = (node, schema) => {\n const text = removeZwsp(getText(node, schema).join('\\n'));\n return getWords(text.split(''), identity).length;\n };\n const countCharacters = (node, schema) => {\n const text = getText(node, schema).join('');\n return strLen(text);\n };\n const countCharactersWithoutSpaces = (node, schema) => {\n const text = getText(node, schema).join('').replace(/\\s/g, '');\n return strLen(text);\n };\n\n const createBodyCounter = (editor, count) => () => count(editor.getBody(), editor.schema);\n const createSelectionCounter = (editor, count) => () => count(editor.selection.getRng().cloneContents(), editor.schema);\n const createBodyWordCounter = editor => createBodyCounter(editor, countWords);\n const get = editor => ({\n body: {\n getWordCount: createBodyWordCounter(editor),\n getCharacterCount: createBodyCounter(editor, countCharacters),\n getCharacterCountWithoutSpaces: createBodyCounter(editor, countCharactersWithoutSpaces)\n },\n selection: {\n getWordCount: createSelectionCounter(editor, countWords),\n getCharacterCount: createSelectionCounter(editor, countCharacters),\n getCharacterCountWithoutSpaces: createSelectionCounter(editor, countCharactersWithoutSpaces)\n },\n getCount: createBodyWordCounter(editor)\n });\n\n const open = (editor, api) => {\n editor.windowManager.open({\n title: 'Word Count',\n body: {\n type: 'panel',\n items: [{\n type: 'table',\n header: [\n 'Count',\n 'Document',\n 'Selection'\n ],\n cells: [\n [\n 'Words',\n String(api.body.getWordCount()),\n String(api.selection.getWordCount())\n ],\n [\n 'Characters (no spaces)',\n String(api.body.getCharacterCountWithoutSpaces()),\n String(api.selection.getCharacterCountWithoutSpaces())\n ],\n [\n 'Characters',\n String(api.body.getCharacterCount()),\n String(api.selection.getCharacterCount())\n ]\n ]\n }]\n },\n buttons: [{\n type: 'cancel',\n name: 'close',\n text: 'Close',\n primary: true\n }]\n });\n };\n\n const register$1 = (editor, api) => {\n editor.addCommand('mceWordCount', () => open(editor, api));\n };\n\n const first = (fn, rate) => {\n let timer = null;\n const cancel = () => {\n if (!isNull(timer)) {\n clearTimeout(timer);\n timer = null;\n }\n };\n const throttle = (...args) => {\n if (isNull(timer)) {\n timer = setTimeout(() => {\n timer = null;\n fn.apply(null, args);\n }, rate);\n }\n };\n return {\n cancel,\n throttle\n };\n };\n\n var global = tinymce.util.Tools.resolve('tinymce.util.Delay');\n\n const fireWordCountUpdate = (editor, api) => {\n editor.dispatch('wordCountUpdate', {\n wordCount: {\n words: api.body.getWordCount(),\n characters: api.body.getCharacterCount(),\n charactersWithoutSpaces: api.body.getCharacterCountWithoutSpaces()\n }\n });\n };\n\n const updateCount = (editor, api) => {\n fireWordCountUpdate(editor, api);\n };\n const setup = (editor, api, delay) => {\n const debouncedUpdate = first(() => updateCount(editor, api), delay);\n editor.on('init', () => {\n updateCount(editor, api);\n global.setEditorTimeout(editor, () => {\n editor.on('SetContent BeforeAddUndo Undo Redo ViewUpdate keyup', debouncedUpdate.throttle);\n }, 0);\n editor.on('remove', debouncedUpdate.cancel);\n });\n };\n\n const register = editor => {\n const onAction = () => editor.execCommand('mceWordCount');\n editor.ui.registry.addButton('wordcount', {\n tooltip: 'Word count',\n icon: 'character-count',\n onAction,\n context: 'any'\n });\n editor.ui.registry.addMenuItem('wordcount', {\n text: 'Word count',\n icon: 'character-count',\n onAction,\n context: 'any'\n });\n };\n\n var Plugin = (delay = 300) => {\n global$2.add('wordcount', editor => {\n const api = get(editor);\n register$1(editor, api);\n register(editor);\n setup(editor, api, delay);\n return api;\n });\n };\n\n Plugin();\n\n})();\n", "/*!\n * jQuery JavaScript Library v3.7.1\n * https://jquery.com/\n *\n * Copyright OpenJS Foundation and other contributors\n * Released under the MIT license\n * https://jquery.org/license\n *\n * Date: 2023-08-28T13:37Z\n */\n( function( global, factory ) {\n\n\t\"use strict\";\n\n\tif ( typeof module === \"object\" && typeof module.exports === \"object\" ) {\n\n\t\t// For CommonJS and CommonJS-like environments where a proper `window`\n\t\t// is present, execute the factory and get jQuery.\n\t\t// For environments that do not have a `window` with a `document`\n\t\t// (such as Node.js), expose a factory as module.exports.\n\t\t// This accentuates the need for the creation of a real `window`.\n\t\t// e.g. var jQuery = require(\"jquery\")(window);\n\t\t// See ticket trac-14549 for more info.\n\t\tmodule.exports = global.document ?\n\t\t\tfactory( global, true ) :\n\t\t\tfunction( w ) {\n\t\t\t\tif ( !w.document ) {\n\t\t\t\t\tthrow new Error( \"jQuery requires a window with a document\" );\n\t\t\t\t}\n\t\t\t\treturn factory( w );\n\t\t\t};\n\t} else {\n\t\tfactory( global );\n\t}\n\n// Pass this if window is not defined yet\n} )( typeof window !== \"undefined\" ? window : this, function( window, noGlobal ) {\n\n// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1\n// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode\n// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common\n// enough that all such attempts are guarded in a try block.\n\"use strict\";\n\nvar arr = [];\n\nvar getProto = Object.getPrototypeOf;\n\nvar slice = arr.slice;\n\nvar flat = arr.flat ? function( array ) {\n\treturn arr.flat.call( array );\n} : function( array ) {\n\treturn arr.concat.apply( [], array );\n};\n\n\nvar push = arr.push;\n\nvar indexOf = arr.indexOf;\n\nvar class2type = {};\n\nvar toString = class2type.toString;\n\nvar hasOwn = class2type.hasOwnProperty;\n\nvar fnToString = hasOwn.toString;\n\nvar ObjectFunctionString = fnToString.call( Object );\n\nvar support = {};\n\nvar isFunction = function isFunction( obj ) {\n\n\t\t// Support: Chrome <=57, Firefox <=52\n\t\t// In some browsers, typeof returns \"function\" for HTML