js-utl
Version:
A collection of JS utility functions to be used across several applications or libraries.
6,294 lines • 244 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define("JSUtl", [], factory);
else if(typeof exports === 'object')
exports["JSUtl"] = factory();
else
root["JSUtl"] = factory();
})((typeof self !== 'undefined' ? self : this), function() {
return /******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./src/modules/array.js":
/*!******************************!*\
!*** ./src/modules/array.js ***!
\******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "unshiftArray": () => (/* binding */ unshiftArray),
/* harmony export */ "cloneArray": () => (/* binding */ cloneArray),
/* harmony export */ "arraySliceFromValueToValue": () => (/* binding */ arraySliceFromValueToValue),
/* harmony export */ "areArrayItemsAllCoercibleToNumber": () => (/* binding */ areArrayItemsAllCoercibleToNumber),
/* harmony export */ "arrayOrArrayLike": () => (/* binding */ arrayOrArrayLike),
/* harmony export */ "lastOfArray": () => (/* binding */ lastOfArray),
/* harmony export */ "firstOfArray": () => (/* binding */ firstOfArray),
/* harmony export */ "arrayFindReverse": () => (/* binding */ arrayFindReverse),
/* harmony export */ "arrayMax": () => (/* binding */ arrayMax),
/* harmony export */ "arrayMin": () => (/* binding */ arrayMin),
/* harmony export */ "sortNums": () => (/* binding */ sortNums)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Array-related utility functions.
*/
/**
* Unshifts an array.
*
* @param {Array} arr The array.
* @param {*} item The item to unshift.
* @return {undefined}
*/
function unshiftArray(arr, item) {
let len = arr.length;
while (len) {
arr[len] = arr[len - 1];
len--;
}
arr[0] = item;
}
/**
* Clones an array.
*
* @param {Array} arr The array to clone.
* @return {Array} The cloned array.
*/
function cloneArray(arr) {
return arr.slice(0);
}
/**
* Gets a slice of an array from a value up until another.
*
* @param {Array} arr The input array.
* @param {number} from The "from" lower value.
* @param {number} to The "two" upper value.
* @return {Array} The slice as a new array.
*/
function arraySliceFromValueToValue(arr, from, to) {
const ret = [];
let include = false;
for (const value of arr) {
if (!include && value == from) {
ret.push(value);
include = true;
} else if (include && value == to) {
ret.push(value);
break;
} else if (include) {
ret.push(value);
}
}
return ret;
}
/**
* Tests whether all the elements of an array are coercible to a number or not.
*
* @param {Array} array An array.
* @return {boolean} True if all the elements are coercible to a number, false otherwise.
*/
function areArrayItemsAllCoercibleToNumber(array) {
const res = !array.some(isNaN);
return res;
}
/**
* Copies an array or converts an array-like object to a new array.
*
* @param {*} arg Array or array-like object.
* @return {Array} An array.
*/
function arrayOrArrayLike(arg) {
return Array.prototype.slice.call(arg);
}
/**
* Returns the last element of the given array.
*
* @param {Array} array An array.
* @return {*} The last element of the array or undefined if there isn't one.
*/
function lastOfArray(array) {
return array[array.length - 1];
}
/**
* Returns the first element of the given array.
*
* @param {Array} array An array.
* @return {*} The first element of the array or undefined if there isn't one.
*/
function firstOfArray(array) {
return array[0];
}
/**
* Like {@link Array.prototype.find}, but in reverse order.
*
* @param {Array} array An array.
* @param {Function} fn Function to use for the test. The function will receive the array element as parameter.
* @return {*} The first element which satisfies the test in the array by seeking for the element in reverse order
* (i.e. the last element of the array for which the test is satisfied).
* If no element satisfies the test, "undefined" is returned.
*/
function arrayFindReverse(array, fn) {
let l = array.length;
let ret = void 0;
while (l) {
l--;
if (fn(array[l])) {
ret = array[l];
break;
}
}
return ret;
}
/**
* Finds the maximum value of an array of numbers.
*
* @param {number[]} array An array of numbers.
* @return {number|undefined} The maximum value of the array, or "undefined"
* if the given array is empty.
*/
const arrayMax = array =>
array.length
? array.reduce(
(carry, current) => (current > carry ? current : carry),
-Infinity
)
: void 0;
/**
* Finds the minimum value of an array of numbers.
*
* @param {number[]} array An array of numbers.
* @return {number|undefined} The minimum value of the array, or "undefined"
* if the given array is empty.
*/
const arrayMin = array =>
array.length
? array.reduce(
(carry, current) => (current < carry ? current : carry),
+Infinity
)
: void 0;
/**
* Sorts an array of numbers returning a new array with the sorted
* numbers (does not mutate the original).
*
* @param {number[]} arrayOfNums An array of numbers.
* @param {boolean} [desc] True for descending order, false for ascending order (default).
* @return {number[]} A new array with the sorted numbers.
*/
const sortNums = (arrayOfNums, desc = false) =>
[...arrayOfNums].sort((a, b) =>
!desc // asc
? a - b
: // desc
b - a
);
/***/ }),
/***/ "./src/modules/bitwise.js":
/*!********************************!*\
!*** ./src/modules/bitwise.js ***!
\********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "turnNthBitOff": () => (/* binding */ turnNthBitOff),
/* harmony export */ "turnNthBitOn": () => (/* binding */ turnNthBitOn),
/* harmony export */ "toggleNthBit": () => (/* binding */ toggleNthBit),
/* harmony export */ "checkNthBitOn": () => (/* binding */ checkNthBitOn)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Bitwise utility functions.
*/
/**
* Turns nth bit off.
*
* @param {number} num A number.
* @param {number} nth Nth bit to turn off (starting from 1 for the rightmost bit).
* @return {number} New number with the nth bit turned off.
*/
const turnNthBitOff = (num, nth) => num & ~(1 << (nth - 1));
/**
* Turns nth bit on.
*
* @param {number} num A number.
* @param {number} nth Nth bit to turn on (starting from 1 for the rightmost bit).
* @return {number} New number with the nth bit turned off.
*/
const turnNthBitOn = (num, nth) => num | (1 << (nth - 1));
/**
* Toggles nth bit.
*
* @param {number} num A number.
* @param {number} nth Nth bit to toggle (starting from 1 for the rightmost bit).
* @return {number} New number with the nth bit toggled.
*/
const toggleNthBit = (num, nth) => num ^ (1 << (nth - 1));
/**
* Checks if nth bit is on.
*
* @param {number} num A number.
* @param {number} nth Nth bit to check.
* @param {number} 0 if the nth bit is off, otherwise a number greater than 0 if the nth bit is on.
*/
const checkNthBitOn = (num, nth) => num & (1 << (nth - 1));
/***/ }),
/***/ "./src/modules/callback.js":
/*!*********************************!*\
!*** ./src/modules/callback.js ***!
\*********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "delay": () => (/* binding */ delay),
/* harmony export */ "debounce": () => (/* binding */ debounce),
/* harmony export */ "throttle": () => (/* binding */ throttle)
/* harmony export */ });
/* harmony import */ var _core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./core */ "./src/modules/core/index.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Utility functions for callback handling (like debouncing, throttling).
*/
/**
* Delays execution of a callback and cancels a previously registered callback if it wasn't executed yet.
*/
const delay = (function () {
let timer = 0;
/**
* Inner function.
*
* @param {Function} callback The callback to execute.
* @param {number} ms Milliseconds to wait before executing the callback.
* @return {undefined}
*/
return function (callback, ms) {
clearTimeout(timer);
timer = setTimeout(function () {
callback();
}, ms);
};
})();
/**
* Debounces a function.
*
* @param {Function} fn A function.
* @param {number} wait Wait interval in milliseconds.
* @return {Function} A new function, debounced.
*/
function debounce(fn, wait) {
let timer = void 0;
return function (...args) {
!(0,_core__WEBPACK_IMPORTED_MODULE_0__.isUndefined)(timer) && clearTimeout(timer);
timer = setTimeout(function () {
fn(...args);
}, wait);
};
}
/**
* Throttles a function.
*
* @see https://www.sitepoint.com/throttle-scroll-events/
*
* @param {Function} fn A function.
* @param {number} wait Wait interval in milliseconds.
* @return {Function} A new function, throttled.
*/
function throttle(fn, wait) {
let time = Date.now();
return function (...args) {
if (time + wait - Date.now() < 0) {
fn(...args);
time = Date.now();
}
};
}
/***/ }),
/***/ "./src/modules/color.js":
/*!******************************!*\
!*** ./src/modules/color.js ***!
\******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "getLuminance": () => (/* binding */ getLuminance),
/* harmony export */ "intToRGBHexString": () => (/* binding */ intToRGBHexString),
/* harmony export */ "colorFromString": () => (/* binding */ colorFromString)
/* harmony export */ });
/* harmony import */ var _hash__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./hash */ "./src/modules/hash.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Color-related utility functions.
*/
/**
* Gets a color's luminance.
*
* @param {number} color Color int value (RGB).
* @return {number} An int greater than 160 if the color is considered dark and less than or
* equal to 160 if the color is considered light.
*/
function getLuminance(color) {
const c = parseInt(color, 16);
const r = (c & 0xff0000) >> 16;
const g = (c & 0x00ff00) >> 8;
const b = c & 0x0000ff;
return 0.299 * r + 0.587 * g + 0.114 * b;
}
/**
* Converts an integer to an RGB hex (hexadecimal) string.
*
* @param {number} i An integer.
* @return {string} An RGB hex string (uppercase).
*/
function intToRGBHexString(i) {
const c = (i & 0x00ffffff).toString(16).toUpperCase();
return "00000".substring(0, 6 - c.length) + c;
}
/**
* Converts a string to an RGB hex (hexadecimal) string representing a color.
*
* @param {string} str The string.
* @return {string} The color as an RGB hex string (uppercase).
*/
const colorFromString = str => {
const hash = (0,_hash__WEBPACK_IMPORTED_MODULE_0__.hashString)(str);
return intToRGBHexString(hash);
};
/***/ }),
/***/ "./src/modules/combinatorics.js":
/*!**************************************!*\
!*** ./src/modules/combinatorics.js ***!
\**************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "yieldCombinationsWithoutRepetition": () => (/* binding */ yieldCombinationsWithoutRepetition),
/* harmony export */ "uniqueProgressiveIncrementalCombinations": () => (/* binding */ uniqueProgressiveIncrementalCombinations),
/* harmony export */ "yieldUniqueProgressiveIncrementalCombinations": () => (/* binding */ yieldUniqueProgressiveIncrementalCombinations),
/* harmony export */ "yieldAllSubsequences": () => (/* binding */ yieldAllSubsequences),
/* harmony export */ "yieldUniqueSubsequences": () => (/* binding */ yieldUniqueSubsequences),
/* harmony export */ "yieldPermutations": () => (/* binding */ yieldPermutations)
/* harmony export */ });
/* harmony import */ var _core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./core */ "./src/modules/core/index.js");
/* harmony import */ var _array__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./array */ "./src/modules/array.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Combinatorics utility functions.
*/
/**
* Yields all the combinations of an array without repetitions (binomial coefficient).
*
* @generator
* @param {Array} items An array.
* @param {number} numberOfItemsPerCombination The number of elements in each combination
* (this function assumes it to be less than "items.length"
* and greater than 0).
* @param {boolean} yieldCopy True if the yielded combination should be a copy (default) or
* the internal array used during the generation of the current combination.
* @yields {Array} The next combination.
*/
const yieldCombinationsWithoutRepetition = function* (
items,
numberOfItemsPerCombination,
yieldCopy = true
) {
const l = items.length;
const prefix = [];
const recurse = function* recurse(
items,
l,
prefix,
numberOfItemsPerCombination,
nextIndex = 0
) {
// Same as:
// if (nextIndex === numberOfItemsPerCombination) {
if (prefix.length === numberOfItemsPerCombination) {
// Base case:
yield yieldCopy ? (0,_array__WEBPACK_IMPORTED_MODULE_1__.arrayOrArrayLike)(prefix) : prefix;
} else {
// Recurrent case:
for (
let i = nextIndex;
i < l &&
// Remaining needed items
numberOfItemsPerCombination - prefix.length <=
// Remaining available items
l - i;
i++
) {
prefix.push(items[i]);
yield* recurse(items, l, prefix, numberOfItemsPerCombination, i + 1);
prefix.pop();
}
}
};
yield* recurse(items, l, prefix, numberOfItemsPerCombination);
};
/**
* Generate unique, progressive and incremental combinations.
*
* @param {Array} items An array of items.
* @return {Array[]} An array of arrays, each representing a unique progressive incremental combination.
* An empty array is returned if the given items array is empty.
*/
const uniqueProgressiveIncrementalCombinations = items => {
const len = items.length;
if (len === 0) {
return [];
}
const last = (0,_array__WEBPACK_IMPORTED_MODULE_1__.arrayOrArrayLike)(items); // Shallow copy/clone of the given array.
if (len === 1) {
// [1] => [[1]]
return [last];
}
const ret = [];
// [1], [2], [3], ..., [n]
items.map(item => ret.push([item]));
if (len > 2) {
// There are at least three items.
for (
let numberOfItemsPerCombination = 2;
numberOfItemsPerCombination < len;
numberOfItemsPerCombination++
) {
for (const combination of yieldCombinationsWithoutRepetition(
items,
numberOfItemsPerCombination
)) {
ret.push(combination);
}
}
}
ret.push(last);
return ret;
};
/**
* Yields unique, progressive and incremental combinations.
*
* @generator
* @param {Array} items An array of items.
* @param {boolean} yieldCopy True if some of the yielded combinations should be a copy (default)
* of the corresponding internal array used during the generation of the current combination
* or that same array should be returned (if "yieldCopy" is "false").
* @yields {Array} An array, each representing the next unique progressive incremental combination.
* An empty array is yielded if the given items array is empty.
*/
const yieldUniqueProgressiveIncrementalCombinations = function* (
items,
yieldCopy = true
) {
const len = items.length;
if (len === 0) {
return;
}
const last = yieldCopy ? (0,_array__WEBPACK_IMPORTED_MODULE_1__.arrayOrArrayLike)(items) : items; // Shallow copy/clone of the given array.
if (len === 1) {
// [1] => [[1]]
yield last;
return;
}
// [1], [2], [3], ..., [n]
yield* (0,_core__WEBPACK_IMPORTED_MODULE_0__.mapYield)(items, item => [item]);
if (len > 2) {
// There are at least three items.
for (
let numberOfItemsPerCombination = 2;
numberOfItemsPerCombination < len;
numberOfItemsPerCombination++
) {
for (const combination of yieldCombinationsWithoutRepetition(
items,
numberOfItemsPerCombination,
yieldCopy
)) {
yield combination;
}
}
}
yield last;
};
/**
* Yields all the subsequences of the given array of items.
*
* @generator
* @param {Array} items An array of items to use to yield subsequences.
* @yields {Array} The next subsequence.
*/
const yieldAllSubsequences = function* (items) {
const l = items.length;
for (let i = 0; i <= l; i++) {
for (const combination of yieldCombinationsWithoutRepetition(items, i)) {
yield combination;
}
}
};
/**
* Yields only the unique subsequences of the given array of items.
*
* @generator
* @param {Array} items An array of items to use to yield subsequences.
* @yields {Array} The next unique subsequence.
*/
const yieldUniqueSubsequences = function* (items) {
const map = new Map();
yield [];
for (const subsequence of yieldAllSubsequences(items)) {
if (!(0,_core__WEBPACK_IMPORTED_MODULE_0__.nestedMapHas)(map, subsequence)) {
(0,_core__WEBPACK_IMPORTED_MODULE_0__.nestedMapSet)(map, subsequence, true);
yield subsequence;
}
}
};
/**
* Yields all the permutations of the given array of items.
*
* @generator
* @param {Array} items An array of items to use to yield permutations.
* @param {boolean} yieldCopy True if the yielded permutation should be a copy (default) or
* the internal array used during the generation of the current permutation.
* @yields {Array} The next permutation.
*/
const yieldPermutations = function* (items, yieldCopy = true) {
const currentPermutationPrefix = [];
const currentPermutationIndicesMap = {};
const permute = function* () {
if (currentPermutationPrefix.length === items.length) {
yield yieldCopy
? (0,_array__WEBPACK_IMPORTED_MODULE_1__.arrayOrArrayLike)(currentPermutationPrefix)
: currentPermutationPrefix;
} else {
for (let i = 0; i < items.length; i++) {
if (currentPermutationIndicesMap[i]) {
continue;
}
currentPermutationPrefix.push(items[i]);
currentPermutationIndicesMap[i] = true;
yield* permute();
delete currentPermutationIndicesMap[i];
currentPermutationPrefix.pop();
}
}
};
yield* permute();
};
/***/ }),
/***/ "./src/modules/constraint.js":
/*!***********************************!*\
!*** ./src/modules/constraint.js ***!
\***********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "filterInt": () => (/* binding */ filterInt),
/* harmony export */ "filterFloat": () => (/* binding */ filterFloat)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Constraints and filtering utility functions.
*/
/**
* Filters the given string so that it only includes digit (0-9)
* and an optional leading sign ("+", which is removed if present, or "-"),
* i.e. represents a valid integer parsable with "Number.parseInt()".
*
* @param {string} str The input string.
* @return {string} The valid input string or an empty string if there isn't any digit.
*/
function filterInt(str) {
let filtered = str.replace(/[^0-9]/g, "");
filtered = filtered.replace(/^[0]+([1-9])/, "$1");
filtered = filtered.replace(/^[0]+$/, "0");
if (str && filtered.length && str[0] === "-") {
filtered = `-${filtered}`;
}
return filtered;
}
/**
* Filters the given string so that it only includes digits (0-9), a decimal separator ("." character)
* and an optional leading sign ("+", which is removed if present, or "-"),
* i.e. represents a valid float parsable with "Number.parseFloat()".
*
* @param {string} str The input string.
* @return {string} The valid float string or an empty string if there isn't any digit or decimal separator.
* If there isn't any digit in the input string and there is a decimal separator ("." character),
* the returned string will be "0.", i.e. a parsable "0." string.
*/
function filterFloat(str) {
let filtered = str.replace(/[^0-9.]/g, "");
const regex = /(\..*)\./g;
const replace = "$1";
do {
filtered = filtered.replace(regex, replace);
} while (filtered != filtered.replace(regex, replace));
filtered === "." ? (filtered = "0.") : filtered;
filtered = filtered.replace(/^[0]+([1-9])/, "$1");
filtered = filtered.replace(/^[0]+($|\.)/, "0$1");
if (str && filtered.length && str[0] === "-") {
filtered = `-${filtered}`;
}
return filtered;
}
/***/ }),
/***/ "./src/modules/convert.js":
/*!********************************!*\
!*** ./src/modules/convert.js ***!
\********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "b2d": () => (/* binding */ b2d),
/* harmony export */ "d2b": () => (/* binding */ d2b)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Utility functions related to conversion of data from one format to another.
*/
/**
* Binary to decimal.
*
* @param {string} x Binary string.
* @return {number} Decimal number.
*/
const b2d = x => parseInt(x, 2);
/**
* Decimal to binary.
*
* @param {number} x Decimal number.
* @return {string} Binary representation.
*/
const d2b = x => x.toString(2);
/***/ }),
/***/ "./src/modules/core/compare.js":
/*!*************************************!*\
!*** ./src/modules/core/compare.js ***!
\*************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "is": () => (/* binding */ is),
/* harmony export */ "objectPropEqual": () => (/* binding */ objectPropEqual),
/* harmony export */ "shallowEqual": () => (/* binding */ shallowEqual)
/* harmony export */ });
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @typechecks
*
*/
/**
* @type {Function}
*/
const hasOwnProperty = Object.prototype.hasOwnProperty;
/**
* Function implementing "Object.is" behaviour.
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
*
* @param {*} x The first value to compare.
* @param {*} y The second value to compare.
* @return {boolean} A boolean indicating whether or not the two arguments are the same value.
*/
function is(x, y) {
// SameValue algorithm
if (x === y) {
// Steps 1-5, 7-10
// Steps 6.b-6.e: +0 != -0
return x !== 0 || 1 / x === 1 / y;
} else {
// Step 6.a: NaN == NaN
return x !== x && y !== y;
}
}
/**
* Checks whether a prop of an object equals in the other object (shallow comparison).
*
* @param {Object} objA The first object.
* @param {Object} objB The second object.
* @param {string} prop The name of the property.
* @return {boolean} True if the value of "prop" in "objA" is shallowly equal to the value of "prop" in "objB".
*/
function objectPropEqual(objA, objB, prop) {
return hasOwnProperty.call(objB, prop) && is(objA[prop], objB[prop]);
}
/**
* Performs equality by iterating through keys on an object and returning "false"
* when any key has values which are not strictly equal between the arguments.
* Returns "true" when the values of all keys are strictly equal.
*
* @see https://stackoverflow.com/questions/22266826/how-can-i-do-a-shallow-comparison-of-the-properties-of-two-objects-with-javascri#answer-37636728
*
* @param {*} objA First object.
* @param {*} objB Second object.
* @return {boolean}
*/
function shallowEqual(objA, objB) {
if (is(objA, objB)) {
return true;
}
if (
typeof objA !== "object" ||
objA === null ||
typeof objB !== "object" ||
objB === null
) {
return false;
}
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
if (keysA.length !== keysB.length) {
return false;
}
// Test for A's keys different from B.
for (let i = 0; i < keysA.length; i++) {
const prop = keysA[i];
if (!objectPropEqual(objA, objB, prop)) {
return false;
}
}
return true;
}
/***/ }),
/***/ "./src/modules/core/index.js":
/*!***********************************!*\
!*** ./src/modules/core/index.js ***!
\***********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "shallowEqual": () => (/* reexport safe */ _compare__WEBPACK_IMPORTED_MODULE_0__.shallowEqual),
/* harmony export */ "objectPropEqual": () => (/* reexport safe */ _compare__WEBPACK_IMPORTED_MODULE_0__.objectPropEqual),
/* harmony export */ "is": () => (/* reexport safe */ _compare__WEBPACK_IMPORTED_MODULE_0__.is),
/* harmony export */ "config": () => (/* binding */ config),
/* harmony export */ "isObjectEmpty": () => (/* binding */ isObjectEmpty),
/* harmony export */ "isObject": () => (/* binding */ isObject),
/* harmony export */ "isPlainObject": () => (/* binding */ isPlainObject),
/* harmony export */ "isArray": () => (/* binding */ isArray),
/* harmony export */ "isCallable": () => (/* binding */ isCallable),
/* harmony export */ "isEmpty": () => (/* binding */ isEmpty),
/* harmony export */ "isEmptyOr0": () => (/* binding */ isEmptyOr0),
/* harmony export */ "getGlobalObject": () => (/* binding */ getGlobalObject),
/* harmony export */ "uniqueId": () => (/* binding */ uniqueId),
/* harmony export */ "nestedPropertyValue": () => (/* binding */ nestedPropertyValue),
/* harmony export */ "getNestedPropertyValue": () => (/* binding */ getNestedPropertyValue),
/* harmony export */ "hasNestedPropertyValue": () => (/* binding */ hasNestedPropertyValue),
/* harmony export */ "setNestedPropertyValue": () => (/* binding */ setNestedPropertyValue),
/* harmony export */ "nestedMapSet": () => (/* binding */ nestedMapSet),
/* harmony export */ "nestedMapHas": () => (/* binding */ nestedMapHas),
/* harmony export */ "nestedMapGet": () => (/* binding */ nestedMapGet),
/* harmony export */ "nestedTreeMapSet": () => (/* binding */ nestedTreeMapSet),
/* harmony export */ "nestedTreeMapHas": () => (/* binding */ nestedTreeMapHas),
/* harmony export */ "nestedTreeMapGet": () => (/* binding */ nestedTreeMapGet),
/* harmony export */ "mapYield": () => (/* binding */ mapYield),
/* harmony export */ "deepArrayCompare": () => (/* binding */ deepArrayCompare),
/* harmony export */ "deepObjectCompare": () => (/* binding */ deepObjectCompare),
/* harmony export */ "nestedObjectConstructValue": () => (/* binding */ nestedObjectConstructValue),
/* harmony export */ "cloneDeeplyJSON": () => (/* binding */ cloneDeeplyJSON),
/* harmony export */ "isReferenceType": () => (/* binding */ isReferenceType),
/* harmony export */ "isPrimitiveType": () => (/* binding */ isPrimitiveType),
/* harmony export */ "hasCyclicReference": () => (/* binding */ hasCyclicReference),
/* harmony export */ "typeToStr": () => (/* binding */ typeToStr),
/* harmony export */ "cloneObjDeeply": () => (/* binding */ cloneObjDeeply),
/* harmony export */ "deepObjectExtend": () => (/* binding */ deepObjectExtend),
/* harmony export */ "deepObjectCloningExtend": () => (/* binding */ deepObjectCloningExtend),
/* harmony export */ "extend": () => (/* binding */ extend),
/* harmony export */ "extendDecorate": () => (/* binding */ extendDecorate),
/* harmony export */ "shallowExtend": () => (/* binding */ shallowExtend),
/* harmony export */ "includesTypeCoercion": () => (/* binding */ includesTypeCoercion),
/* harmony export */ "isUndefined": () => (/* binding */ isUndefined),
/* harmony export */ "isInt": () => (/* binding */ isInt),
/* harmony export */ "ctypeDigit": () => (/* binding */ ctypeDigit),
/* harmony export */ "isIntegerOrIntegerStr": () => (/* binding */ isIntegerOrIntegerStr),
/* harmony export */ "findIndex": () => (/* binding */ findIndex),
/* harmony export */ "firstPropValue": () => (/* binding */ firstPropValue),
/* harmony export */ "isStrictlyTrue": () => (/* binding */ isStrictlyTrue),
/* harmony export */ "isTruthy": () => (/* binding */ isTruthy),
/* harmony export */ "allTruthy": () => (/* binding */ allTruthy),
/* harmony export */ "allNotUndefined": () => (/* binding */ allNotUndefined),
/* harmony export */ "isJSONString": () => (/* binding */ isJSONString),
/* harmony export */ "noOpFn": () => (/* binding */ noOpFn),
/* harmony export */ "partialShallowEqual": () => (/* binding */ partialShallowEqual),
/* harmony export */ "shallowObjectDiff": () => (/* binding */ shallowObjectDiff),
/* harmony export */ "str": () => (/* binding */ str),
/* harmony export */ "mapObject": () => (/* binding */ mapObject),
/* harmony export */ "mapToObject": () => (/* binding */ mapToObject),
/* harmony export */ "propSelection": () => (/* binding */ propSelection),
/* harmony export */ "prototypeChainProperties": () => (/* binding */ prototypeChainProperties),
/* harmony export */ "prop": () => (/* binding */ prop),
/* harmony export */ "defineProperty": () => (/* binding */ defineProperty),
/* harmony export */ "completeObjectAssign": () => (/* binding */ completeObjectAssign)
/* harmony export */ });
/* harmony import */ var _compare__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./compare */ "./src/modules/core/compare.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Core utility functions.
*/
/**
* Optional configuration with useful properties.
*
* @type {Object}
*/
const config = {
uniqueIdPrefix: "",
elementUniqueIdPrefix: "",
checkNetworkURI: null,
};
/**
* Tests if an object is empty.
*
* @param {Object} obj The object to test.
* @return {boolean} "true" if the given object is empty (does not have own properties), "false" otherwise.
*/
function isObjectEmpty(obj) {
for (const prop in obj) {
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
return false;
}
}
return true;
}
/**
* @type {string}
*/
const objPrototypeToString = Object.prototype.toString.call({});
/**
* Tests if a variable is an object.
*
* @param {*} obj The variable to test.
* @return {boolean} "true" if "obj" is indeed an object, "false" otherwise.
*/
const isObject = function (obj) {
return objPrototypeToString === Object.prototype.toString.call(obj);
};
/**
* Tests if a variable is a plain object (i.e. "{}", an object literal).
*
* @param {*} obj The variable to test.
* @return {boolean} "true" if "obj" is a plain object, "false" otherwise.
*/
const isPlainObject = obj => {
return (
obj !== null &&
typeof obj === "object" &&
obj.constructor === Object &&
isObject(obj)
);
};
/**
* Tests to see whether something is an array or not.
*
* @param {*} something A variable to check whether it is an array or not.
* @return {boolean} True if the parameter passed in is an array, false otherwise.
*/
function isArray(something) {
return (
Object.prototype.toString.call(something) ===
Object.prototype.toString.call([])
);
}
/**
* Tests if the given value is callable.
*
* @param {*} v The value.
* @return {boolean} True if callable, false otherwise.
*/
function isCallable(v) {
return typeof v === "function";
}
/**
* Tests if a variable is empty returning true for empty strings and empty arrays.
*
* @param {*} data The variable to test.
* @return {boolean} True if the variable is empty, false otherwise.
*/
function isEmpty(data) {
return !data || data.length === 0;
}
/**
* Tests if a variable is empty or 0 ("0" string) returning true for empty strings,
* empty arrays, the "0" string and empty values.
*
* @param {*} data The variable to test.
* @return {boolean} True if the variable is empty or "0", false otherwise.
*/
function isEmptyOr0(data) {
return !data || data === "0" || data.length === 0;
}
/**
* Returns a reference to the global object.
*
* @return {Window|global} The global object (this function is cross-platform aware).
*/
function getGlobalObject() {
return typeof __webpack_require__.g !== "undefined" ? __webpack_require__.g : window;
}
/**
* @type {string}
*/
const JSUtlUniqueIdCounterProp = "JSUtlUniqueIdCounterLEzKKl87QCDxwVH";
/**
* Generates a unique ID which can be used as an "id" attribute.
*
* @param {string|undefined} [uniqueIdPrefix] Local unique ID prefix which overrides the prefix
* set on the "config" configuration object.
* @return {string} The unique ID.
*/
function uniqueId(uniqueIdPrefix = void 0) {
const globalObject = getGlobalObject();
globalObject[JSUtlUniqueIdCounterProp] =
globalObject[JSUtlUniqueIdCounterProp] || 0;
globalObject[JSUtlUniqueIdCounterProp]++;
const uniqueIdCounter = globalObject[JSUtlUniqueIdCounterProp];
const uniqueId = (uniqueIdPrefix || config.uniqueIdPrefix) + uniqueIdCounter;
return uniqueId;
}
/**
* Gets a nested value of an object given an array of nested property names (keys).
*
* @param {Object} data JS POJO object.
* @param {Array} props Array of object nested keys.
* @return {*} The leaf value.
*/
function nestedPropertyValue(data, props) {
let root = data;
for (let i = 0; i < props.length; i++) {
const prop = props[i];
root = root[prop];
}
return root;
}
/**
* Alias for "nestedPropertyValue".
*
* @alias
*/
const getNestedPropertyValue = nestedPropertyValue;
/**
* Checks if a nested value of an object given an array of nested property names (keys) exists.
*
* @param {Object} data JS POJO object.
* @param {Array} props Array of object nested keys.
* @return {boolean} True if the nested key exists, false otherwise.
*/
function hasNestedPropertyValue(data, props) {
if (!props.length) {
return false;
}
let root = data;
for (let i = 0; i < props.length; i++) {
const prop = props[i];
if (!root[prop]) {
return false;
}
root = root[prop];
}
return true;
}
/**
* Sets a nested value of an object given an array of nested property names (keys).
*
* @param {Object} data JS POJO object.
* @param {Array} props Array of object nested keys.
* @param {*} value Leaf value.
* @return {undefined}
*/
function setNestedPropertyValue(data, props, value) {
if (!props.length) {
return;
}
let root = data;
let prev = null;
for (let i = 0; i < props.length; i++) {
const prop = props[i];
if (typeof root[prop] !== "object") {
root[prop] = {};
}
prev = root;
root = root[prop];
}
if (prev) {
prev[props[props.length - 1]] = value;
}
}
/**
* Sets a nested value on a nested map.
*
* @param {Map|WeakMap} map A map or weak map.
* @param {Array} keys Array of keys to traverse. Each key will lead to a nested map.
* @param {*} value The value to set at the inner key.
* @return {undefined}
*/
const nestedMapSet = (map, keys, value) => {
let i = 0;
let current = map;
while (i < keys.length - 1) {
const key = keys[i];
const nested = current.get(key);
if (nested instanceof Map || nested instanceof WeakMap) {
current = nested;
} else {
const newMap = new Map();
current.set(key, newMap);
current = newMap;
}
i++;
}
current.set(keys[i], value);
};
/**
* Tests if a map has the given nested keys.
*
* @param {Map|WeakMap} map A map or weak map.
* @param {Array} keys Array of keys to check. Each key represents a nested map.
* @return {boolean} "true" if all the nested keys exist, false otherwise.
*/
const nestedMapHas = (map, keys) => {
let current = map;
let i = 0;
const l = keys.length;
while (
(current instanceof Map || current instanceof WeakMap) &&
current.has(keys[i]) &&
i < l
) {
current = current.get(keys[i]);
i++;
}
return i == l;
};
/**
* Gets a value from a nested map.
*
* @param {Map|WeakMap} map A map or weak map.
* @param {Array} keys Array of keys. Each key represents a nested map.
* @return {*} The value of the map or "undefined" if there is no value for the given nested keys.
*/
const nestedMapGet = (map, keys) => {
let current = map;
let i = 0;
const l = keys.length;
while (
(current instanceof Map || current instanceof WeakMap) &&
current.has(keys[i]) &&
i < l
) {
current = current.get(keys[i]);
i++;
}
return i == l ? current : void 0;
};
/**
* @type {Symbol}
*/
const treeMapSubtree = Symbol("treeMapSubtree");
/**
* Sets a nested value on a nested tree map.
*
* @param {Map|WeakMap} rootMap A map or weak map to use as the root.
* @param {Array} keys Array of keys to traverse. Each key will lead to a nested node of the tree map.
* @param {*} value The value to set at the inner nested key.
* @return {undefined}
*/
const nestedTreeMapSet = (rootMap, keys, value) => {
let i = 0;
let current = rootMap;
const MapConstructor = rootMap instanceof WeakMap ? WeakMap : Map;
while (i < keys.length - 1) {
const key = keys[i];
const nested = current.get(key);
if (nested) {
current =
nested[treeMapSubtree] ||
(nested[treeMapSubtree] = new MapConstructor());
} else {
const newMap = new MapConstructor();
const node = {
[treeMapSubtree]: newMap,
value: void 0,
};
current.set(key, node);
current = newMap;
}
i++;
}
const key = keys[i];
!current.has(key)
? current.set(key, {
value,
})
: (current.get(key).value = value);
};
/**
* Tests if a tree map has the given nested keys.
*
* @param {Map|WeakMap} rootMap The root of the map or weak map.
* @param {Array} keys Array of keys to check. Each key represents a nested node of the tree map.
* @return {boolean} "true" if all the nested keys exist, false otherwise.
*/
const nestedTreeMapHas = (rootMap, keys) => {
let current = rootMap;
let i = 0;
const l = keys.length;
while (
(current instanceof Map || current instanceof WeakMap) &&
current.has(keys[i]) &&
i < l
) {
current = current.get(keys[i])[treeMapSubtree];
i++;
}
return i == l;
};
/**
* Gets a value from a nested tree map.
*
* @param {Map|WeakMap} rootMap The root of the map or weak map.
* @param {Array} keys Array of keys. Each key represents a nested node of the tree map.
* @return {*} The value of the tree map or "undefined" if there is no value for the given nested keys.
*/
const nestedTreeMapGet = (rootMap, keys) => {
let current = rootMap;
let i = 0;
const lastIndex = keys.length - 1;
while (
(current instanceof Map || current instanceof WeakMap) &&
current.has(keys[i]) &&
i < lastIndex
) {
current = current.get(keys[i])[treeMapSubtree];
i++;
}
if (i === lastIndex && current) {
const lastKey = keys[i];
if (current.has(lastKey)) {
const nested = current.get(lastKey);
return nested.value;
}
}
return void 0;
};
/**
* Yields values of an array mapping the yielded value.
*
* @generator
* @param {Array} items An array of items.
* @param {*} fn The function to call.
* The function will receive, in order the nth item,
* the index of the item in the array of items and the whole items array
* as parameters.
* @param {*} thisArg Optional this arg of the called function (defaults to undefined).
* @yields {*} The next yielded mapped item.
*/
function* mapYield(items, fn, thisArg = void 0) {
items.map();
const boundFn = fn.bind(thisArg);
for (let i = 0; i < items.length; i++) {
yield boundFn(items[i], i, items);
}
}
/**
* Compares two arrays deeply.
*
* @param {Array} arr1 First array.
* @param {Array} arr2 Second array.
* @return {boolean} True if they are equal (same indexes and same values), false otherwise.
*/
function deepArrayCompare(arr1, arr2) {
if (arr1.length != arr2.length) {
return false;
}
const toString = Object.prototype.toString;
const arrayToStringStr = toString.call([]);
for (let i = 0; i < arr1.length; i++) {
if (!(i in arr2)) {
return false;
} else if (isPlainObject(arr1[i])) {
if (
!isPlainObject(arr2[i]) ||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
!deepObjectCompare(arr1[i], arr2[i])
) {
return false;
}
} else if (arrayToStringStr === toString.call(arr1[i])) {
if (
arrayToStringStr !== toString.call(arr2[i]) ||
!deepArrayCompare(arr1[i], arr2[i])
) {
return false;
}
} else {
if (arr1[i] !== arr2[i]) {
return false;
}
}
}
return true;
}
/**
* Compare two objects deeply.
*
* @param {Object} obj1 First object.
* @param {Object} obj2 Second object.
* @return {boolean} True if they are equal (same properties and same values), false otherwise.
*/
function deepObjectCompare(obj1, obj2) {
const toString = Object.prototype.toString;
const arrayToStringStr = toString.call([]);
for (const property in obj1) {
if (!(property in obj2)) {
// `obj2[property]` does not contain the property of `obj1`.
return false;
} else if (isPlainObject(obj1[property])) {
// `obj1[property]` is an object.
if (
!isPlainObject(obj2[property]) ||
!deepObjectCompare(obj1[property], obj2[property])
) {
// `obj2[property]` is not an object or the branches are different.
return false;
}
} else if (arrayToStringStr === toString.call(obj1[property])) {
// `obj1[property]` is an array.
if (
arrayToStringStr !== toString.call(obj2[property]) ||
!deepArrayCompare(obj1[property], obj2[property])
) {
// `obj2[property]` is not an array or the two objects are different.
return false;
}
} else {
// `obj1[property]` is not an object and is not an array.
if (obj1[property] !== obj2[property]) {
return false;
}
}
}
// `obj1` equals `obj2` (has the same properties and the same values).
return true;
}
/**
* Nests the properties of an object using an array of props definitions and defaults.
* Returns the leaf.
*
* Example:
*
* ```
* const obj = {};
* let nest = [{a: {}}, {b: {}}, {c: {}}, {d: {}}, {e: {}}, {f: {}}, {g: {}}, {h: {}} ];
* const leaf = nestedObjectConstructValue(obj, nest);
* leaf.i = 'i';
* leaf.l = { m: "m" };
* JSON.stringify(obj); // {"a":{"b":{"c":{"d":{"e":{"f":{"g":{"h":{"i":"i","l":{"m":"m"}}}}}}}}}}
* nest = nest.concat([ {n: {}}, {o: {}}, {p: {}} ]);
* var pLeaf = nestedObjectConstructValue(obj, nest);
* pLeaf.q = 'q';
* nest = nest.concat([ {q: {}} ]);
* nestedObjectConstructValue(obj, nest); // 'q'
* ```
*
* @param {Object} root The root object.
* @param {Array} nestedPropsDef The nexted props definitions.
* @param {boolean} [isRootArrayIfRootFalsy] True if the root should be an array if the first argument "root" is falsy.
* @return {*} The leaf.
*/
function nestedObjectConstructValue(
root,
nestedPropsDef,
isRootArrayIfRootFalsy
) {
root = root || (isRootArrayIfRootFalsy ? [] : {});
let leaf = root;
for (let i = 0; i < nestedPropsDef.length; i++) {
const propDef = nestedPropsDef[i];
const propKey = Object.keys(propDef)[0];
const propDefault = propDef[propKey];
leaf[propKey] = leaf[propKey] || propDefault;
leaf = leaf[propKey];
}
return leaf;
}
/**
* Clones an object deeply using the JSON API.
*
* @param {Object} obj The object to clone.
* @return {Object} The cloned object.
*/
function cloneDeeplyJSON(obj) {
return JSON.parse(JSON.stringify(obj));
}
/**
* Tests whether the given value is a reference type or not.
*
* @param {*} value Any value which can be an object or a primitive type.
* @return {boolean} True if the given value is a reference type, false otherwise.
*/
function isReferenceType(value) {
return new Object(value) === value;
}
/**
* Tests whether the given value is a primitive type or not.
*
* @param {*} value Any value which can be an object or a primitive type.
* @return {boolean} True if the given value is a primitive type, false otherwise.
*/
function isPrimitiveType(value) {
return new Object(value) !== value;
}
/**
* Checks whether an object has a cyclic reference or not.
*
* @param {Object} obj The object to check for a cyclic reference.
* @return {boolean} True if the object has a cyclic reference, false otherwise.
*/
function hasCyclicReference(obj) {
const stackSet = [];
let detected = false;
function detect(obj) {
if (detected) {
return;
}
if (typeof obj !== "object") {
return;
}
const indexOfObj = stackSet.indexOf(obj);
if (indexOfObj !== -1) {
detected = true;
return;
}
stackSet.push(obj);
for (const k in obj) {
if (Object.prototype.hasOwnProperty.call(obj, k)) {
detect(obj[k]);
}
}
stackSet.splice(indexOfObj, 1);
return;
}
detect(obj);
return detected;
}
/**
* Converts a type to its string representation.
*
* @param {*} type A variable.
* @return {string} The string representation of "type".
*/
function typeToStr(type) {
return Object.prototype.toString.call(type);
}
/**
* Clones an object deeply and returns the clone.
*
* @param {Object} object The object to clone.
* @return {Object} The clone.
* @throws {Error} If a circular reference if even only one property is of an unkown type
* (this should never happen) or a circular reference is detected.
*/
function cloneObjDeeply(object) {
const newObject = new object.constructor();
for (const prop in object) {
// If the property is defined on the prototype, ignore it. We don't want to assign it for each clone instance.
if (!Object.prototype.hasOwnProperty.call(object, prop)) {
continue;
}
const property = object[prop];
if (isPrimitiveType(property)) {
newObject[prop] = property;
} else if (isReferenceType(property)) {
if (!hasCyclicReference(property)) {
const clone = cloneObjDeeply(property);
newObject[prop] = clone;
} else {
throw new Error(
"Circular reference detected inside of property '" +
prop +
"' (" +
typeToStr(property) +
") in object (" +
typeToStr(object) +
")"
);
}
} else {
throw new Error(
"Oops! Unknown type for property '" +
prop +
"' (" +
typeToStr(property) +
") in object (" +
typeToStr(object) +
")"
);
}
}
return newObject;
}
/**
* Deep object extension implementation.
* Nothing is returned, but the destination object will be modified and merged with the source object
* so that properties of the source object which are objects will recursively merge with the corresponding
* destination property while the other properties with all the other types will replace the properties of the
* destination object.
* Note that this method should not be used for inheritance via the Prototypal Combination Inheritance pattern.
* Also, this method doesn't perform a deep object cloning, it just extends the destinationObject by adding properties
* it doesn't have in a deep way.
*
* @param {Object} destinationObject The destination object which will be modified and merged with the source object.
* @param {Object} sourceObject The source object which will be used to extend the destination object.
* @param {Object} [options] An object containing the options for the extension.
* The currently available options are:
*
* - extendsArrays (boolean: false): Whether or not to extend nested arrays too (defaults to false);
*
* @return {undefined}
*/
function deepObjectExtend(
destinationObject,
sourceObject,
options = {}
) {
for (const property in sourceObject) {
if (sourceObject[property] && isPlainObject(sourceObject[property])) {
destinationObject[property] = destinationObject[property] || {};
deepObjectExtend(
destinationObject[property],
sourceObject[property],
options
);
} else if (
options.extendArrays &&
sourceObject[property] &&
isArray(sourceObject[property])
) {
destinationObject[property] = destinationObject[property] || [];
deepObjectExtend(
destinationObject[property],
sourceObject[property],
options
);
} else {
destinationObject[property] = sourceObject[property];
}
}
}
/**
* Deep object cloning extension implementation. If the source objects contain a property with a reference type, a clone object
* of the same type of that property will be created and then merged with the property object of the destination object.
*
* @param {Object} destinationObject The destination object which will be modified and merged with the source object.
* @param {...Object} sourceObject One or more objects which will be used to extend the destination object.
* @return {undefined}
*/
function deepObjectCloningExtend(...args) {
const destinationObject = args[0];
let sourceObject;
for (let i = 1; args[i]; i++) {
sourceObject = args[i];
for (const property in sourceObject) {
if (sourceObject[property] && isPlainObject(sourceObject[property])) {
destinationObject[property] = destinationObject[property] || {};
deepObjectExtend(
destinationObject[property],
cloneObjDeeply(sourceObject[property])
);
} else {
destinationObject[property] = sourceObject[property];
}
}
}
}
/**
* Extends a destination object with the provided source objects.
*
* @param {Object} destinationObj The destination object.
* @param {...Object|Array} sourceObjects The source objects. If the last argument is an array containing one single truthy element,
* it will be treated as an options parameter and its single first truthy element will be treated as object
* containing the options for the extension.
* The currently available options are:
*
* - extendsArrays (boolean: false): Whether or not to extend nested arrays too (defaults to false);
*
* @return {Object} The destination object "destinationObj" given as parameter after extension.
*/
function extend(destinationObj, ...sourceObjects) {
let options = {};
if (sourceObjects.length) {
const last = sourceObjects.pop();
if (isArray(last) && last.length === 1 && isPlainObject(last[0])) {
options = last[0];
} else {
sourceObjects.push(last);
}
}
for (const sourceObject of sourceObjects) {
deepObjectExtend(destinationObj, sourceObject, options);
}
return destinationObj;
}
/**
* Extends a destination object with the provided source objects.
*
* @param {Object} destinationObject The destination object.
* @param {...*} rest The source objects with the last parameter being an array of rules,
* each rule being a tuple array where the first element is an array of "ORed" property names (strings or numbers)
* or regexes matching property names for which the corresponding values should be decorated
* (or a single property name or regex matching a property name if the decoration should only happen on a single property),
* and where the second element is a callback to execute for each value which is a value of a property
* of a source object.
* The callback has the following signature:
*
* (value: *, prop: string|number, parent: Object) => *|undefined
*
* The callback will receive the final value after extension, its associated property and the parent object
* where that property is set with that value.
* Its returned value will be used as the final value of the property for that object in "destinationObject".
*
* If the last parameter is not an array of rules, it will be treated as the last source object to use for the extension
* (the "extend" function will be simply called under the hood without any decoration logic).
* @return {Object} The destination object "destinationObject" given as parameter after extension and, if the callback is given
* as the last parameter, after applying the given callback.
*/
function extendDecorate(destinationObject, ...rest) {
const rules = rest[rest.length - 1];
if (isArray(rules)) {
rest.pop();
const sourceObjects = rest;
const initialRetValue = {};
const matchedRulesMap = new Map();
const callbacksMap = new Map();
const paths = [];
const mapKeys = (
destinationObject,
sourceObject,
currentStack,
currentPath
) => {
for (const key in sourceObject) {
currentStack.push({
destinationObject,
sourceObject,
property: key,
path: [...currentPath, key],
});
}
};
const matchRule = (rule, property) => {
if (rule instanceof RegExp && typeof property === "string") {
return property.match(rule);
} else {
return rule === property;
}
};
const matchArrayRule = (arrayRule, property) => {
for (const rule of arrayRule) {
if (matchRule(rule, property)) {
return true;
}
}
return false;
};
const ruleMatches = (rule, property) => {
if (isArray(rule)) {
return matchArrayRule(rule, property);
} else {
return matchRule(rule, property);
}
};
const matchRules = property => {
if (!matchedRulesMap.has(property)) {
const callbacks = [];
for (const [rule, callback] of rules) {
if (ruleMatches(rule, property)) {
callbacks.push(callback);
}
}
matchedRulesMap.set(property, callbacks);
}
return matchedRulesMap.get(property);
};
for (const sourceObject of sourceObjects) {
const currentStack = [];
const currentPath = [];
mapKeys(destinationObject, sourceObject, currentStack, currentPath);
while (currentStack.length) {
const {
destinationObject,
sourceObject,
property,
path: currentPath,
} = currentStack.pop();
if (sourceObject[property] && isPlainObject(sourceObject[property])) {
// "sourceObject[property]" is an object of class "Object".
destinationObject[property] = isPlainObject(
destinationObject[property]
)
? destinationObject[property]
: {};
mapKeys(
destinationObject[property],
sourceObject[property],
currentStack,
currentPath
);
} else {
// "sourceObject[property]" is not an object.
destinationObject[property] = sourceObject[property];
}
const callbacks = matchRules(property);
if (callbacks && callbacks.length) {
if (!nestedTreeMapHas(callbacksMap, currentPath)) {
paths.push([...currentPath]);
}
nestedTreeMapSet(
callbacksMap,
currentPath,
callbacks.map(callback => retValue => path => {
const value =
retValue === initialRetValue
? destinationObject[property]
: retValue;
return callback(value, property, destinationObject, path);
})
);
}
}
}
// Decorating the final nested values.
for (let i = paths.length - 1; i >= 0; i--) {
const path = paths[i];
const callbacks = nestedTreeMapGet(callbacksMap, path) || [];
let retValue = initialRetValue;
for (const callback of callbacks) {
retValue = callback(retValue)(path);
}
if (retValue !== initialRetValue) {
setNestedPropertyValue(destinationObject, path, retValue);
}
}
return destinationObject;
} else {
return extend(destinationObject, ...rest);
}
}
/**
* Shallowly extends a destination object with the provided source objects (first dimension).
*
* @param {Object} destinationObject The destination object.
* @param {...Object} sourceObjects The source objects.
* @return {Object} The destination object "destinationObject" given as parameter after shallow extension.
*/
function shallowExtend(destinationObject, ...sourceObjects) {
sourceObjects.map(obj =>
Object.keys(obj).map(key => (destinationObject[key] = obj[key]))
);
return destinationObject;
}
/**
* Like "Array.prototype.includes", but with type coercion.
*
* @param {Array} array The array.
* @param {Anything} value The value.
* @return {boolean} True if the value is included within the array (checking with type coercion`==`).
*/
function includesTypeCoercion(array, value) {
for (const valueOfArray of array) {
if (valueOfArray == value) {
return true;
}
}
return false;
}
/**
* Tests whether a value is undefined or not.
*
* @param {*} value A value
* @return {boolean} True value is undefined, false otherwise.
*/
function isUndefined(value) {
return typeof value === "undefined";
}
/**
* Tests if the given value is an int.
*
* @param {*} value The value.
* @return {boolean} True if value is an int, false otherwise.
*/
function isInt(value) {
return Number.isInteger(value);
}
/**
* Tests if the given string is an integer string.
*
* @param {*} a The string.
* @return {boolean} True if the given string is an integer string, false otherwise.
*/
function ctypeDigit(a) {
return Boolean(a.match(/^[0-9]+$/));
}
/**
* Tests if the given value is an int or an integer string.
*
* @param {*} a The value.
* @return {boolean} True if the value is an int or an integer string, false otherwise.
*/
function isIntegerOrIntegerStr(a) {
return Number.isInteger(a) || ctypeDigit(a);
}
/**
* Finds the index of a value in an array without type juggling
* (i.e. like "Array.prototype.indexOf", but using "==" for equality comparison).
*
* @param {Array} array An array.
* @param {*} value A value.
* @return {number} -1 if the value is not in array, otherwise the index of value in array.
*/
function findIndex(array, value) {
return array.findIndex(el => el == value);
}
/**
* Returns the first value of the first property of an object.
*
* @param {Object} obj The object.
* @return {*} The value of the first property of the given object.
*/
function firstPropValue(obj) {
let prop;
for (prop in obj) {
break;
}
return obj[prop];
}
/**
* Tests if a value is strictly a boolean "true".
*
* @param {*} value A value.
* @return {boolean} "true" if the value is a boolean "true", "false" otherwise.
*/
function isStrictlyTrue(value) {
return value === true;
}
/**
* Tests if a value is truthy or not.
*
* @param {*} value The value.
* @return {boolean} "true" if the value is truthy (evaluates to boolean "true"), "false" otherwise.
*/
function isTruthy(value) {
return Boolean(value);
}
/**
* Tests if all the given values are truthy.
*
* @param {...*} values The values.
* @return {boolean} "true" if and only if all the values are truthy.
*/
function allTruthy(...values) {
return values.every(isTruthy);
}
/**
* Tests if all the given values are not undefined.
*
* @param {...*} values The values.
* @return {boolean} "true" if and only if all the values are not undefined.
*/
function allNotUndefined(...values) {
return values.every(value => typeof value !== "undefined");
}
/**
* Tests if a string is a valid JSON string.
*
* @param {string} str A string.
* @return {boolean} "true" if the string represents a valid JSON string, "false" otherwise.
*/
function isJSONString(str) {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
}
/**
* No-op function.
*
* @return {undefined}
*/
// eslint-disable-next-line @typescript-eslint/no-empty-function
function noOpFn() {}
/**
* Tests if a partial object is a subset of another object.
*
* @param {Object} obj An object.
* @param {Object} partialObj A partial object which may not have all the keys of "obj"
* or may even have different keys, or keys with different values.
* @return {boolean} False if "partialObj" has a key which is not in "obj",
* or has at least one key which is also in "obj" but with a different value
* (shallow comparison), true otherwise.
*/
function partialShallowEqual(obj, partialObj) {
return (0,_compare__WEBPACK_IMPORTED_MODULE_0__.shallowEqual)(
Object.keys(partialObj).reduce((carry, key) => {
carry[key] = obj[key];
return carry;
}, {}),
partialObj
);
}
/**
* Returns a shallow object diff, returning an object with two keys "objA" and "objB",
* each containing an object with all the properties of one of the two objects which are not within
* the other object, respectively.
* If a property is on both objects but each object has a different value for that same property
* (using shallow equality comparison), the returned property will be set on both objects with their
* respective values.
*
* @param {Object} objA First object.
* @param {Object} objB Second object.
* @return {Object} An object containing the shallow diff, with two keys "objA" and "objB".
*/
function shallowObjectDiff(objA, objB) {
const diff = {
objA: {},
objB: {},
};
if ((0,_compare__WEBPACK_IMPORTED_MODULE_0__.shallowEqual)(objA, objB)) {
return diff;
}
const keysA = Object.keys(objA);
const keysB = Object.keys(objB);
for (let i = 0; i < keysA.length; i++) {
const prop = keysA[i];
if (!(0,_compare__WEBPACK_IMPORTED_MODULE_0__.objectPropEqual)(objA, objB, prop)) {
diff.objA[prop] = objA[prop];
if (hasOwnProperty.call(objB, prop)) {
diff.objB[prop] = objB[prop];
}
}
}
for (let i = 0; i < keysB.length; i++) {
const prop = keysB[i];
if (!(0,_compare__WEBPACK_IMPORTED_MODULE_0__.objectPropEqual)(objB, objA, prop)) {
diff.objB[prop] = objB[prop];
if (hasOwnProperty.call(objA, prop)) {
diff.objA[prop] = objA[prop];
}
}
}
return diff;
}
/**
* Casts a value to a string.
*
* @param {*} v A value.
* @return {string} The string representation of the value.
*/
function str(v) {
return "" + v;
}
/**
* Maps an object, executing a function on each of its properties
* returning a new mapped object.
*
* @param {Object} obj The object to map.
* @param {Function} fn The function to use for the mapping.
* @return {Object} The new mapped object.
*/
const mapObject = (obj, fn) =>
Object.fromEntries(
Object.entries(obj).map(([key, value], index) => [
key,
fn(value, key, index),
])
);
/**
* Maps an array to an object.
*
* @param {Array} arr An array.
* @param {Function} fn A function receiving the current value, its index as well as the whole array "arr"
* as parameters returning a tuple with the key at index 0 and the value at index 1 to set on the object.
* @returns {Object} The array mapped to an object.
*/
const mapToObject = (arr, fn) => {
let res;
return arr.reduce(
(carry, ...rest) =>
((res = fn(...rest)) && false) ||
((carry[res[0]] = res[1]) && false) ||
carry,
{}
);
};
/**
* Selects the truthy properties of an object or the properties of an object
* passing a test specified with a callback function.
*
* @param {Object} obj The input object.
* @param {Function} fn A function which will receive two parameters:
*
* - value: The current value of the input object for a given property;
* - prop: The name of the current property of the input object.
*
* The function will have to return a boolean "true" indicating that this value
* and property has to be included in the returned object, or "false" otherwise.
*
* @return {Object} An object having only the properties which passed the test
* implemented by the "fn" callback function.
*/
const propSelection = (obj, fn = isTruthy) =>
Object.keys(obj).reduce((carry, key) => {
if (fn(obj[key], key)) {
carry[key] = obj[key];
}
return carry;
}, {});
/**
* Returns all the properties of the given object traversing its prototype chain.
*
* @param {Object} obj The object.
* @param {Object} [options] An object with options.
* @param {?Object} [options.stopAtPrototype] The prototype in the chain at which to stop the traversing.
* Defaults to null, in which case the whole prototype chain will be traversed.
* @param {boolean} [options.stopAtPrototypeInclude] Whether or not to include the properties of the given prototype at which to stop.
* Works only if "stopAtPrototype" is set to a valid prototype object in the prototype chain
* of "obj".
* Defaults to true, in which case the properties of the prototype at which to stop will be included
* in the returned array.
* @return {string[]} An array of containing the names of the properties.
*/
function prototypeChainProperties(
obj,
{ stopAtPrototype = null, stopAtPrototypeInclude = true } = {}
) {
let current = obj;
const map = {};
let isStopPrototype = false;
let stop = false;
while (!stop && current && (!isStopPrototype || stopAtPrototypeInclude)) {
if (isStopPrototype) {
stop = true;
}
const properties = Object.getOwnPropertyNames(current);
properties.map(property => (map[property] = true));
current = Object.getPrototypeOf(current);
if (stopAtPrototype) {
isStopPrototype = current === stopAtPrototype;
}
}
const properties = Object.keys(map);
return properties;
}
/**
* Defines an object's property with a getter and an optional setter.
*
* @param {Object} obj An object (may be a prototype).
* @param {string} propname The property name.
* @param {Function} getfn Getter function.
* @param {Function|undefined} [setfn] Setter function.
* @return {undefined}
*/
function prop(obj, propname, getfn, setfn = void 0) {
const propObj = {};
propObj[propname] = {
get: getfn,
set: setfn,
};
Object.defineProperties(obj, propObj);
}
/**
* Defines a property on an object.
*
* @param {Object} o An object.
* @param {string} p The property to define.
* @param {Object} descriptor Optional object containing the descriptor's properties to use to override the default properties.
* @return {Object} The object that was passed to the function.
*/
function defineProperty(o, p, descriptor = {}) {
return Object.defineProperty(o, p, {
configurable: false,
enumerable: false,
writable: true,
...descriptor,
});
}
/**
* Assigns the properties of the given source objects to the target object.
*
* @source https://stackoverflow.com/questions/39515321/spread-operator-issues-with-property-accessors-getters#answer-39521418
*
* @param {Object} target The target object.
* @param {...Object} sources The source objects.
* @return {Object} The target object.
*/
function completeObjectAssign(target, ...sources) {
sources.forEach(source => {
const descriptors = Object.keys(source).reduce((descriptors, key) => {
descriptors[key] = Object.getOwnPropertyDescriptor(source, key);
return descriptors;
}, {});
// By default, Object.assign copies enumerable Symbols too.
Object.getOwnPropertySymbols(source).forEach(sym => {
const descriptor = Object.getOwnPropertyDescriptor(source, sym);
if (descriptor.enumerable) {
descriptors[sym] = descriptor;
}
});
Object.defineProperties(target, descriptors);
});
return target;
}
/***/ }),
/***/ "./src/modules/date.js":
/*!*****************************!*\
!*** ./src/modules/date.js ***!
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "isValidDate": () => (/* binding */ isValidDate),
/* harmony export */ "isValidDateTimeStr": () => (/* binding */ isValidDateTimeStr),
/* harmony export */ "utcDate": () => (/* binding */ utcDate)
/* harmony export */ });
/* harmony import */ var _string__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./string */ "./src/modules/string.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Tests if the given value is a valid date.
*
* @param {*} value The value to test.
* @return {boolean} True if it is a valid date, false otherwise.
*/
function isValidDate(value) {
return (
Object.prototype.toString.call(value) === "[object Date]" &&
!isNaN(value.getTime())
);
}
/**
* Tests if the given string is a valid datetime string (e.g. in ISO "YYYY-MM-DD HH:ii:ss" format).
*
* @param {string} str The given string.
* @return {boolean} True if it is a valid datetime string, false otherwise.
*/
function isValidDateTimeStr(str) {
return isValidDate(new Date(str));
}
/**
* Returns a UTC datetime in ISO `YYYY-MM-DD HH:ii:ss` format.
*
* @param {Object} [options] An optional object of options.
* @param {boolean} [options.Y] True to return the year of the UTC datetime. Defaults to true.
* @param {boolean} [options.m] True to return the month of the UTC datetime. Defaults to true.
* @param {boolean} [options.d] True to return the day of the UTC datetime. Defaults to true.
* @param {boolean} [options.H] True to return the hours of the UTC datetime. Defaults to true.
* @param {boolean} [options.i] True to return the minutes of the UTC datetime. Defaults to true.
* @param {boolean} [options.s] True to return the seconds of the UTC datetime. Defaults to true.
* @param {Date|string} [options.date] A date or a string that will be passed to the `Date` constructor
* which represents the date on which to compute and return the UTC date.
* @return {string} The UTC datetime.
*/
const utcDate = ({
Y = true,
m = true,
d = true,
H = true,
i = true,
s = true,
date = void 0,
} = []) => {
const finalDate = date ? new Date(date) : new Date();
const year = finalDate.getUTCFullYear();
const month = (finalDate.getUTCMonth() + 1 + "").padStart(2, "0");
const day = (finalDate.getUTCDate() + "").padStart(2, "0");
const hours = (finalDate.getUTCHours() + "").padStart(2, "0");
const minutes = (finalDate.getUTCMinutes() + "").padStart(2, "0");
const seconds = (finalDate.getUTCSeconds() + "").padStart(2, "0");
const UTCDate = (0,_string__WEBPACK_IMPORTED_MODULE_0__.trim)(
(0,_string__WEBPACK_IMPORTED_MODULE_0__.trim)(
`${Y ? year : ""}-${m && (Y || d || (!Y && !d)) ? month : ""}-${
d ? day : ""
}`,
" -"
) +
" " +
(0,_string__WEBPACK_IMPORTED_MODULE_0__.trim)(
`${H ? hours : ""}:${i && (H || s || (!H && !s)) ? minutes : ""}:${
s ? seconds : ""
}`,
" :"
),
" "
);
let finalUTCDate = UTCDate.replace("--", "-");
finalUTCDate = finalUTCDate.replace("::", ":");
return finalUTCDate;
};
/***/ }),
/***/ "./src/modules/fn.js":
/*!***************************!*\
!*** ./src/modules/fn.js ***!
\***************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "_": () => (/* binding */ _),
/* harmony export */ "proceedCallingFn": () => (/* binding */ proceedCallingFn),
/* harmony export */ "curry": () => (/* binding */ curry),
/* harmony export */ "POJOCurry": () => (/* binding */ POJOCurry),
/* harmony export */ "compose": () => (/* binding */ compose),
/* harmony export */ "pipe": () => (/* binding */ pipe),
/* harmony export */ "pick": () => (/* binding */ pick),
/* harmony export */ "liftBinaryFn": () => (/* binding */ liftBinaryFn),
/* harmony export */ "juxt": () => (/* binding */ juxt),
/* harmony export */ "converge": () => (/* binding */ converge),
/* harmony export */ "execIfPOJOHas": () => (/* binding */ execIfPOJOHas),
/* harmony export */ "execWithExistentProps": () => (/* binding */ execWithExistentProps),
/* harmony export */ "forGen": () => (/* binding */ forGen),
/* harmony export */ "flatten": () => (/* binding */ flatten),
/* harmony export */ "flattenDeep": () => (/* binding */ flattenDeep),
/* harmony export */ "cartesianProduct": () => (/* binding */ cartesianProduct),
/* harmony export */ "identityFn": () => (/* binding */ identityFn),
/* harmony export */ "identityArgsFn": () => (/* binding */ identityArgsFn),
/* harmony export */ "chain": () => (/* binding */ chain)
/* harmony export */ });
/* harmony import */ var _core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./core */ "./src/modules/core/index.js");
/* harmony import */ var _array__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./array */ "./src/modules/array.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Utility functions for functional programming.
*/
/**
* @type {string}
*/
const JSUtlCurryPlaceholderProp = "JSUtlCurryPlaceholderPropRPecoyYmCYqZ2lE";
/**
* Curry function placeholder.
*
* @type {Object}
*/
const _ = {
[JSUtlCurryPlaceholderProp]: true,
};
/**
* @type {string}
*/
const JSUtlProceedCallingFnProp = "JSUtlProceedCallingFnPropRBmGaAgOCgftF9t";
/**
* Return value of "onFnCall" to call the curried function and return its value.
*
* @type {Object}
*/
const proceedCallingFn = {
[JSUtlProceedCallingFnProp]: true,
};
/**
* Curries a function.
*
* @see https://medium.com/@kj_huang/implementation-of-lodash-curry-function-8b1024d71e3b
*
* @param {Function} fn A function to curry in order to return the curried version of the function.
* @param {Object} [obj] An optional object with further properties to tweak the currying behaviour
* and execute code while collecting the arguments of the curried function.
* @param {number|undefined} [obj.arity] The arity of the function, i.e. its number of arguments.
* If omitted, "fn.length" will be used.
* @param {Function|undefined} [obj.onEffectiveArgAdded] An optional callback to execute whenever a new effective argument
* (not a placeholder) is added to the curried function.
* The callback will receive an object with the following properties as argument:
*
* - addedArg: The effective argument added;
* - args: An array with all the previously arguments collected so far
* without considering "addedArg";
* - fn: The function "fn";
* - curriedFn: The current curried function;
*
* The return value of the function is ignored.
* @param {Function|undefined} [obj.onPlaceholder] An optional callback to execute whenever a new placeholder is added to the curried function.
* The callback will receive an object with the following properties as argument:
*
* - args: An array with all the previously arguments collected so far
* without considering "addedArg";
* - fn: The function "fn";
* - curriedFn: The current curried function;
*
* The return value of the function is ignored.
* @param {Function|undefined} [obj.onFnCall] An optional callback to execute just before calling the "fn" function
* (i.e. when the "fn" function is ready to be called and all its arguments have been collected).
*
* The callback will receive an object with the following properties as argument:
*
* - args: The array of the effective arguments of the "fn" function;
* - fn: The function "fn" which was initially passed to "curry";
* - curriedFn: The current curried function;
*
* This way, the code of the callback may decide what to do and may even call the function on its own
* and prevent the call from the caller side (i.e. within the "curry" function).
*
* The callback must explicitly tell "curry" to call the function by returing "proceedCallingFn".
* If the callback returns any other value, then "fn" will not be called in "curry" and the return value
* of this callback will be returned.
* @param {Function|undefined} [obj.onCurriedFnFirstCall] An optional callback to execute only the first time when the first curried function returned by "curry"
* is invoked for the very first time with the very first argument or arguments.
*
* The callback will receive an object with the following properties as argument:
*
* - addedArgs: The arguments provided by the caller;
* - fn: The "fn" function;
* - curriedFn: The current curried function;
*
* @param {Function|undefined} [obj.onNewCurriedFn] An optional callback to execute initially and each time a new curried function is going to be returned.
*
* The callback will an object with the following properties as argument:
*
* - curriedFn: The current curried function (same as "newCurriedFn" when this callback is invoked
* for the very first time);
* - newCurriedFn: The new curried function (will be the same as "curriedFn" when this callback is invoked
* for the very first time);
*
*
* @return {Function} The curried version of the function.
*/
const curry = (
fn,
{
arity = void 0,
onEffectiveArgAdded = void 0,
onPlaceholder = void 0,
onFnCall = void 0,
onCurriedFnFirstCall = void 0,
onNewCurriedFn = void 0,
} = {}
) => {
let curriedFnFirstCall = true;
const expectedNumberOfArgs = typeof arity !== "undefined" ? arity : fn.length;
const nextParameterIndex = 0;
const placeholdersIndices = [];
const curriedInner = (
expectedNumberOfArgs,
nextParameterIndex,
placeholdersIndices,
...args
) =>
function curriedFn(...addedArgs) {
let newExpectedNumberOfArgs = expectedNumberOfArgs;
let newNextParameterIndex = nextParameterIndex;
let newPlaceholdersIndices = null;
let argsRequiredChange = false;
curriedFnFirstCall &&
((onCurriedFnFirstCall &&
onCurriedFnFirstCall({ addedArgs, fn, curriedFn })) ||
true) &&
(curriedFnFirstCall = false);
let numberOfConsumablePlaceholders = placeholdersIndices.length;
for (const addedArg of addedArgs) {
!argsRequiredChange && (args = [...args]);
argsRequiredChange = true;
// "addedArg" may be either a placeholder or an effective argument.
const isPlaceholder = addedArg
? addedArg[JSUtlCurryPlaceholderProp] === _[JSUtlCurryPlaceholderProp]
: false;
if (numberOfConsumablePlaceholders > 0 && !isPlaceholder) {
// Argument is an effective argument consuming a previously set placeholder.
onEffectiveArgAdded &&
onEffectiveArgAdded({ addedArg, args, fn, curriedFn });
let argIndex;
if (newPlaceholdersIndices === null) {
const [firstIndex, ...rest] = placeholdersIndices;
argIndex = firstIndex;
newPlaceholdersIndices = rest;
} else {
argIndex = newPlaceholdersIndices.shift();
}
args[argIndex] = addedArg;
numberOfConsumablePlaceholders--;
newExpectedNumberOfArgs--;
} else {
if (isPlaceholder) {
// Argument is a new placeholder.
if (newPlaceholdersIndices === null) {
newPlaceholdersIndices = placeholdersIndices.concat(
newNextParameterIndex
);
} else {
newPlaceholdersIndices.push(newNextParameterIndex);
}
onPlaceholder && onPlaceholder({ args, fn, curriedFn });
} else {
// Argument is an effective argument.
newExpectedNumberOfArgs--;
onEffectiveArgAdded &&
onEffectiveArgAdded({ addedArg, args, fn, curriedFn });
}
args[newNextParameterIndex] = addedArg;
newNextParameterIndex++;
}
}
// eslint-disable-next-line @typescript-eslint/no-use-before-define
return curried.call(
null,
curriedFn,
newExpectedNumberOfArgs,
newNextParameterIndex,
newPlaceholdersIndices === null
? [...placeholdersIndices]
: newPlaceholdersIndices,
...args
);
};
const curried = (
curriedFn,
expectedNumberOfArgs,
nextParameterIndex,
placeholdersIndices,
...args
) => {
if (expectedNumberOfArgs <= 0) {
if (onFnCall) {
const shouldCallCurriedFn = onFnCall({ args, fn, curriedFn });
if (
shouldCallCurriedFn &&
shouldCallCurriedFn[JSUtlProceedCallingFnProp] ===
proceedCallingFn[JSUtlProceedCallingFnProp]
) {
return fn(...args);
} else {
return shouldCallCurriedFn;
}
} else {
return fn(...args);
}
} else {
const newCurried = curriedInner(
expectedNumberOfArgs,
nextParameterIndex,
placeholdersIndices,
...args
);
onNewCurriedFn && onNewCurriedFn({ curriedFn, newCurriedFn: newCurried });
return newCurried;
}
};
const newCurried = curriedInner(
expectedNumberOfArgs,
nextParameterIndex,
placeholdersIndices
);
onNewCurriedFn &&
onNewCurriedFn({ curriedFn: newCurried, newCurriedFn: newCurried });
return newCurried;
};
/**
* Curries a POJO function, i.e. a function having only a single POJO (Plain Old JavaScript Object)
* as parameter (a function with named arguments).
*
* Each object passed to the returned curried function will be merged with the final object
* to pass to the function "fn" when finally calling it.
*
* @param {Function} fn A function to curry in order to return the curried version of the function.
* @param {Object} [obj] An optional object with further properties to tweak the currying behaviour
* and execute code while collecting the POJO objects which will construct
* the final POJO object to pass to the curried function after plugging the curried POJO function.
* @param {string} [obj.plugPropertyName] The name of the property which instructs that it's time to call the function.
* @param {boolean} [obj.plugPropertyMustBeTruthy] By default, it is enough that the property with "obj.plugPropertyName" name
* is set on the object passed to the curried function to instruct it to call
* "fn".
* If this property is set to "true", the property with "plugPropertyName" name
* will also have to be truthy.
* @param {Function} [obj.onPOJOArgMerged] An optional callback to execute right after merging the next POJO argument with the so far accumulated POJO object.
* The callback will an object with the following properties as argument:
*
* - POJOArg: The given POJO argument;
* - POJO: the so far merged POJO object merged with the given "POJOArg";
* - fn: The "fn" function;
* - curriedFn: The current curried function;
*
* @param {Function} [obj.onFnCall] An optional callback to execute just before calling the "fn" function
* (i.e. when the "fn" function is ready to be called and has been plugged and all
* of its POJO object argument properties have been collected).
*
* The callback will receive an object with the following properties as argument:
*
* - POJO: The callback will receive the function "fn" POJO argument (an object) as its first argument;
* - fn: The "fn" function;
* - curriedFn: The current curried function;
*
* This way, the code of the callback may decide what to do and may even call the function on its own
* and prevent the call from the caller side (i.e. within the "POJOCurry" function).
*
* The callback must explicitly tell "POJOCurry" to call the function by returing "proceedCallingFn"
* If the callback returns any other value, then "fn" will not be called in "POJOCurry" and the return value
* of this callback will be returned.
* @param {Function|undefined} [obj.onCurriedFnFirstCall] An optional callback to execute only the first time when the first curried function returned by "curry"
* is invoked for the very first time with the very first POJO argument.
*
* The callback will receive an object with the following properties as argument:
*
* - POJOArg: The given POJO argument yet to merge with the internal final POJO;
* - fn: The "fn" function;
* - curriedFn: The current curried function;
*
* @param {Function|undefined} [obj.onNewCurriedFn] An optional callback to execute initially and each time a new curried function is going to be returned.
*
* The callback will receive an object with the following properties as argument:
*
* - curriedFn: The current curried function (same as "newCurriedFn" when this callback is invoked
* for the very first time);
* - newCurriedFn: The new curried function (will be the same as "curriedFn" when this callback is invoked
* for the very first time);
*
* @return {Function} The curried version of the function.
*/
const POJOCurry = (
fn,
{
plugPropertyName = "plugCurried",
plugPropertyMustBeTruthy = false,
onPOJOArgMerged = void 0,
onFnCall = void 0,
onCurriedFnFirstCall = void 0,
onNewCurriedFn = void 0,
} = {}
) => {
const POJO = {};
let curriedFnFirstCall = true;
const curriedInner = accPOJO =>
function curriedFn(POJOArg) {
curriedFnFirstCall &&
((onCurriedFnFirstCall &&
onCurriedFnFirstCall({ POJOArg, fn, curriedFn })) ||
true) &&
(curriedFnFirstCall = false);
let POJO = Object.assign({}, accPOJO, POJOArg || {});
if (
Object.prototype.hasOwnProperty.call(POJO, plugPropertyName) &&
(!plugPropertyMustBeTruthy || POJO[plugPropertyName])
) {
const { [plugPropertyName]: POJOArgIgnoredProperty, ...rest } = POJOArg;
const { [plugPropertyName]: POJOIgnoredProperty, ...POJORest } = POJO;
POJO = POJORest;
if (!(0,_core__WEBPACK_IMPORTED_MODULE_0__.isObjectEmpty)(rest)) {
onPOJOArgMerged &&
onPOJOArgMerged({ POJOArg: rest, POJO, fn, curriedFn });
}
let shouldCallCurriedFn = true;
let ret = void 0;
if (onFnCall) {
ret = onFnCall({ POJO, fn, curriedFn });
shouldCallCurriedFn = ret
? ret[JSUtlProceedCallingFnProp] ===
proceedCallingFn[JSUtlProceedCallingFnProp]
: false;
}
if (shouldCallCurriedFn) {
return fn(POJO);
} else {
return ret;
}
} else {
onPOJOArgMerged && onPOJOArgMerged({ POJOArg, POJO, fn, curriedFn });
const newCurried = curriedInner(POJO);
onNewCurriedFn &&
onNewCurriedFn({ curriedFn, newCurriedFn: newCurried });
return newCurried;
}
};
const newCurried = curriedInner(POJO);
onNewCurriedFn &&
onNewCurriedFn({ curriedFn: newCurried, newCurriedFn: newCurried });
return newCurried;
};
/**
* A utility function which composes functions or higher-order functions.
*
* @param {...Function|...Function[]} fns A list of functions or higher-order functions or arrays of functions
* (arrays will be flattened) to compose.
* @return {Function} A function composed of all the functions or higher-order functions
* used for composition.
*/
const compose = (...fns) => (...args) => {
let outerArgs = args;
let hoFn = void 0;
fns = fns.flat(1);
for (let i = fns.length - 1; i >= 0; i--) {
const fn = fns[i];
hoFn = fn(...outerArgs);
outerArgs = [hoFn];
}
return hoFn;
};
/**
* A utility function which pipes functions.
*
* @param {...Function|...Function[]} fns A list of functions or arrays of functions (arrays will be flattened)
* to pipe.
* @return {Function} A function representing the pipe.
*/
const pipe = (...fns) => (...args) => {
fns = fns.flat(1);
return fns.length ? fns.reduce((arg, fn) => [fn(...arg)], args)[0] : void 0;
};
/**
* Returns a function which lets picking the properties of an object.
*
* @param {...string|...number} props The properties to pick.
* @return {Function} A function which if called picks the "props" properties from its argument object
* and returns a new object with the picked properties.
*/
const pick = (...props) => o =>
props.reduce((a, e) => ({ ...a, [e]: o[e] }), {});
/**
* Lifts two functions using a binary function which takes their results as arguments.
*
* @param {Function} binaryFn A binary function (i.e. a function which takes two arguments).
* @return {Function} A higher-order function which has to be called with the first function as argument ("firstFn")
* and returns another higher-order function which has to be called with the second function as argument ("secondFn").
* Then, the returned function will take the parameters to pass to the two functions ("firstFn" and "secondFn")
* and return the result of calling "binaryFn" with the result of those functions given as parameters.
*/
const liftBinaryFn = binaryFn => firstFn => secondFn => (...params) =>
binaryFn(firstFn(...params), secondFn(...params));
/**
* Applies an array of functions to a list of values.
*
* @param {Function[]} fns An array of functions.
* @return {Function} A function which if called with a list of values, will pass the list to each function of "fns"
* and return an array with the values after applying each of the original "fns" to its parameters.
*/
const juxt = fns => (...values) => fns.map(fn => fn(...values));
/**
* Converges a multi-arg function.
*
* @param {Function} multiArgFn A multi-arg function.
* @param {Function[]} fns An array of functions to converge.
* Each function will receive the parameter passed to the function returned
* by this higher-order function (i.e. "params").
* @return {Function} A function which, if called, will pass its arguments to each of the functions in "fns"
* and pass each result of those functions to the multi-arg function "multiArgFn",
* returning its result.
*/
const converge = (multiArgFn, fns) => (...params) =>
multiArgFn(...fns.map(fn => fn(...params)));
/**
* Executes a callback if a POJO object has a property.
*
* @param {Object} POJO A POJO object.
* @return {(prop: string|number) => (fn: Function) => *} A function which receives the property
* and returns and returns a function receiving the callback
* function ("fn") to execute.
*/
const execIfPOJOHas = POJO => prop => fn =>
Object.prototype.hasOwnProperty.call(POJO, prop) && fn(POJO[prop], POJO);
/**
* Executes a callback with the existent properties of an object.
*
* @param {...string|...number} props The properties to check for existence.
* @return {(o: Object) => (fn: (existentProps: string[]|number[]) => *) => *} A function which receives the POJO object for which to check for the given properties
* and returns a function receiving a callback which will receive the existent properties
* of the object as parameter.
*/
const execWithExistentProps = (...props) => o => fn =>
fn(props.filter(prop => Object.prototype.hasOwnProperty.call(o, prop)));
/**
* Loops through the values of a generator and returns an array with its mapped
* values mapped with the given callback.
*
* @param {GeneratorFunction} gen A generator function.
* @return {(args: ...*) => (fn: (val: *) => *) => Array} A function which takes the arguments for the generator and returns
* another function which takes the callback to use to map each
* value of the generator returning an array with all the mapped values of the generator.
*/
const forGen = gen => (...args) => fn => {
const generator = gen(...args);
const arr = [];
for (const value of generator) {
const res = fn(value);
arr.push(res);
}
return arr;
};
/**
* Flattens an array (its first dimension, at most).
*
* @param {Array} arr An array.
* @return {Array} A new flattened array.
*/
const flatten = arr => Array.prototype.concat.apply([], arr);
/**
* Flattens an array with any dimension.
*
* @param {Array} arr An array.
* @param {number} dimension The flattening dimension (defaults to 1, but can be greater, even "Infinity").
* @return {Array} The flattened array.
*/
const flattenDeep = (arr, dimension = 1) => {
return dimension > 0
? arr.reduce(
(acc, val) =>
acc.concat((0,_core__WEBPACK_IMPORTED_MODULE_0__.isArray)(val) ? flattenDeep(val, dimension - 1) : val),
[]
)
: (0,_array__WEBPACK_IMPORTED_MODULE_1__.arrayOrArrayLike)(arr);
};
/**
* Computes the cartesian product of the given sets.
*
* @param {...Array} sets The sets to use to compute the cartesian product.
* @return {Array} The cartesian product of the given sets.
*/
const cartesianProduct = (...sets) =>
sets.reduce((acc, set) => flatten(acc.map(x => set.map(y => [...x, y]))), [
[],
]);
/**
* Identity function.
*
* @see https://en.wikipedia.org/wiki/Identity_function
*
* @param {*} value Any value.
* @return {*} The same passed value.
*/
const identityFn = value => value;
/**
* Identity function for multiple args returning an array of those args.
*
* @param {...*} args The args.
* @return {Array} The same args returned in an array.
*/
const identityArgsFn = (...args) => args;
/**
* @type {Function}
*/
const chainLink = (fn, next) => args =>
fn(args, next && ((...args) => next(args)));
/**
* A higher-order function to create a chain of functions following the Chain of Responsibility design pattern.
*
* @param {...Function|...Function[]} fns A list of functions or higher-order functions or arrays of functions
* (arrays will be flattened) to chain.
* @return {Function} A function representing the chain of the given functions which, if called, will return the result of the chain.
* Each function will receive the next function as its last parameter.
*/
const chain = (...fns) => (...args) => {
fns = fns.flat(1);
const chainFn = fns.reduceRight((nextChainLink, fn) => {
return chainLink(fn, nextChainLink);
}, void 0);
return chainFn(args);
};
/***/ }),
/***/ "./src/modules/google.js":
/*!*******************************!*\
!*** ./src/modules/google.js ***!
\*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "googleMapBestZoomLevelFromBounds": () => (/* binding */ googleMapBestZoomLevelFromBounds)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Utility functions related to Google.
*/
/**
* Determines the best zoom level for a Google map.
*
* @param {google.maps.LatLngBounds} bounds The bounds.
* @param {Object} mapDim JS POJO with the properties height and width.
* @param {number} mapDim.height The height of the map's div.
* @param {number} mapDim.width The width of the map's div.
* @return {number} The best zoom level.
*/
function googleMapBestZoomLevelFromBounds(bounds, mapDim) {
const WORLD_DIM = { height: 256, width: 256 };
const ZOOM_MAX = 21;
function latRad(lat) {
const sin = Math.sin((lat * Math.PI) / 180);
const radX2 = Math.log((1 + sin) / (1 - sin)) / 2;
return Math.max(Math.min(radX2, Math.PI), -Math.PI) / 2;
}
function zoom(mapPx, worldPx, fraction) {
return Math.floor(Math.log(mapPx / worldPx / fraction) / Math.LN2);
}
const ne = bounds.getNorthEast();
const sw = bounds.getSouthWest();
const latFraction = (latRad(ne.lat()) - latRad(sw.lat())) / Math.PI;
const lngDiff = ne.lng() - sw.lng();
const lngFraction = (lngDiff < 0 ? lngDiff + 360 : lngDiff) / 360;
const latZoom = zoom(mapDim.height, WORLD_DIM.height, latFraction);
const lngZoom = zoom(mapDim.width, WORLD_DIM.width, lngFraction);
return Math.min(latZoom, lngZoom, ZOOM_MAX);
}
/***/ }),
/***/ "./src/modules/hash.js":
/*!*****************************!*\
!*** ./src/modules/hash.js ***!
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "stringHashArray": () => (/* binding */ stringHashArray),
/* harmony export */ "hashString": () => (/* binding */ hashString),
/* harmony export */ "onePassStringHash": () => (/* binding */ onePassStringHash),
/* harmony export */ "intSumHash": () => (/* binding */ intSumHash)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Hashing-related utility functions.
*/
/**
* Computes a hash of an array of strings (the order of strings does not matter).
*
* NOTE: An array with duplicate values given as parameter to this function
* may yield to a hash which would collide with other hashes computed
* on different arrays with this same function.
* Therefore is on behalf of the caller to be sure that "array" contains
* unique strings.
*
* @param {string[]} array An array of strings.
* @return {number} A number representing the hash code of the array.
*/
function stringHashArray(array) {
let code = 0;
for (let i = 0; i < array.length; i++) {
let n = 0;
for (let j = 0; j < array[i].length; j++) {
n = (n * 251) ^ array[i].charCodeAt(j);
}
code ^= n;
}
return code;
}
/**
* Returns the hash of a string.
*
* @see https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript#answer-7616484
*
* @param {string} str The string.
* @return {number} The hash code of the string, represented as a number.
*/
const hashString = str => {
let hash = 0,
i,
chr;
if (str.length === 0) {
return hash;
}
for (i = 0; i < str.length; i++) {
chr = str.charCodeAt(i);
hash = (hash << 5) - hash + chr;
hash |= 0; // Convert to 32 bit integer.
}
return hash;
};
/**
* A one-pass algorithm to compute the hash of a series of unique strings incrementally.
*
* NOTE: Duplicate values given as parameter to this function
* may yield to a hash which would collide with other hashes computed
* on different string series with this same function.
* Therefore is on behalf of the caller to be sure that the series of strings will be unique
* while calling this function incrementally.
*
* @param {string} str The string.
* @param {number} [hash] The previous hash computed with this same function if this call is the continuation
* of the unique string series.
* @return {number} The next hash.
*/
function onePassStringHash(str, hash = 0) {
let nextHash = hash;
let n = 0;
for (let j = 0; j < str.length; j++) {
n = (n * 251) ^ str.charCodeAt(j);
}
nextHash ^= n;
return nextHash;
}
/**
* Given a sequence of integers, computes the hash of their sum so that two different sequences
* will have the same hash if the sum of their integers will be the same (the overall sum of the sequences may be higher than `Number.MAX_SAFE_INTEGER`).
*
* @see https://stackoverflow.com/questions/69749629/hash-function-that-returns-the-same-hash-for-a-sum-even-if-different-terms-lead/69749873
*
* Example:
*
* ```
* intSumHash([1, 2, 3, 4, 5, 6]); // 21
* intSumHash([1, 2, 3, 4, 5, 6]) === intSumHash([2, 3, 1, 4, 6, 5]); // true
* intSumHash([1, 2, 3, 4, 5, 6]) === intSumHash([5, 1, 10, 4, 1]); // true
* intSumHash([1, 2, 3, 4, 5, 6]) === intSumHash([21]); // true
* intSumHash([1, 2, 3, 4, 5, 6]) === intSumHash([7, 7, 7]); // true
*
* intSumHash([1, 2]); // 3
*
* const LARGE_PRIME = 999999999989;
* intSumHash([4504 * LARGE_PRIME + 1, 4504 * LARGE_PRIME + 2]); // 800745160017
*
* intSumHash([Number.MAX_SAFE_INTEGER - 1, Number.MAX_SAFE_INTEGER - 2, Number.MAX_SAFE_INTEGER - 90, 10, 13]); // 209
* intSumHash([Number.MAX_SAFE_INTEGER - 2, Number.MAX_SAFE_INTEGER - 90, 10, Number.MAX_SAFE_INTEGER - 1, 13]); // 209
* intSumHash([209, -10, 2, 3, 5]); // 209
* intSumHash([1, 2, 3, 20, 209 - (20 + 3 + 2 + 1)]); // 209
* intSumHash([4, 1, 2, 1, 1, 1, 20, 209 - 10, -86, 70, -25, 1, 7, 13]); // 209
*
* intSumHash([9007597764421056, -10, 2, 3, 5]); // 398509680158
* intSumHash([1, 2, 3, 20, 9007597764421056 - (20 + 3 + 2 + 1)]); // 398509680158
* intSumHash([4, 1, 2, 1, 1, 1, 20, 9007597764421056 - 10, -86, 70, -25, 1, 7, 13]); // 398509680158
* ```
*
* @param {number[]} seq A sequence of integers (an array).
* @return {number} The hash of the sum of the sequence of integers.
*/
function intSumHash(seq) {
const BIG_PRIME = 4503599627370449;
let h = 0;
for (let i = 0; i < seq.length; i++) {
const value = seq[i];
h = (h % BIG_PRIME) + (value % BIG_PRIME);
}
return h;
}
/***/ }),
/***/ "./src/modules/iterator.js":
/*!*********************************!*\
!*** ./src/modules/iterator.js ***!
\*********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "xrange": () => (/* binding */ xrange)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Utility functions related to iterators, generators and iterations.
*/
/**
* Yields all the numbers of the specified range
* (including "start" and "limit" if they fall in the range while stepping
* with "step").
*
* @generator
* @param {number} start An int specifying the start of the range.
* @param {number} limit An int specifying the limit of the range.
* @param {number} step An int specifying the step to take within each value of the range.
* @yield {number} The next number of the range.
*/
function* xrange(start, limit, step = 1) {
if (start < limit) {
if (step <= 0) {
throw new RangeError("Step must be a positive int greater than 0.");
}
for (let i = start; i <= limit; i += step) {
yield i;
}
} else {
if (step >= 0) {
throw new RangeError("Step must be a negative int greater than 0.");
}
for (let i = start; i >= limit; i += step) {
yield i;
}
}
}
/***/ }),
/***/ "./src/modules/map-coordinates.js":
/*!****************************************!*\
!*** ./src/modules/map-coordinates.js ***!
\****************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "clampLat": () => (/* binding */ clampLat),
/* harmony export */ "wrapLng": () => (/* binding */ wrapLng),
/* harmony export */ "normalizeLat": () => (/* binding */ normalizeLat),
/* harmony export */ "normalizeLng": () => (/* binding */ normalizeLng)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Utility functions related to the coordinates of a map.
*/
/**
* Clamps a latitude value so that it is always between -90 and 90.
*
* Latitude ranges between -90 and 90 degrees, inclusive.
* Values above or below this range will be clamped to the range [-90, 90].
* This means that if the value specified is less than -90, it will be set to -90.
* And if the value is greater than 90, it will be set to 90.
*
* @param {number|string} lat Latitude. Either a number or a string which can be casted to a number.
* @return {number} Latitude, clamped.
*/
const clampLat = lat => Number(lat < -90 ? -90 : lat > 90 ? 90 : lat);
/**
* Wraps a longitude value so that it is always between -180 and 180.
*
* Longitude ranges between -180 and 180 degrees, inclusive.
* Values above or below this range will be wrapped so that they fall within the range.
* For example, a value of -190 will be converted to 170.
* A value of 190 will be converted to -170.
* This reflects the fact that longitudes wrap around the globe.
*
* @param {number|string} lng Longitude. Either a number or a string which can be casted to a number.
* @return {number} lng Longitude, wrapped.
*/
const wrapLng = lng => {
lng = Number(lng);
while (lng > 180) {
lng -= 360;
}
while (lng < -180) {
lng += 360;
}
return lng;
};
/**
* Normalizes a latitude so that it is within the range [0, 180].
*
* 1. normalizeLat(90) === 0;
* 2. normalizeLat(0) === 90;
* 3. normalizeLat(-90) === 180;
*
* @param {number|string} lat Latitude. Either a number or a string which can be casted to a number.
* @return {number} Latitude, normalized.
*/
const normalizeLat = lat => {
lat = clampLat(lat);
if (lat >= 0) {
// 1. + 2.
return 90 - lat;
} else {
// 3.
return 90 + Math.abs(lat);
}
};
/**
* Normalizes a longitude so that it is within the range [0, 360].
*
* 1. normalizeLng(-180) === 0;
* 2. normalizeLng(0) === 180;
* 3. normalizeLng(180) === 360;
*
* @param {number} lng Longitude. Either a number or a string which can be casted to a number.
* @return {number} Longitude, normalized.
*/
const normalizeLng = lng => {
lng = wrapLng(lng);
return lng + 180;
};
/***/ }),
/***/ "./src/modules/math.js":
/*!*****************************!*\
!*** ./src/modules/math.js ***!
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "round": () => (/* binding */ round),
/* harmony export */ "sum": () => (/* binding */ sum),
/* harmony export */ "intDiv": () => (/* binding */ intDiv),
/* harmony export */ "isEven": () => (/* binding */ isEven),
/* harmony export */ "isOdd": () => (/* binding */ isOdd),
/* harmony export */ "proportion": () => (/* binding */ proportion)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Mathematical utility functions.
*/
/**
* Rounds a number.
*
* @param {number} number The number to round.
* @param {number} precision The decimal precision.
* @return {number} The rounded number.
*/
function round(number, precision = 0) {
const factor = 10 ** precision;
return Math.round(number * factor) / factor;
}
/**
* Sums two or more numbers.
*
* @param {...number} numbers The numbers to sum.
* @return {number} The sum.
*/
function sum(...numbers) {
return numbers.reduce((carry, num) => carry + num);
}
/**
* Integer division (without decimal part).
*
* @param {number} num A number.
* @param {number} divideBy The number by which to divide "num".
* @return {number} The result of the integer division.
*/
function intDiv(num, divideBy) {
return Math.floor(num / divideBy);
}
/**
* Tests if a number is even.
*
* @param {number} num A number.
* @return {boolean} True if even, false if odd.
*/
function isEven(num) {
return num % 2 === 0;
}
/**
* Tests if a number is odd.
*
* @param {number} num A number.
* @return {boolean} True if odd, false if even.
*/
function isOdd(num) {
return !isEven(num);
}
/**
* Converts a source value of a source range to a value that is proportional
* in another destination range.
*
* @param {number[]} sourceTuple The source range tuple, i.e. a tuple of two values, the starting value of the range at index 0 and the ending value of the range at index 1,
* respectively.
* This function assumes that both the starting and ending values are positive numbers (the starting value can be 0).
* @return {(destRange: number[]) => (sourceValue: number) => number} A function receiving the destination range tuple as argument (having the same shape as the source range)
* returning a function taking the source value as argument returning the value proportional
* in the destination range.
*/
const proportion = ([sourceFrom, sourceTo]) => ([
destFrom,
destTo,
]) => sourceValue =>
(sourceValue - sourceFrom) * ((destTo - destFrom) / (sourceTo - sourceFrom)) +
destFrom;
/***/ }),
/***/ "./src/modules/object.js":
/*!*******************************!*\
!*** ./src/modules/object.js ***!
\*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "objectMin": () => (/* binding */ objectMin)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Object-related utility functions.
*/
/**
* @type {Function}
*/
const defaultObjectComparator = (a, b) => (a < b ? -1 : a > b ? 1 : 0);
/**
* Finds the minimum value of an object.
*
* @param {Object} obj An object.
* @param {Object} [options] An optional object with further options.
* @param {(a: *, c: *) => number} [options.comparator] A comparator function receiving two values as arguments which must return a number less than 0 if the first
* given value is the new minimum value.
* @param {boolean} [options.returnAsKeyVal] True to return an object containing two properties `value` and `key`, namely the minimum value's key
* (`key` property) as well as the minimum value itself (`value` property).
* @return {*} The minimum value or an object with the key and the minimum value if "returnAsKeyVal" is truthy.
*/
const objectMin = (
obj,
{ comparator = defaultObjectComparator, returnAsKeyVal = false } = {}
) => {
const min = { key: void 0, value: void 0 };
for (const key in obj) {
const value = obj[key];
if (typeof min.key === "undefined" || comparator(value, min.value) < 0) {
min.key = key;
min.value = value;
}
}
return returnAsKeyVal ? min : min.value;
};
/***/ }),
/***/ "./src/modules/path.js":
/*!*****************************!*\
!*** ./src/modules/path.js ***!
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "basename": () => (/* binding */ basename),
/* harmony export */ "pathinfo": () => (/* binding */ pathinfo),
/* harmony export */ "filenameExtension": () => (/* binding */ filenameExtension),
/* harmony export */ "dirname": () => (/* binding */ dirname)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Utility functions for filenames and paths.
*/
/**
* Returns the basename of a path.
*
* @param {string} path A path.
* @return {string} The basename of the given path.
*/
function basename(path) {
return path.split(/[\\/]/).pop();
}
/**
* Returns info about a path.
*
* @param {string} path The path.
* @param {number} [options] Optioanl options flag.
*/
function pathinfo(path, options) {
// discuss at: http://locutus.io/php/pathinfo/
// original by: Nate
// revised by: Kevin van Zonneveld (http://kvz.io)
// improved by: Brett Zamir (http://brett-zamir.me)
// improved by: Dmitry Gorelenkov
// input by: Timo
// note 1: Inspired by actual PHP source: php5-5.2.6/ext/standard/string.c line #1559
// note 1: The way the bitwise arguments are handled allows for greater flexibility
// note 1: & compatability. We might even standardize this
// note 1: code and use a similar approach for
// note 1: other bitwise PHP functions
// note 1: Locutus tries very hard to stay away from a core.js
// note 1: file with global dependencies, because we like
// note 1: that you can just take a couple of functions and be on your way.
// note 1: But by way we implemented this function,
// note 1: if you want you can still declare the PATHINFO_*
// note 1: yourself, and then you can use:
// note 1: pathinfo('/www/index.html', PATHINFO_BASENAME | PATHINFO_EXTENSION);
// note 1: which makes it fully compliant with PHP syntax.
// example 1: pathinfo('/www/htdocs/index.html', 1)
// returns 1: '/www/htdocs'
// example 2: pathinfo('/www/htdocs/index.html', 'PATHINFO_BASENAME')
// returns 2: 'index.html'
// example 3: pathinfo('/www/htdocs/index.html', 'PATHINFO_EXTENSION')
// returns 3: 'html'
// example 4: pathinfo('/www/htdocs/index.html', 'PATHINFO_FILENAME')
// returns 4: 'index'
// example 5: pathinfo('/www/htdocs/index.html', 2 | 4)
// returns 5: {basename: 'index.html', extension: 'html'}
// example 6: pathinfo('/www/htdocs/index.html', 'PATHINFO_ALL')
// returns 6: {dirname: '/www/htdocs', basename: 'index.html', extension: 'html', filename: 'index'}
// example 7: pathinfo('/www/htdocs/index.html')
// returns 7: {dirname: '/www/htdocs', basename: 'index.html', extension: 'html', filename: 'index'}
let opt = "";
let realOpt = "";
let optName = "";
let optTemp = 0;
const tmpArr = {};
let cnt = 0;
let i = 0;
let haveBasename = false;
let haveExtension = false;
let haveFilename = false;
// Input defaulting & sanitation
if (!path) {
return false;
}
if (!options) {
options = "PATHINFO_ALL";
}
// Initialize binary arguments. Both the string & integer (constant) input is
// allowed
const OPTS = {
PATHINFO_DIRNAME: 1,
PATHINFO_BASENAME: 2,
PATHINFO_EXTENSION: 4,
PATHINFO_FILENAME: 8,
PATHINFO_ALL: 0,
};
// PATHINFO_ALL sums up all previously defined PATHINFOs (could just pre-calculate)
for (optName in OPTS) {
if (Object.prototype.hasOwnProperty.call(OPTS, optName)) {
OPTS.PATHINFO_ALL = OPTS.PATHINFO_ALL | OPTS[optName];
}
}
if (typeof options !== "number") {
// Allow for a single string or an array of string flags
options = [].concat(options);
for (i = 0; i < options.length; i++) {
// Resolve string input to bitwise e.g. 'PATHINFO_EXTENSION' becomes 4
if (OPTS[options[i]]) {
optTemp = optTemp | OPTS[options[i]];
}
}
options = optTemp;
}
// Internal Functions
const _getExt = function (path) {
const str = path + "";
const dotP = str.lastIndexOf(".") + 1;
return !dotP ? false : dotP !== str.length ? str.substr(dotP) : "";
};
// Gather path infos
if (options & OPTS.PATHINFO_DIRNAME) {
const dirName = path.replace(/\\/g, "/").replace(/\/[^/]*\/?$/, ""); // dirname
tmpArr.dirname = dirName === path ? "." : dirName;
}
if (options & OPTS.PATHINFO_BASENAME) {
if (haveBasename === false) {
haveBasename = basename(path);
}
tmpArr.basename = haveBasename;
}
if (options & OPTS.PATHINFO_EXTENSION) {
if (haveBasename === false) {
haveBasename = basename(path);
}
if (haveExtension === false) {
haveExtension = _getExt(haveBasename);
}
if (haveExtension !== false) {
tmpArr.extension = haveExtension;
}
}
if (options & OPTS.PATHINFO_FILENAME) {
if (haveBasename === false) {
haveBasename = basename(path);
}
if (haveExtension === false) {
haveExtension = _getExt(haveBasename);
}
if (haveFilename === false) {
haveFilename = haveBasename.slice(
0,
haveBasename.length -
(haveExtension
? haveExtension.length + 1
: haveExtension === false
? 0
: 1)
);
}
tmpArr.filename = haveFilename;
}
// If array contains only 1 element: return string
cnt = 0;
for (opt in tmpArr) {
if (Object.prototype.hasOwnProperty.call(tmpArr, opt)) {
cnt++;
realOpt = opt;
}
}
if (cnt === 1) {
return tmpArr[realOpt];
}
// Return full-blown array
return tmpArr;
}
/**
* Returns the extension of a filename.
*
* @param {string} filename The filename.
* @return {string} The extension of the given filename.
*/
function filenameExtension(filename) {
const extension = pathinfo(filename, "PATHINFO_EXTENSION");
if (typeof extension !== "string") {
return "";
}
return extension;
}
/**
* Returns the dirname of a path.
*
* @param {string} path A path.
* @return {string} The dirname of the given path.
*/
function dirname(path) {
// discuss at: http://locutus.io/php/dirname/
// original by: Ozh
// improved by: XoraX (http://www.xorax.info)
// example 1: dirname('/etc/passwd')
// returns 1: '/etc'
// example 2: dirname('c:/Temp/x')
// returns 2: 'c:/Temp'
// example 3: dirname('/dir/test/')
// returns 3: '/dir'
return path.replace(/\\/g, "/").replace(/\/[^/]*\/?$/, "");
}
/***/ }),
/***/ "./src/modules/promise.js":
/*!********************************!*\
!*** ./src/modules/promise.js ***!
\********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "timeout": () => (/* binding */ timeout),
/* harmony export */ "minDelayPromise": () => (/* binding */ minDelayPromise),
/* harmony export */ "maxDelayFallbackPromise": () => (/* binding */ maxDelayFallbackPromise),
/* harmony export */ "applyAsync": () => (/* binding */ applyAsync),
/* harmony export */ "composeAsync": () => (/* binding */ composeAsync),
/* harmony export */ "asSoonAtLeastSomeFulfilled": () => (/* binding */ asSoonAtLeastSomeFulfilled)
/* harmony export */ });
/* harmony import */ var _core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./core */ "./src/modules/core/index.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Promise-related utility functions.
*/
/**
* Creates a new timeout promise which will resolve after the given milliseconds timeout.
*
* @param {number} delayMs Delay in milliseconds after which the promise will resolve.
* @param {*} [value] Optional value to resolve with.
* @return {Promise} A new promise which resolves right after "delayMs" have elapsed.
*/
function timeout(delayMs, value) {
return new Promise(resolve => setTimeout(resolve, delayMs, value));
}
/**
* Creates a new promise with a minimum delay before it is fulfilled.
*
* @param {Promise} promise A promise.
* @param {number} minDelay Minumum delay in milliseconds.
* @return {Promise} A new promise which resolves with the given value of the given promise
* or rejects with the rejected value of the promise if it rejects.
*/
function minDelayPromise(promise, minDelay) {
return Promise.all([promise, timeout(minDelay)])
.then(([value]) => {
return value;
})
.catch(e => {
throw e;
});
}
/**
* Resolves a promise with an optional fallback which fires if the promise does not resolve
* under a certain time constraint.
*
* @param {Object} obj An object.
* @param {Promise} obj.promise A promise.
* @param {number} obj.maxDelayMs Max delay in milliseconds to wait before executing "onFallback" code if the time elapses.
* @param {Function} obj.onFallback Function to execute if the given "promise" takes more than "maxDelayMs" to resolve.
* @param {number} obj.fallbackMinDelayMs Number of milliseconds to wait if the fallback code gets executed before resolving the promise.
* @return {Promise} A promise which resolves with the value of "promise" or rejects with the error of the given "promise".
*/
function maxDelayFallbackPromise({
promise,
maxDelayMs,
// eslint-disable-next-line @typescript-eslint/no-empty-function
onFallback = () => {},
fallbackMinDelayMs,
} = {}) {
const uniqueIdentifier = (0,_core__WEBPACK_IMPORTED_MODULE_0__.uniqueId)();
return Promise.race([
promise,
timeout(maxDelayMs).then(() => uniqueIdentifier),
]).then(value => {
if (value === uniqueIdentifier) {
onFallback();
return minDelayPromise(promise, fallbackMinDelayMs);
} else {
return value;
}
});
}
/**
* Applies an async operation to a promise returning a new one.
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Composition
*
* @param {Promise} acc A promise.
* @param {Function} onfulfilled Fulfilled callback.
* @param {Function} onrejected Rejected callback.
* @return {Promise} A new promise.
*/
const applyAsync = (acc, onfulfilled, onrejected) => {
return typeof onrejected !== "undefined"
? acc.then(onfulfilled, onrejected)
: acc.then(onfulfilled);
};
/**
* Composes functions which are run subsequently
* (sequential composition) using promises.
*
* This function is useful when a chain of operations is known ahead of time
* and they must be executed subsequently.
*
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises#Composition
*
* @param {...(Function|Array)} funcs The functions (fulfilled callbacks). An array can be given and it MUST have
* the fulfilled callback at index 0 and the reject callback at index 1.
* @return {Function} A new function that accepts an initial value to be passed through the composition pipeline.
* If the returned function is called, it will return a Promise which represents the chain formed
* by the promises composed subsequently.
*/
const composeAsync = (...funcs) => x => {
return funcs.reduce((acc, func) => {
let promise;
if ((0,_core__WEBPACK_IMPORTED_MODULE_0__.isArray)(func)) {
// Item at index 0 is the fulfilled callback,
// while the item at index 1 is the reject callback.
promise = applyAsync(acc, func[0], func[1]);
} else {
promise = applyAsync(acc, func);
}
return promise;
}, Promise.resolve(x));
};
/**
* Returns a promise which resolves as soon as at least some of the promises given as parameter are fulfilled,
* and rejects if the minimum number of resolved promises ("minNumberOfFulfilledPromises") is not reached after all the given promises are settled.
*
* @param {Promise[]} promises An array of promises. If an empty array is given, then the returned promise will never resolve (will remain in pending state forever).
* @param {number} minNumberOfFulfilledPromises The minimum number of the given promises that must be fulfilled to consider the returned promise fulfilled
* (e.g. at least 3 of the given promises must be fulfilled).
* Defaults to 1.
* If "minNumberOfFulfilledPromises" is less than 0, then it is treated as if it was 1.
* If "minNumberOfFulfilledPromises" is greater than the number of the given promises "promises",
* then "minNumberOfFulfilledPromises" is treated as if it was "promises.length".
* @return {Promise} A new promise. The promise either fulfills or rejects with an object having the following properties:
*
* - fulfilled: An array, each element being an object having the following properties:
*
* - promise: The fulfilled promise of the array of promises "promises";
* - value: The value that the promise has resolved with;
* - index: The positional index of the given array of promises "promises";
*
* - rejected: An array, each element being an object having the following properties:
*
* - promise: The rejected promise of the array of promises "promises";
* - reason: The reason that the promise has rejected with;
* - index: The positional index of the given array of promises "promises";
*
* The "fulfilled" array will have "minNumberOfFulfilledPromises" elements.
*/
const asSoonAtLeastSomeFulfilled = (
promises,
minNumberOfFulfilledPromises = 1
) => {
const length = promises.length;
const unresolvablePromise = new Promise(_core__WEBPACK_IMPORTED_MODULE_0__.noOpFn);
let promiseToReturn = unresolvablePromise;
if (minNumberOfFulfilledPromises < 0) {
minNumberOfFulfilledPromises = 1;
} else if (minNumberOfFulfilledPromises > length) {
minNumberOfFulfilledPromises = length;
}
if (length > 0) {
let settledCount = 0;
let isPromiseSettled = false;
promiseToReturn = new Promise((resolve, reject) => {
const fulfilled = [];
const rejected = [];
promises.map((promise, index) => {
let isFulfilled = false;
promise
.then(value => {
if (!isPromiseSettled) {
isFulfilled = true;
settledCount++;
fulfilled.push({
promise,
index,
value,
});
if (fulfilled.length === minNumberOfFulfilledPromises) {
isPromiseSettled = true;
resolve({ fulfilled, rejected });
}
}
})
.catch(reason => {
if (!isPromiseSettled) {
if (!isFulfilled) {
settledCount++;
rejected.push({ promise, index, reason });
if (settledCount === length) {
isPromiseSettled = true;
reject({ fulfilled, rejected });
}
}
}
});
});
});
}
return promiseToReturn;
};
/***/ }),
/***/ "./src/modules/rand.js":
/*!*****************************!*\
!*** ./src/modules/rand.js ***!
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "randomStr": () => (/* binding */ randomStr),
/* harmony export */ "randomInt": () => (/* binding */ randomInt),
/* harmony export */ "randomFloat": () => (/* binding */ randomFloat),
/* harmony export */ "randomDifferentFromValue": () => (/* binding */ randomDifferentFromValue),
/* harmony export */ "uuid": () => (/* binding */ uuid),
/* harmony export */ "noncanonicalUUID": () => (/* binding */ noncanonicalUUID),
/* harmony export */ "randomArrayShuffle": () => (/* binding */ randomArrayShuffle),
/* harmony export */ "randomString": () => (/* binding */ randomString)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Utility functions providing random functionality.
*/
/**
* Generates a random string.
*
* @param {number} length The length of the string to return.
* @return {string} The random string.
*/
function randomStr(length) {
let result = "";
const characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
const charactersLength = characters.length;
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
/**
* Generates a random int between min and max (both included).
*
* @param {number} min Min int value.
* @param {number} max Max int value.
* @return {number} A random int between min and max.
*/
function randomInt(min = 0, max = Number.MAX_SAFE_INTEGER) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
/**
* Generates a random float between min and max integers (both included).
*
* @param {number} min Min int value.
* @param {number} max Max int value.
* @return {number} A random float between min and max.
*/
function randomFloat(min = 0, max = 562949953421311) {
const randInt = randomInt(min, max);
if (randInt >= max) {
return randInt;
}
return randInt + Math.random();
}
/**
* Returns a random float (using "Math.random()") not equal to the given value.
*
* @param {number} value The given value.
* @return {number} A random float not equal to value.
*/
function randomDifferentFromValue(value) {
let ret = Math.random();
while (value == ret) {
ret = Math.random();
}
return ret;
}
/**
* @type {Array}
*/
let noncanonicalUUIDCounter = 1;
/**
* Generates a new UUID.
*
* @see https://github.com/tastejs/todomvc/blob/gh-pages/examples/react/js/utils.js
*
* @return {string} The UUID.
*/
function uuid() {
let i, random;
let uuid = "";
for (i = 0; i < 32; i++) {
random = (Math.random() * 16) | 0;
if (i === 8 || i === 12 || i === 16 || i === 20) {
uuid += "-";
}
uuid += (i === 12 ? 4 : i === 16 ? (random & 3) | 8 : random).toString(16);
}
return uuid;
}
/**
* Generates a new noncanonical UUID. This noncanonical UUID has a further
* int prefixed by "-" which is concatenated to a canonical UUID at the end
* of the canonical UUID before returning this noncanonical UUID.
* The int starts with 1 and increments every time this function is called.
*
* @return {string} A noncanonical UUID.
*/
function noncanonicalUUID() {
const UUID = uuid();
return UUID + "-" + noncanonicalUUIDCounter++;
}
/**
* Shuffles an array randomly modifing the given array.
*
* @param {Array} array The input array.
* @return {Array} A reference to the same array given as input,
* but with its elements randomly shuffled.
*/
const shuffleArrayRandomly = array => {
let i = array.length,
temporaryValue,
randomIndex;
while (0 !== i) {
randomIndex = Math.floor(Math.random() * i);
i--;
temporaryValue = array[i];
array[i] = array[randomIndex];
array[randomIndex] = temporaryValue;
}
return array;
};
/**
* Returns an array with the elements of the given array randomly shuffled.
*
* @param {Array} array An array.
* @return {Array} A new array with the same elements of the input array, but randomly shuffled.
*/
function randomArrayShuffle(array) {
return shuffleArrayRandomly(Object.keys(array)).map(i => array[i]);
}
/**
* Generates a random string.
*
* @return {string} A random string.
*/
const randomString = () => Math.random().toString(36).substr(2);
/***/ }),
/***/ "./src/modules/stats.js":
/*!******************************!*\
!*** ./src/modules/stats.js ***!
\******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "mean": () => (/* binding */ mean),
/* harmony export */ "median": () => (/* binding */ median),
/* harmony export */ "minAbsDeviationFromValue": () => (/* binding */ minAbsDeviationFromValue),
/* harmony export */ "minAbsDeviationFromExcludedValue": () => (/* binding */ minAbsDeviationFromExcludedValue)
/* harmony export */ });
/* harmony import */ var _math__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./math */ "./src/modules/math.js");
/* harmony import */ var _array__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./array */ "./src/modules/array.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Statistics-related utility functions.
*/
/**
* Computes the mean of the given numbers.
*
* @param {...number} numbers The numbers.
* @return {number} The mean.
*/
function mean(...numbers) {
return (0,_math__WEBPACK_IMPORTED_MODULE_0__.sum)(...numbers) / numbers.length;
}
/**
* Computes the median of the given numbers.
*
* @param {...number} numbers The numbers.
* @return {number} The median value.
*/
function median(...numbers) {
const sorted = (0,_array__WEBPACK_IMPORTED_MODULE_1__.sortNums)(numbers);
const middleIndex = (0,_math__WEBPACK_IMPORTED_MODULE_0__.intDiv)(sorted.length, 2);
return (0,_math__WEBPACK_IMPORTED_MODULE_0__.isOdd)(sorted.length)
? sorted[middleIndex]
: mean(sorted[middleIndex - 1], sorted[middleIndex]);
}
/**
* Computes the min deviation from a value.
*
* @param {number} value A value.
* @return {(...numbers: number[]) => number} A function receiving the numbers to use to compute the minimum deviation
* from "value".
*/
const minAbsDeviationFromValue = value => (...numbers) => {
let minAbsDeviation = Infinity;
numbers.map(num => {
const deviation = Math.abs(num - value);
if (deviation < minAbsDeviation) {
minAbsDeviation = deviation;
}
});
return minAbsDeviation;
};
/**
* Computes the min deviation from a value excluding that value from the numbers received.
*
* @param {number} value A value.
* @return {(...numbers: number[]) => number} A function receiving the numbers to use to compute the minimum deviation
* from "value" exluding "value".
*/
const minAbsDeviationFromExcludedValue = value => (...numbers) =>
minAbsDeviationFromValue(value)(...numbers.filter(num => num !== value));
/***/ }),
/***/ "./src/modules/string.js":
/*!*******************************!*\
!*** ./src/modules/string.js ***!
\*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "escapeRegExp": () => (/* binding */ escapeRegExp),
/* harmony export */ "trimCharacterMask": () => (/* binding */ trimCharacterMask),
/* harmony export */ "trimCharacterRegex": () => (/* binding */ trimCharacterRegex),
/* harmony export */ "trim": () => (/* binding */ trim),
/* harmony export */ "trimLeft": () => (/* binding */ trimLeft),
/* harmony export */ "trimRight": () => (/* binding */ trimRight),
/* harmony export */ "concatWithInnerOuterSeparators": () => (/* binding */ concatWithInnerOuterSeparators),
/* harmony export */ "optionsValueLabel": () => (/* binding */ optionsValueLabel),
/* harmony export */ "startsWith": () => (/* binding */ startsWith),
/* harmony export */ "ucaseFirst": () => (/* binding */ ucaseFirst),
/* harmony export */ "reverseString": () => (/* binding */ reverseString),
/* harmony export */ "separateIntThousands": () => (/* binding */ separateIntThousands)
/* harmony export */ });
/* harmony import */ var _core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./core */ "./src/modules/core/index.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Utility functions for working with strings.
*/
/**
* Escapes special characters for a JS regex.
*
* @see https://stackoverflow.com/questions/3115150/how-to-escape-regular-expression-special-characters-using-javascript#answer-9310752
*
* @param {string} text The string to escape.
* @return {string} The same string with special regex characters escaped.
*/
function escapeRegExp(text) {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
}
/**
* Trim characters from the beginning and end of a string.
*
* @param {string} str The string.
* @param {string} characterMask Character mask.
* @param {Object} options Options.
* @param {Object.boolean} options.shouldTrimLeft "true" to trim left (defaults to "true" if omitted).
* @param {Object.boolean} options.shouldTrimRight "true" to trim right (defaults to "true" if omitted).
* @return {string} The trimmed string.
*/
function trimCharacterMask(str, characterMask, options = {}) {
if (typeof characterMask === "undefined") {
characterMask = " ";
}
const escapedCharacterMask = escapeRegExp(characterMask);
const shouldTrimLeft =
typeof options.shouldTrimLeft === "undefined" || options.shouldTrimLeft;
const shouldTrimRight =
typeof options.shouldTrimRight === "undefined" || options.shouldTrimRight;
const regexParts = [];
if (shouldTrimLeft) {
regexParts[regexParts.length] = "^[" + escapedCharacterMask + "]+";
}
if (shouldTrimRight) {
regexParts[regexParts.length] = "[" + escapedCharacterMask + "]+$";
}
const regex = new RegExp(regexParts.join("|"), "gm");
return str.replace(regex, "");
}
/**
* Trim characters from the beginning and end of a string using an array
* of regex characters.
*
* @param {string} str The string.
* @param {string} regexCharacters Regex characters.
* @param {string} additionalModifiers Additional regex modifiers.
* @return {string} The trimmed string.
*/
function trimCharacterRegex(str, regexCharacters, additionalModifiers) {
if (typeof regexCharacters === "undefined") {
regexCharacters = ["\\s"];
}
additionalModifiers = additionalModifiers || "";
const regex = new RegExp(
"(^(" +
regexCharacters.join("|") +
")+)|((" +
regexCharacters.join("|") +
")+$)",
"g" + additionalModifiers
);
return str.replace(regex, "");
}
/**
* Alias of "trimCharacterMask".
* Trim characters from the beginning and end of a string.
*
* @param {string} str The string.
* @param {string} characterMask Character mask.
* @return {string} The trimmed string.
*/
function trim(str, characterMask) {
return trimCharacterMask(str, characterMask);
}
/**
* Trim characters from the beginning of a string.
*
* @param {string} str The string.
* @param {string} characterMask Character mask.
* @return {string} The left-trimmed string.
*/
function trimLeft(str, characterMask) {
return trimCharacterMask(str, characterMask, {
shouldTrimLeft: true,
shouldTrimRight: false,
});
}
/**
* Trim characters from the end of a string.
*
* @param {string} str The string.
* @param {string} characterMask Character mask.
* @return {string} The right-trimmed string.
*/
function trimRight(str, characterMask) {
return trimCharacterMask(str, characterMask, {
shouldTrimLeft: false,
shouldTrimRight: true,
});
}
/**
* Concats the values of an array with an outer separator using an inner separator
* for first nesting level arrays.
*
* E.g.:
*
* concatWithInnerOuterSeparators(["a", "value", ["with", "nested", "value"], "etc"], " # ", " $ ")
* // Returns:
* "a # value # with $ nested $ value # etc"
*
* @param {Array<string>|Array<Array<string>>} arrayToConcat An array of strings or arrays or strings.
* @param {string} outerSeparator Outer separator.
* @param {string} innerSeparator Inner separator.
* @return {string} The concatenated string.
*/
function concatWithInnerOuterSeparators(
arrayToConcat,
outerSeparator = " ",
innerSeparator = " "
) {
const toConcatFinally = [];
for (const value of arrayToConcat) {
if ((0,_core__WEBPACK_IMPORTED_MODULE_0__.isArray)(value)) {
toConcatFinally[toConcatFinally.length] = trim(
value.join(innerSeparator),
innerSeparator
);
} else {
toConcatFinally[toConcatFinally.length] = value;
}
}
const ret = trim(toConcatFinally.join(outerSeparator), outerSeparator);
return ret;
}
/**
* Returns an array of options with a value and a label string.
*
* @param {Object} obj An object with parameters.
* @param {Object[]} obj.arrayOfObjects An array of objects.
* @param {string[]|Array.<string|string[]>} obj.concatObjectProps Properties, keys of each object to use for the label
* and to concat with "outerSeparator".
* A nested array of properties can be used to specify an inner
* part of the label to concat using the "innerSeparator".
* @param {string} obj.valueProp Name of the property which value has to be used for the value property
* of the returned array of objects.
* @param {string} obj.outerSeparator Outer separator.
* @param {string} obj.innerSeparator Inner separator.
* @return {Object[]} Array of objects, each object with two properties:
*
* - "value": The value of the object;
* - "label": The label of the object.
*
*/
function optionsValueLabel({
arrayOfObjects,
concatObjectProps,
valueProp = "id",
outerSeparator = " ",
innerSeparator = " ",
}) {
const options = [];
for (const obj of arrayOfObjects) {
const arrayToConcat = [];
for (const prop of concatObjectProps) {
if ((0,_core__WEBPACK_IMPORTED_MODULE_0__.isArray)(prop)) {
arrayToConcat[arrayToConcat.length] = prop.map(
propName => obj[propName]
);
} else {
arrayToConcat[arrayToConcat.length] = obj[prop];
}
}
options[options.length] = {
value: obj[valueProp],
label: concatWithInnerOuterSeparators(
arrayToConcat,
outerSeparator,
innerSeparator
),
};
}
return options;
}
/**
* Tests if a string starts with another
*
* @param {string} haystack The haystack string.
* @param {string} needle The needle string.
* @return {boolean} True if the haystack string starts with needle, false otherwise.
*/
function startsWith(haystack, needle) {
return haystack.indexOf(needle, 0) === 0;
}
/**
* Makes the first character of the given string uppercase.
*
* @param {string} string A string.
* @return {string} The string with its first character made uppercase.
*/
function ucaseFirst(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
/**
* Reverses a string.
*
* @param {string} string A string to reverse.
* @return {string} The reversed string.
*/
function reverseString(string) {
return string.split("").reverse().join("");
}
/**
* Given an integer, returns a string containing the same integer with additional thousands separators.
*
* @param {number} num An integer.
* @param {string} [sep] The thousands separator to use.
* @return {string} The same integer with thousands separators.
*/
function separateIntThousands(num, sep = ",") {
return num
.toString()
.split("")
.reverse()
.map((d, i, a) =>
(i + 1) % 3 === 0 && i !== a.length - 1 ? `${sep}${d}` : d
)
.reverse()
.join("");
}
/***/ }),
/***/ "./src/modules/time.js":
/*!*****************************!*\
!*** ./src/modules/time.js ***!
\*****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "time": () => (/* binding */ time),
/* harmony export */ "msToTime": () => (/* binding */ msToTime),
/* harmony export */ "millisecToSec": () => (/* binding */ millisecToSec),
/* harmony export */ "secondsToTimeString": () => (/* binding */ secondsToTimeString)
/* harmony export */ });
/* harmony import */ var _core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./core */ "./src/modules/core/index.js");
/* harmony import */ var _math__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./math */ "./src/modules/math.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Time-related utility functions.
*/
/**
* Returns the current Unix time in seconds.
*
* @return {number} Current Unix time in seconds.
*/
function time() {
const d = new Date();
const seconds = Math.round(d.getTime() / 1000);
return seconds;
}
/**
* Returns the time string approximated to the nearest microsecond
* corresponding the given Unix timestamp in milliseconds
* in the format "HH:mm:ss.ms".
*
* @param {number} [ms] The time in microseconds to convert into a string.
* If omitted, the current time will be used.
* @return {string} The time string.
*/
function msToTime(ms) {
const date = new Date(ms || new Date().getTime());
const isoDate = new Date(
date.getTime() - date.getTimezoneOffset() * 60000
).toISOString();
return isoDate.slice(11, -1);
}
/**
* Converts milliseconds to seconds.
*
* @param {number} millisec Number of milliseconds.
* @return {number} The milliseconds in seconds.
*/
function millisecToSec(millisec) {
return millisec * 0.001;
}
/**
* Converts seconds to a `minutes:seconds` or `hours:minutes:seconds` time string
* (if the second parameter is an object with `includeHours` set to a truthy value),
* e.g. `123` becomes `"02:03"`, or `"00:02:03"` if `includeHours` is truthy.
*
* @param {number} secs The number of seconds.
* @param {Object} options Options.
* @param {Object.boolean} options.includeHours "true" to include hours (defaults to "false" if omitted).
* @return {string} The time string.
*/
const secondsToTimeString = (secs, { includeHours = false } = {}) => {
if (!secs || !(0,_core__WEBPACK_IMPORTED_MODULE_0__.isIntegerOrIntegerStr)(secs)) {
return includeHours ? "00:00:00" : "00:00";
}
let hours = "";
let minutes = (0,_math__WEBPACK_IMPORTED_MODULE_1__.intDiv)(secs, 60);
if (includeHours) {
hours = `${((0,_math__WEBPACK_IMPORTED_MODULE_1__.intDiv)(secs, 60 * 60) + "").padStart(2, "0")}:`;
minutes = minutes % 60;
}
minutes += "";
const seconds = (secs % 60) + "";
return `${hours}${minutes.padStart(2, "0")}:${seconds.padStart(2, "0")}`;
};
/***/ }),
/***/ "./src/modules/validate.js":
/*!*********************************!*\
!*** ./src/modules/validate.js ***!
\*********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "isValidHttpUrl": () => (/* binding */ isValidHttpUrl)
/* harmony export */ });
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Returns true if the given string is a valid HTTP URL (either HTTP or HTTPS).
*
* @see https://regex101.com/r/HjBD9T/1
*
* @param {string} maybeValidHttpUrl A string that's maybe a valid HTTP URL.
* @return {boolean} True if the given string is a valid HTTP URL, false otherwise.
*/
function isValidHttpUrl(maybeValidHttpUrl) {
return /^(?:(?:https?:)\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})))(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(
maybeValidHttpUrl
);
}
/***/ }),
/***/ "./src/modules/web.js":
/*!****************************!*\
!*** ./src/modules/web.js ***!
\****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "buildQueryString": () => (/* binding */ buildQueryString),
/* harmony export */ "formData": () => (/* binding */ formData),
/* harmony export */ "xhr": () => (/* binding */ xhr),
/* harmony export */ "checkNetwork": () => (/* binding */ checkNetwork),
/* harmony export */ "waitNetwork": () => (/* binding */ waitNetwork),
/* harmony export */ "setCookie": () => (/* binding */ setCookie),
/* harmony export */ "getCookie": () => (/* binding */ getCookie),
/* harmony export */ "unsetCookie": () => (/* binding */ unsetCookie),
/* harmony export */ "isInViewport": () => (/* binding */ isInViewport),
/* harmony export */ "isScrolledIntoView": () => (/* binding */ isScrolledIntoView),
/* harmony export */ "hasVerticalScrollbar": () => (/* binding */ hasVerticalScrollbar),
/* harmony export */ "hasHorizontalScrollbar": () => (/* binding */ hasHorizontalScrollbar),
/* harmony export */ "elementUniqueId": () => (/* binding */ elementUniqueId),
/* harmony export */ "getElementComputedStyle": () => (/* binding */ getElementComputedStyle),
/* harmony export */ "elementInnerDimensions": () => (/* binding */ elementInnerDimensions),
/* harmony export */ "countTextareaLines": () => (/* binding */ countTextareaLines),
/* harmony export */ "isScrollOnBottom": () => (/* binding */ isScrollOnBottom),
/* harmony export */ "getVerticalScrollBarWidth": () => (/* binding */ getVerticalScrollBarWidth),
/* harmony export */ "isEllipsisActive": () => (/* binding */ isEllipsisActive),
/* harmony export */ "copyTextToClipboard": () => (/* binding */ copyTextToClipboard),
/* harmony export */ "rAFLooper": () => (/* binding */ rAFLooper),
/* harmony export */ "nestedRAF": () => (/* binding */ nestedRAF),
/* harmony export */ "getRawURIFragment": () => (/* binding */ getRawURIFragment),
/* harmony export */ "getDecodedURIFragment": () => (/* binding */ getDecodedURIFragment),
/* harmony export */ "appendEncodedJSONFragmentToURI": () => (/* binding */ appendEncodedJSONFragmentToURI),
/* harmony export */ "getDecodedJSONFromFragmentURI": () => (/* binding */ getDecodedJSONFromFragmentURI),
/* harmony export */ "parseQueryStringArgsMultiDim": () => (/* binding */ parseQueryStringArgsMultiDim),
/* harmony export */ "getQueryStringArgsMultiDim": () => (/* binding */ getQueryStringArgsMultiDim),
/* harmony export */ "cursorFocus": () => (/* binding */ cursorFocus),
/* harmony export */ "detectWrapped": () => (/* binding */ detectWrapped),
/* harmony export */ "maxNestingLevel": () => (/* binding */ maxNestingLevel),
/* harmony export */ "getScrollableAncestor": () => (/* binding */ getScrollableAncestor),
/* harmony export */ "smoothScrollToTop": () => (/* binding */ smoothScrollToTop),
/* harmony export */ "downloadFile": () => (/* binding */ downloadFile)
/* harmony export */ });
/* harmony import */ var _core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./core */ "./src/modules/core/index.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Web application (browser) utility functions.
*/
/**
* Builds a form data instance or object recursively.
*
* @see https://stackoverflow.com/questions/22783108/convert-js-object-to-form-data#answer-42483509
*
* @param {FormData|Object} formData Form data instance or JS POJO object.
* @param {Array|Object} data JS POJO object or array with the form data to use to build the forma data.
* @param {boolean} [shouldEncodeURIComponent] Optionally instructs the function if the parameters should be encoded
* (keys and values) using "encodeURIComponent".
* @param {string} [parentKey] Parent key for nested parameters (used internally for recursion).
* @return {undefined}
*/
function buildFormData(formData, data, shouldEncodeURIComponent, parentKey) {
if (
data &&
typeof data === "object" &&
!(data instanceof Date) &&
!(data instanceof File)
) {
Object.keys(data).forEach(key => {
buildFormData(
formData,
data[key],
shouldEncodeURIComponent,
parentKey
? `${parentKey}[${key}]`
: shouldEncodeURIComponent
? encodeURIComponent(key)
: key
);
});
} else {
// Leaf value.
const value =
data == null
? ""
: shouldEncodeURIComponent
? encodeURIComponent(data)
: data;
formData instanceof FormData
? formData.append(parentKey, value)
: (formData[parentKey] = value);
}
}
/**
* Constructs a query string from the given data.
* This method works with nested objects/arrays.
*
* @param {Array|Object} data The object.
* @return {string} The query string.
*/
function buildQueryString(data) {
const formData = {};
buildFormData(formData, data, true); // "true" instructs the function to encode URI parts (keys and values).
const parts = [];
for (const prop in formData) {
parts.push(prop + "=" + formData[prop]);
}
return parts.join("&");
}
/**
* Converts an object (array or JS POJO object) to a form data instance.
*
* @param {Array|Object} data The data (array or POJO object).
* @return {FormData} A form data instance.
*/
function formData(data) {
const formData = new FormData();
buildFormData(formData, data);
return formData;
}
/**
* Returns a new XMLHttpRequest or ActiveXObject object.
*
* @return {XMLHttpRequest|ActiveXObject}
*/
const xhr = () =>
(window.ActiveXObject && new window.ActiveXObject("Microsoft.XMLHTTP")) ||
new XMLHttpRequest();
/**
* Checks whether the network is reachable or not.
*
* @param {string} URI An eventual URI to use for the request.
* NOTE: If omitted, then "config.checkNetworkURI" will be used,
* or, if "config.checkNetworkURI" is not set,
* the website's hostname will be used.
* Also, in every case, A GET query string with a random parameter
* is always appended to the URI.
* @return {Promise} A promise which resolves to "true" if the network is reachable and to "false" otherwise.
* Note that the returned promise always resolves to "true" when this code runs on localhost.
*/
function checkNetwork(URI = null) {
// Handle IE and more capable browsers.
const xhrObj = xhr();
return new Promise(resolve => {
// Issue request and handle response.
try {
xhrObj.onreadystatechange = () => {
if (xhrObj.readyState == 4) {
resolve(
xhrObj.status >= 200 &&
(xhrObj.status < 300 || xhrObj.status === 304)
);
}
};
// Open new request as a HEAD to the root hostname with a random param to bust the cache.
xhrObj.open(
"HEAD",
(URI ||
_core__WEBPACK_IMPORTED_MODULE_0__.config.checkNetworkURI ||
"//" +
window.location.hostname +
(window.location.port != 80 ? ":" + window.location.port : "")) +
"?rand=" +
Math.floor((1 + Math.random()) * 0x10000), // 0x10000 = 2^16
true
);
xhrObj.send();
} catch (error) {
resolve(false);
}
});
}
/**
* Returns a promise which resolves when the network is available.
*
* NOTE: If the network is available, the promise will resolve almost immediately.
*
* @param {number} intervalMillisecs An interval in milliseconds to wait before the next network check.
* @return {Promise} A promise.
*/
function waitNetwork(intervalMillisecs = 3000) {
return new Promise(resolve => {
checkNetwork().then(isNetworkReachable => {
if (isNetworkReachable) {
resolve();
} else {
const interval = setInterval(() => {
checkNetwork().then(isNetworkReachable => {
if (isNetworkReachable) {
clearInterval(interval);
resolve();
}
});
}, intervalMillisecs);
}
});
});
}
/**
* Sets a cookie value.
*
* @see https://www.w3schools.com/js/js_cookies.asp
*
* @param {string} cname The cookie name.
* @param {string} cvalue The cookie value.
* @param {number|undefined} exdays Number of days after which the cookie expires,
* or "undefined" to make the cookie expire at the end of the session.
* @return {undefined}
*/
function setCookie(cname, cvalue, exdays) {
let expires = "";
if (exdays) {
const d = new Date();
d.setTime(d.getTime() + exdays * 24 * 60 * 60 * 1000);
expires = "expires=" + d.toUTCString() + ";";
}
document.cookie = cname + "=" + cvalue + ";" + expires + "path=/";
}
/**
* Gets a cookie value.
*
* @see https://www.w3schools.com/js/js_cookies.asp
*
* @param {string} cname The cookie name.
* @return {string|undefined} The cookie value or "undefined", if not set.
*/
function getCookie(cname) {
const name = cname + "=";
const ca = document.cookie.split(";");
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) == " ") {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length, c.length);
}
}
return void 0;
}
/**
* Unsets a cookie.
*
* @param {string} cname The cookie name.
* @return {undefined}
*/
function unsetCookie(cname) {
setCookie(cname, "", -365);
}
/**
* Tests whether a DOM element is in viewport or not.
*
* @param {Element} elem The DOM element.
* @return {boolean} True if it is in viewport, false otherwise.
*/
function isInViewport(elem) {
const bounding = elem.getBoundingClientRect();
return (
bounding.top >= 0 &&
bounding.left >= 0 &&
bounding.bottom <=
(window.innerHeight || document.documentElement.clientHeight) &&
bounding.right <=
(window.innerWidth || document.documentElement.clientWidth)
);
}
/**
* Tests if a DOM element is scrolled into the scrollable view of its parent scrollable container.
*
* @param {Element} elem The DOM element to test.
* @param {Element} holder The DOM element of the scrollable container of the DOM element to test.
* @param {number|Function} minPx Minimum number of pixels of the element's height which must be scrolled into the view
* in order to consider the element to be scrolled into view.
* If a function is given, it will receive the element's bounding client rect as the first argument
* as well as the holder element's bounding client rect as the second argument and must return
* the minimum number of pixels.
* @return {boolean} True if the given element is scrolled into view, false otherwise.
*/
function isScrolledIntoView(el, holder, minPx = 1) {
const elRect = el.getBoundingClientRect();
const holderRect = holder.getBoundingClientRect();
const { top, bottom, height } = elRect;
const minPxNumberFn = () =>
typeof minPx === "function" ? minPx(elRect, holderRect) : minPx;
let bottomDiff;
return top <= holderRect.top
? holderRect.top - top + minPxNumberFn() <= height
: (bottomDiff = bottom - holderRect.bottom) < 0
? true
: holderRect.bottom >= top && minPx
? holderRect.bottom - top >= minPxNumberFn()
: bottomDiff <= height;
}
/**
* Tests if a DOM element has a vertical scrollbar.
*
* @param {Element} elem The DOM element.
* @return {boolean} True it has a vertical scrollbar, false otherwise.
*/
function hasVerticalScrollbar(elem) {
const hasVerticalScrollbar = elem.scrollHeight > elem.clientHeight;
return hasVerticalScrollbar;
}
/**
* Tests if a DOM element has a horizontal scrollbar.
*
* @param {Element} elem The DOM element.
* @return {boolean} True it has a horizontal scrollbar, false otherwise.
*/
function hasHorizontalScrollbar(elem) {
const hasHorizontalScrollbar = elem.scrollWidth > elem.clientWidth;
return hasHorizontalScrollbar;
}
/**
* Generates a unique ID which can be used for an element.
*
* @param {string|undefined} [elementUniqueIdPrefix] Local unique ID prefix which overrides the prefix
* set on the "config" configuration object.
* @return {string} The element unique ID.
*/
function elementUniqueId(elementUniqueIdPrefix = void 0) {
const uniqueElementIdSuffix = (0,_core__WEBPACK_IMPORTED_MODULE_0__.uniqueId)();
return (
(elementUniqueIdPrefix || _core__WEBPACK_IMPORTED_MODULE_0__.config.elementUniqueIdPrefix) +
uniqueElementIdSuffix
);
}
/**
* Gets the computed style of an element.
*
* @param {Element} element DOM element.
* @return {CSSStyleDeclaration} The computed style.
*/
function getElementComputedStyle(element) {
return window.getComputedStyle(element);
}
/**
* Gets element's inner dimensions (height and width without padding).
*
* @param {Element} element An element.
* @return {Object} An object with "width" and "height" properties.
*/
function elementInnerDimensions(element) {
const computedStyle = getElementComputedStyle(element);
let elementHeight = element.clientHeight; // Height with padding.
let elementWidth = element.clientWidth; // Width with padding
elementHeight -=
parseFloat(computedStyle.paddingTop) +
parseFloat(computedStyle.paddingBottom);
elementWidth -=
parseFloat(computedStyle.paddingLeft) +
parseFloat(computedStyle.paddingRight);
return {
width: elementWidth,
height: elementHeight,
};
}
/**
* @type {HTMLTextAreaElement}
*/
let countTextareaLinesBuffer;
/**
* Returns the number of lines in a textarea, including wrapped lines.
*
* @see https://stackoverflow.com/questions/28905965/textarea-how-to-count-wrapped-lines-rows#answer-45252226
*
* @param {HTMLTextAreaElement} textarea A textarea element. Note that the textarea should have an integer line height
* to avoid rounding errors.
*/
function countTextareaLines(textarea) {
if (countTextareaLinesBuffer == null) {
countTextareaLinesBuffer = document.createElement("textarea");
countTextareaLinesBuffer.style.border = "none";
countTextareaLinesBuffer.style.height = "0";
countTextareaLinesBuffer.style.overflow = "hidden";
countTextareaLinesBuffer.style.padding = "0";
countTextareaLinesBuffer.style.position = "absolute";
countTextareaLinesBuffer.style.left = "0";
countTextareaLinesBuffer.style.top = "0";
countTextareaLinesBuffer.style.zIndex = "-1";
document.body.appendChild(countTextareaLinesBuffer);
}
const cs = window.getComputedStyle(textarea);
const pl = parseInt(cs.paddingLeft);
const pr = parseInt(cs.paddingRight);
let lh = parseInt(cs.lineHeight);
// `cs.lineHeight` may return 'normal', which means line height = font size.
if (isNaN(lh)) lh = parseInt(cs.fontSize);
// Copy content width.
countTextareaLinesBuffer.style.width = textarea.clientWidth - pl - pr + "px";
// Copy text properties.
countTextareaLinesBuffer.style.font = cs.font;
countTextareaLinesBuffer.style.letterSpacing = cs.letterSpacing;
countTextareaLinesBuffer.style.whiteSpace = cs.whiteSpace;
countTextareaLinesBuffer.style.wordBreak = cs.wordBreak;
countTextareaLinesBuffer.style.wordSpacing = cs.wordSpacing;
countTextareaLinesBuffer.style.wordWrap = cs.wordWrap;
// Copy value.
countTextareaLinesBuffer.value = textarea.value;
let result = Math.floor(countTextareaLinesBuffer.scrollHeight / lh);
if (result == 0) {
result = 1;
}
return result;
}
/**
* Checks if the scroll of an element is on the bottom.
*
* @param {Element} DOMNode Element.
* @return {boolean} True if the scroll is on the bottom, false otherwise.
*/
function isScrollOnBottom(DOMNode) {
const ret = DOMNode.scrollTop + DOMNode.offsetHeight >= DOMNode.scrollHeight;
return ret;
}
/**
* Returns the default browser's vertical scrollbar width.
*
* @return {Number} The scrollbar width.
*/
function getVerticalScrollBarWidth() {
const scrollDiv = document.createElement("div");
scrollDiv.className = "vertical-scrollbar-measure";
const sheet = document.createElement("style");
sheet.innerHTML =
"div.vertical-scrollbar-measure { width: 100px; height: 100px; overflow: scroll; position: absolute; top: -9999px; }";
document.body.appendChild(sheet);
document.body.appendChild(scrollDiv);
const scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
document.body.removeChild(scrollDiv);
const sheetParent = sheet.parentNode;
sheetParent.removeChild(sheet);
return scrollbarWidth;
}
/**
* Tests if an element with "text-overflow: ellipsis;" has the ellipsis active
* and therefore its text is truncated.
*
* @param {Element} e The DOM element.
* @return {boolean} True if ellipsis are present, false otherwise.
*/
function isEllipsisActive(e) {
return e.offsetWidth < e.scrollWidth;
}
/**
* A fallback function to copy a text to clipboard.
*
* @param {string} text The text to copy.
* @param {Function} [onSuccess] An optional callback to execute on success.
* @param {Function} [onFailure] An optional callback to execute on failure.
* @return {undefined}
*/
function fallbackCopyTextToClipboard(text, onSuccess, onFailure) {
const bodyScrollTop =
document.documentElement.scrollTop || document.body.scrollTop;
const textArea = document.createElement("textarea");
textArea.value = text;
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
const successful = document.execCommand("copy");
if (successful) {
onSuccess && onSuccess();
} else {
onFailure && onFailure();
}
} catch (err) {
onFailure && onFailure(err);
}
(document.body.removeChild(textArea) &&
document.documentElement.scrollTop &&
(document.documentElement.scrollTop = bodyScrollTop)) ||
(document.body.scrollTop = bodyScrollTop);
}
/**
* Copies a text to clipboard.
*
* @param {string} text The text to copy.
* @param {Function} [onSuccess] An optional callback to execute on success.
* @param {Function} [onFailure] An optional callback to execute on failure.
* @return {undefined}
*/
function copyTextToClipboard(text, onSuccess, onFailure) {
if (!navigator.clipboard) {
fallbackCopyTextToClipboard(text, onSuccess, onFailure);
return;
}
navigator.clipboard.writeText(text).then(
function () {
onSuccess && onSuccess();
},
function (err) {
onFailure && onFailure(err);
}
);
}
/**
* Asynchronously invokes a callback multiple times, each in its own animation frame.
*
* @param {number} n The number of times the callback should be invoked.
* @param {Function} callback The callback to invoke.
* @return {*} The identifier of the first animation frame or "n" if it is falsy during the outermost call.
*/
const rAFLooper = (n, callback) =>
n &&
window.requestAnimationFrame(() => (callback(), rAFLooper(--n, callback)));
/**
* Requests a predefined number of animation frames and executes a callback after.
*
* @param {number} count The number of animation frames to request before executing the callback.
* @param {Function} callback The callback to execute after "count" animation frames have been requested.
* @return {number} The identifier of the first animation frame.
*/
const nestedRAF = (count, callback) => {
let c = count || 1;
const innerCallback = () => {
c--;
if (!c) {
callback();
return;
}
window.requestAnimationFrame(innerCallback);
};
return window.requestAnimationFrame(innerCallback);
};
/**
* Returns the raw contents of the URI fragment (i.e. everything after the hash ("#") character).
*
* @param {string} URIFragment The URI fragment.
* @return {string} The raw contents of the URI fragment.
*/
function getRawURIFragment(URIFragment) {
const fragment = (URIFragment || window.location.hash).replace(/^#/, "");
return fragment;
}
/**
* Returns the decoded contents of a URI fragment (i.e. everything after the hash ("#") character).
*
* @param {string} URIFragment The URI fragment.
* @return {string} The contents of the URI fragment, decoded.
*/
function getDecodedURIFragment(URIFragment) {
const fragment = decodeURIComponent(getRawURIFragment(URIFragment));
return fragment;
}
/**
* Appends an encoded JSON fragment to a URI.
*
* @param {string} URI The URI.
* @param {*} data Data to encode in JSON format.
*/
function appendEncodedJSONFragmentToURI(URI, data) {
return URI + "#" + encodeURIComponent(JSON.stringify(data));
}
/**
* Returnes the decoded JSON data eventually stored in the URI fragment.
*
* @param {*} defaultData Default data to return if either the URI fragment is missing or
* the content of the URI fragment is not a valid JSON-encoded string.
* @return {*} The decoded JSON data or "defaultData".
*/
function getDecodedJSONFromFragmentURI(defaultData = null) {
const fragment = window.location.hash;
if (!(0,_core__WEBPACK_IMPORTED_MODULE_0__.isEmpty)(fragment)) {
const decodedFragment = getDecodedURIFragment(fragment);
if ((0,_core__WEBPACK_IMPORTED_MODULE_0__.isJSONString)(decodedFragment)) {
return JSON.parse(decodedFragment);
}
}
return defaultData;
}
/**
* Parses a multidimensional query string and returns an object with the parsed args.
*
* @see https://stackoverflow.com/questions/8648892/convert-url-parameters-to-a-javascript-object#answer-44713056
*
* @param {string} str The query string.
* @param {Object} [array] The base object to use (or a new object if omitted or falsy).
* @return {Object} The object with the parsed data.
*/
function parseQueryStringArgsMultiDim(str, array) {
if (!str) {
str = window.location.search.substr(1);
}
let i,
j,
ct,
p,
lastObj,
obj,
undef,
chr,
tmp,
key,
value,
postLeftBracketPos,
keys,
keysLen;
const strArr = String(str).replace(/^&/, "").replace(/&$/, "").split("&"),
sal = strArr.length,
fixStr = function (str) {
return decodeURIComponent(str.replace(/\+/g, "%20"));
};
if (!array) {
array = {};
}
for (i = 0; i < sal; i++) {
tmp = strArr[i].split("=");
key = fixStr(tmp[0]);
value = tmp.length < 2 ? "" : fixStr(tmp[1]);
while (key.charAt(0) === " ") {
key = key.slice(1);
}
if (key.indexOf("\x00") > -1) {
key = key.slice(0, key.indexOf("\x00"));
}
if (key && key.charAt(0) !== "[") {
keys = [];
postLeftBracketPos = 0;
for (j = 0; j < key.length; j++) {
if (key.charAt(j) === "[" && !postLeftBracketPos) {
postLeftBracketPos = j + 1;
} else if (key.charAt(j) === "]") {
if (postLeftBracketPos) {
if (!keys.length) {
keys.push(key.slice(0, postLeftBracketPos - 1));
}
keys.push(key.substr(postLeftBracketPos, j - postLeftBracketPos));
postLeftBracketPos = 0;
if (key.charAt(j + 1) !== "[") {
break;
}
}
}
}
if (!keys.length) {
keys = [key];
}
for (j = 0; j < keys[0].length; j++) {
chr = keys[0].charAt(j);
if (chr === " " || chr === "." || chr === "[") {
keys[0] = keys[0].substr(0, j) + "_" + keys[0].substr(j + 1);
}
if (chr === "[") {
break;
}
}
obj = array;
for (j = 0, keysLen = keys.length; j < keysLen; j++) {
key = keys[j].replace(/^['"]/, "").replace(/['"]$/, "");
lastObj = obj;
if ((key !== "" && key !== " ") || j === 0) {
if (obj[key] === undef) {
obj[key] = {};
}
obj = obj[key];
} else {
// To insert new dimension
ct = -1;
for (p in obj) {
if (Object.prototype.hasOwnProperty.call(obj, p)) {
if (+p > ct && p.match(/^\d+$/g)) {
ct = +p;
}
}
}
key = ct + 1;
}
}
lastObj[key] = value;
}
}
/* ===== */
/*
* This code converts the object properties to arrays if they are objects with consecutive integer keys
* from 0 to n, where n is the number of properties of that object minus one
* (i.e. it converts meaningful objects which are to be interpreted as arrays to arrays).
*/
const fnNormalizeObjToArrayIfPropsAreConsecutiveIntsFrom0 = function (obj) {
const keys = Object.keys(obj);
const truthMap = {};
for (let i = 0; i < keys.length; i++) {
truthMap[i] = true;
}
const array = [];
for (let i = 0; i < keys.length; i++) {
const prop = keys[i] + "";
if (!prop.match(/^[0-9]+$/)) {
return obj;
}
const intProp = Number(prop);
if (truthMap[intProp]) {
array[intProp] = obj[prop];
delete truthMap[intProp];
} else {
return obj;
}
}
if (Object.keys(truthMap).length === 0) {
return array;
} else {
return obj;
}
};
const fnNormalizeToArrayIfNeeded = function fnNormalizeToArrayIfNeeded(obj) {
for (const prop in obj) {
if ((0,_core__WEBPACK_IMPORTED_MODULE_0__.isPlainObject)(obj[prop])) {
obj[prop] = fnNormalizeObjToArrayIfPropsAreConsecutiveIntsFrom0(
obj[prop]
);
fnNormalizeToArrayIfNeeded(obj[prop]);
}
}
};
/* /===== */
fnNormalizeToArrayIfNeeded(array);
return array;
}
/**
* Gets the query string arguments of the current location in a multidimensional fashion
* (multidimension-aware).
*
* @return {Object} An object representing the query string arguments.
*/
function getQueryStringArgsMultiDim() {
const obj = {};
parseQueryStringArgsMultiDim(location.search.substring(1), obj);
return obj;
}
/**
* Focuses an input without scrolling.
*
* @see https://stackoverflow.com/questions/4963053/focus-to-input-without-scrolling
*
* @param {Element} elem The DOM element.
*/
const cursorFocus = function (elem) {
let x, y;
// More sources for scroll x, y offset.
if (typeof window.pageXOffset !== "undefined") {
x = window.pageXOffset;
y = window.pageYOffset;
} else if (typeof window.scrollX !== "undefined") {
x = window.scrollX;
y = window.scrollY;
} else if (
document.documentElement &&
typeof document.documentElement.scrollLeft !== "undefined"
) {
x = document.documentElement.scrollLeft;
y = document.documentElement.scrollTop;
} else {
x = document.body.scrollLeft;
y = document.body.scrollTop;
}
elem.focus();
if (typeof x !== "undefined") {
window.scrollTo(x, y);
}
};
/**
* Detects wrapped elements.
*
* @param {string|Element[]} classNameOrElements A class name (with or without the leading dot) or the DOM elements to check.
* @return {Element[]} The wrapped DOM elements.
*/
function detectWrapped(classNameOrElements) {
let elements;
if (typeof classNameOrElements === "string") {
classNameOrElements = classNameOrElements.replace(/^\./, "");
elements = document.getElementsByClassName(classNameOrElements);
} else {
elements = classNameOrElements;
}
const wrapped = [];
let prev = {};
let curr = {};
for (let i = 0; i < elements.length; i++) {
const element = elements[i];
curr = element.getBoundingClientRect();
if (prev && prev.top < curr.top) {
wrapped.push(element);
}
prev = i === 0 ? curr : prev;
}
return wrapped;
}
/**
* Gets the maximum nesting level of an element (or of the whole DOM if "document.body" is given as parameter).abs
*
* @param {Element} elem The DOM element from which to start identifying the maximum nesting level.
* @return {number} The maximum nesting level, starting from 0 if the given element has no children.
*/
function maxNestingLevel(el) {
if (!el.children) {
return 0;
}
let max = -1;
for (let i = 0; i < el.children.length; i++) {
const nestingLevel = maxNestingLevel(el.children[i]);
if (nestingLevel > max) {
max = nestingLevel;
}
}
return max + 1;
}
/**
* @type {RegExp}
*/
const REGEXP_SCROLL_PARENT = /^(visible|hidden)/;
/**
* Get the first scrollable ancestor of an element.
*
* @param {Element} el The element to use as the base from which to determine its first scrollable ancestor.
* @return {Element} The first scrollable ancestor element scroll, or the document body.
*/
const getScrollableAncestor = el =>
!(el instanceof HTMLElement) || typeof window.getComputedStyle !== "function"
? null
: el.scrollHeight >= el.clientHeight &&
!REGEXP_SCROLL_PARENT.test(
window.getComputedStyle(el).overflowY || "visible"
)
? el
: getScrollableAncestor(el.parentElement) ||
document.scrollingElement ||
document.body;
/**
* Smoothly scrolls to the top of a scrollable element or the browser's window.
*
* @param {Element} [el] The element. Defaults to "window".
* @return {undefined}
*/
const smoothScrollToTop = (el = window) =>
el.scroll({
top: 0,
behavior: "smooth",
});
/**
* Downloads a file without opening a new browser's tab.
*
* @see https://stackoverflow.com/questions/1066452/easiest-way-to-open-a-download-window-without-navigating-away-from-the-page#answer-43523297
*
* @param {string} fileURI The URI of the file to download.
* @return {undefined}
*/
function downloadFile(fileURI) {
var link = document.createElement("a");
link.href = fileURI;
link.download = fileURI.substr(fileURI.lastIndexOf("/") + 1);
link.click();
}
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/global */
/******/ (() => {
/******/ __webpack_require__.g = (function() {
/******/ if (typeof globalThis === 'object') return globalThis;
/******/ try {
/******/ return this || new Function('return this')();
/******/ } catch (e) {
/******/ if (typeof window === 'object') return window;
/******/ }
/******/ })();
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
/*!**********************!*\
!*** ./src/index.js ***!
\**********************/
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "config": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.config),
/* harmony export */ "isObjectEmpty": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.isObjectEmpty),
/* harmony export */ "isObject": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.isObject),
/* harmony export */ "isPlainObject": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.isPlainObject),
/* harmony export */ "isArray": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.isArray),
/* harmony export */ "isEmpty": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.isEmpty),
/* harmony export */ "isEmptyOr0": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.isEmptyOr0),
/* harmony export */ "getGlobalObject": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.getGlobalObject),
/* harmony export */ "uniqueId": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.uniqueId),
/* harmony export */ "deepArrayCompare": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.deepArrayCompare),
/* harmony export */ "deepObjectCompare": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.deepObjectCompare),
/* harmony export */ "nestedObjectConstructValue": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.nestedObjectConstructValue),
/* harmony export */ "cloneDeeplyJSON": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.cloneDeeplyJSON),
/* harmony export */ "isReferenceType": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.isReferenceType),
/* harmony export */ "isPrimitiveType": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.isPrimitiveType),
/* harmony export */ "hasCyclicReference": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.hasCyclicReference),
/* harmony export */ "typeToStr": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.typeToStr),
/* harmony export */ "cloneObjDeeply": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.cloneObjDeeply),
/* harmony export */ "deepObjectExtend": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.deepObjectExtend),
/* harmony export */ "deepObjectCloningExtend": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.deepObjectCloningExtend),
/* harmony export */ "extend": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.extend),
/* harmony export */ "extendDecorate": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.extendDecorate),
/* harmony export */ "shallowExtend": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.shallowExtend),
/* harmony export */ "includesTypeCoercion": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.includesTypeCoercion),
/* harmony export */ "nestedPropertyValue": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.nestedPropertyValue),
/* harmony export */ "getNestedPropertyValue": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.getNestedPropertyValue),
/* harmony export */ "hasNestedPropertyValue": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.hasNestedPropertyValue),
/* harmony export */ "setNestedPropertyValue": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.setNestedPropertyValue),
/* harmony export */ "isUndefined": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.isUndefined),
/* harmony export */ "isInt": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.isInt),
/* harmony export */ "ctypeDigit": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.ctypeDigit),
/* harmony export */ "isIntegerOrIntegerStr": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.isIntegerOrIntegerStr),
/* harmony export */ "isCallable": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.isCallable),
/* harmony export */ "findIndex": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.findIndex),
/* harmony export */ "firstPropValue": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.firstPropValue),
/* harmony export */ "isStrictlyTrue": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.isStrictlyTrue),
/* harmony export */ "isTruthy": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.isTruthy),
/* harmony export */ "allTruthy": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.allTruthy),
/* harmony export */ "allNotUndefined": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.allNotUndefined),
/* harmony export */ "isJSONString": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.isJSONString),
/* harmony export */ "noOpFn": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.noOpFn),
/* harmony export */ "is": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.is),
/* harmony export */ "shallowEqual": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.shallowEqual),
/* harmony export */ "objectPropEqual": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.objectPropEqual),
/* harmony export */ "partialShallowEqual": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.partialShallowEqual),
/* harmony export */ "shallowObjectDiff": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.shallowObjectDiff),
/* harmony export */ "nestedMapSet": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.nestedMapSet),
/* harmony export */ "nestedMapHas": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.nestedMapHas),
/* harmony export */ "nestedMapGet": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.nestedMapGet),
/* harmony export */ "nestedTreeMapSet": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.nestedTreeMapSet),
/* harmony export */ "nestedTreeMapHas": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.nestedTreeMapHas),
/* harmony export */ "nestedTreeMapGet": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.nestedTreeMapGet),
/* harmony export */ "mapYield": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.mapYield),
/* harmony export */ "str": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.str),
/* harmony export */ "mapObject": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.mapObject),
/* harmony export */ "mapToObject": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.mapToObject),
/* harmony export */ "propSelection": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.propSelection),
/* harmony export */ "prototypeChainProperties": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.prototypeChainProperties),
/* harmony export */ "prop": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.prop),
/* harmony export */ "defineProperty": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.defineProperty),
/* harmony export */ "completeObjectAssign": () => (/* reexport safe */ _modules_core__WEBPACK_IMPORTED_MODULE_0__.completeObjectAssign),
/* harmony export */ "_": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__._),
/* harmony export */ "proceedCallingFn": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.proceedCallingFn),
/* harmony export */ "curry": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.curry),
/* harmony export */ "POJOCurry": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.POJOCurry),
/* harmony export */ "compose": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.compose),
/* harmony export */ "pipe": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.pipe),
/* harmony export */ "pick": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.pick),
/* harmony export */ "liftBinaryFn": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.liftBinaryFn),
/* harmony export */ "juxt": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.juxt),
/* harmony export */ "converge": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.converge),
/* harmony export */ "execIfPOJOHas": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.execIfPOJOHas),
/* harmony export */ "execWithExistentProps": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.execWithExistentProps),
/* harmony export */ "forGen": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.forGen),
/* harmony export */ "flatten": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.flatten),
/* harmony export */ "flattenDeep": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.flattenDeep),
/* harmony export */ "cartesianProduct": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.cartesianProduct),
/* harmony export */ "identityFn": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.identityFn),
/* harmony export */ "identityArgsFn": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.identityArgsFn),
/* harmony export */ "chain": () => (/* reexport safe */ _modules_fn__WEBPACK_IMPORTED_MODULE_1__.chain),
/* harmony export */ "stringHashArray": () => (/* reexport safe */ _modules_hash__WEBPACK_IMPORTED_MODULE_2__.stringHashArray),
/* harmony export */ "hashString": () => (/* reexport safe */ _modules_hash__WEBPACK_IMPORTED_MODULE_2__.hashString),
/* harmony export */ "onePassStringHash": () => (/* reexport safe */ _modules_hash__WEBPACK_IMPORTED_MODULE_2__.onePassStringHash),
/* harmony export */ "intSumHash": () => (/* reexport safe */ _modules_hash__WEBPACK_IMPORTED_MODULE_2__.intSumHash),
/* harmony export */ "timeout": () => (/* reexport safe */ _modules_promise__WEBPACK_IMPORTED_MODULE_3__.timeout),
/* harmony export */ "minDelayPromise": () => (/* reexport safe */ _modules_promise__WEBPACK_IMPORTED_MODULE_3__.minDelayPromise),
/* harmony export */ "maxDelayFallbackPromise": () => (/* reexport safe */ _modules_promise__WEBPACK_IMPORTED_MODULE_3__.maxDelayFallbackPromise),
/* harmony export */ "applyAsync": () => (/* reexport safe */ _modules_promise__WEBPACK_IMPORTED_MODULE_3__.applyAsync),
/* harmony export */ "composeAsync": () => (/* reexport safe */ _modules_promise__WEBPACK_IMPORTED_MODULE_3__.composeAsync),
/* harmony export */ "asSoonAtLeastSomeFulfilled": () => (/* reexport safe */ _modules_promise__WEBPACK_IMPORTED_MODULE_3__.asSoonAtLeastSomeFulfilled),
/* harmony export */ "buildQueryString": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.buildQueryString),
/* harmony export */ "formData": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.formData),
/* harmony export */ "xhr": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.xhr),
/* harmony export */ "checkNetwork": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.checkNetwork),
/* harmony export */ "waitNetwork": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.waitNetwork),
/* harmony export */ "setCookie": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.setCookie),
/* harmony export */ "getCookie": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.getCookie),
/* harmony export */ "unsetCookie": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.unsetCookie),
/* harmony export */ "isInViewport": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.isInViewport),
/* harmony export */ "isScrolledIntoView": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.isScrolledIntoView),
/* harmony export */ "hasVerticalScrollbar": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.hasVerticalScrollbar),
/* harmony export */ "hasHorizontalScrollbar": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.hasHorizontalScrollbar),
/* harmony export */ "elementUniqueId": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.elementUniqueId),
/* harmony export */ "getElementComputedStyle": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.getElementComputedStyle),
/* harmony export */ "elementInnerDimensions": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.elementInnerDimensions),
/* harmony export */ "countTextareaLines": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.countTextareaLines),
/* harmony export */ "isScrollOnBottom": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.isScrollOnBottom),
/* harmony export */ "getVerticalScrollBarWidth": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.getVerticalScrollBarWidth),
/* harmony export */ "isEllipsisActive": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.isEllipsisActive),
/* harmony export */ "copyTextToClipboard": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.copyTextToClipboard),
/* harmony export */ "rAFLooper": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.rAFLooper),
/* harmony export */ "nestedRAF": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.nestedRAF),
/* harmony export */ "getRawURIFragment": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.getRawURIFragment),
/* harmony export */ "getDecodedURIFragment": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.getDecodedURIFragment),
/* harmony export */ "appendEncodedJSONFragmentToURI": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.appendEncodedJSONFragmentToURI),
/* harmony export */ "getDecodedJSONFromFragmentURI": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.getDecodedJSONFromFragmentURI),
/* harmony export */ "getQueryStringArgsMultiDim": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.getQueryStringArgsMultiDim),
/* harmony export */ "cursorFocus": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.cursorFocus),
/* harmony export */ "parseQueryStringArgsMultiDim": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.parseQueryStringArgsMultiDim),
/* harmony export */ "detectWrapped": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.detectWrapped),
/* harmony export */ "maxNestingLevel": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.maxNestingLevel),
/* harmony export */ "getScrollableAncestor": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.getScrollableAncestor),
/* harmony export */ "smoothScrollToTop": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.smoothScrollToTop),
/* harmony export */ "downloadFile": () => (/* reexport safe */ _modules_web__WEBPACK_IMPORTED_MODULE_4__.downloadFile),
/* harmony export */ "randomInt": () => (/* reexport safe */ _modules_rand__WEBPACK_IMPORTED_MODULE_5__.randomInt),
/* harmony export */ "randomFloat": () => (/* reexport safe */ _modules_rand__WEBPACK_IMPORTED_MODULE_5__.randomFloat),
/* harmony export */ "randomStr": () => (/* reexport safe */ _modules_rand__WEBPACK_IMPORTED_MODULE_5__.randomStr),
/* harmony export */ "randomString": () => (/* reexport safe */ _modules_rand__WEBPACK_IMPORTED_MODULE_5__.randomString),
/* harmony export */ "randomDifferentFromValue": () => (/* reexport safe */ _modules_rand__WEBPACK_IMPORTED_MODULE_5__.randomDifferentFromValue),
/* harmony export */ "randomArrayShuffle": () => (/* reexport safe */ _modules_rand__WEBPACK_IMPORTED_MODULE_5__.randomArrayShuffle),
/* harmony export */ "uuid": () => (/* reexport safe */ _modules_rand__WEBPACK_IMPORTED_MODULE_5__.uuid),
/* harmony export */ "noncanonicalUUID": () => (/* reexport safe */ _modules_rand__WEBPACK_IMPORTED_MODULE_5__.noncanonicalUUID),
/* harmony export */ "time": () => (/* reexport safe */ _modules_time__WEBPACK_IMPORTED_MODULE_6__.time),
/* harmony export */ "msToTime": () => (/* reexport safe */ _modules_time__WEBPACK_IMPORTED_MODULE_6__.msToTime),
/* harmony export */ "millisecToSec": () => (/* reexport safe */ _modules_time__WEBPACK_IMPORTED_MODULE_6__.millisecToSec),
/* harmony export */ "secondsToTimeString": () => (/* reexport safe */ _modules_time__WEBPACK_IMPORTED_MODULE_6__.secondsToTimeString),
/* harmony export */ "escapeRegExp": () => (/* reexport safe */ _modules_string__WEBPACK_IMPORTED_MODULE_7__.escapeRegExp),
/* harmony export */ "trimCharacterMask": () => (/* reexport safe */ _modules_string__WEBPACK_IMPORTED_MODULE_7__.trimCharacterMask),
/* harmony export */ "trimCharacterRegex": () => (/* reexport safe */ _modules_string__WEBPACK_IMPORTED_MODULE_7__.trimCharacterRegex),
/* harmony export */ "trim": () => (/* reexport safe */ _modules_string__WEBPACK_IMPORTED_MODULE_7__.trim),
/* harmony export */ "trimLeft": () => (/* reexport safe */ _modules_string__WEBPACK_IMPORTED_MODULE_7__.trimLeft),
/* harmony export */ "trimRight": () => (/* reexport safe */ _modules_string__WEBPACK_IMPORTED_MODULE_7__.trimRight),
/* harmony export */ "concatWithInnerOuterSeparators": () => (/* reexport safe */ _modules_string__WEBPACK_IMPORTED_MODULE_7__.concatWithInnerOuterSeparators),
/* harmony export */ "optionsValueLabel": () => (/* reexport safe */ _modules_string__WEBPACK_IMPORTED_MODULE_7__.optionsValueLabel),
/* harmony export */ "startsWith": () => (/* reexport safe */ _modules_string__WEBPACK_IMPORTED_MODULE_7__.startsWith),
/* harmony export */ "ucaseFirst": () => (/* reexport safe */ _modules_string__WEBPACK_IMPORTED_MODULE_7__.ucaseFirst),
/* harmony export */ "reverseString": () => (/* reexport safe */ _modules_string__WEBPACK_IMPORTED_MODULE_7__.reverseString),
/* harmony export */ "separateIntThousands": () => (/* reexport safe */ _modules_string__WEBPACK_IMPORTED_MODULE_7__.separateIntThousands),
/* harmony export */ "googleMapBestZoomLevelFromBounds": () => (/* reexport safe */ _modules_google__WEBPACK_IMPORTED_MODULE_8__.googleMapBestZoomLevelFromBounds),
/* harmony export */ "delay": () => (/* reexport safe */ _modules_callback__WEBPACK_IMPORTED_MODULE_9__.delay),
/* harmony export */ "debounce": () => (/* reexport safe */ _modules_callback__WEBPACK_IMPORTED_MODULE_9__.debounce),
/* harmony export */ "throttle": () => (/* reexport safe */ _modules_callback__WEBPACK_IMPORTED_MODULE_9__.throttle),
/* harmony export */ "basename": () => (/* reexport safe */ _modules_path__WEBPACK_IMPORTED_MODULE_10__.basename),
/* harmony export */ "pathinfo": () => (/* reexport safe */ _modules_path__WEBPACK_IMPORTED_MODULE_10__.pathinfo),
/* harmony export */ "filenameExtension": () => (/* reexport safe */ _modules_path__WEBPACK_IMPORTED_MODULE_10__.filenameExtension),
/* harmony export */ "dirname": () => (/* reexport safe */ _modules_path__WEBPACK_IMPORTED_MODULE_10__.dirname),
/* harmony export */ "b2d": () => (/* reexport safe */ _modules_convert__WEBPACK_IMPORTED_MODULE_11__.b2d),
/* harmony export */ "d2b": () => (/* reexport safe */ _modules_convert__WEBPACK_IMPORTED_MODULE_11__.d2b),
/* harmony export */ "turnNthBitOff": () => (/* reexport safe */ _modules_bitwise__WEBPACK_IMPORTED_MODULE_12__.turnNthBitOff),
/* harmony export */ "turnNthBitOn": () => (/* reexport safe */ _modules_bitwise__WEBPACK_IMPORTED_MODULE_12__.turnNthBitOn),
/* harmony export */ "toggleNthBit": () => (/* reexport safe */ _modules_bitwise__WEBPACK_IMPORTED_MODULE_12__.toggleNthBit),
/* harmony export */ "checkNthBitOn": () => (/* reexport safe */ _modules_bitwise__WEBPACK_IMPORTED_MODULE_12__.checkNthBitOn),
/* harmony export */ "getLuminance": () => (/* reexport safe */ _modules_color__WEBPACK_IMPORTED_MODULE_13__.getLuminance),
/* harmony export */ "intToRGBHexString": () => (/* reexport safe */ _modules_color__WEBPACK_IMPORTED_MODULE_13__.intToRGBHexString),
/* harmony export */ "colorFromString": () => (/* reexport safe */ _modules_color__WEBPACK_IMPORTED_MODULE_13__.colorFromString),
/* harmony export */ "yieldCombinationsWithoutRepetition": () => (/* reexport safe */ _modules_combinatorics__WEBPACK_IMPORTED_MODULE_14__.yieldCombinationsWithoutRepetition),
/* harmony export */ "uniqueProgressiveIncrementalCombinations": () => (/* reexport safe */ _modules_combinatorics__WEBPACK_IMPORTED_MODULE_14__.uniqueProgressiveIncrementalCombinations),
/* harmony export */ "yieldUniqueProgressiveIncrementalCombinations": () => (/* reexport safe */ _modules_combinatorics__WEBPACK_IMPORTED_MODULE_14__.yieldUniqueProgressiveIncrementalCombinations),
/* harmony export */ "yieldAllSubsequences": () => (/* reexport safe */ _modules_combinatorics__WEBPACK_IMPORTED_MODULE_14__.yieldAllSubsequences),
/* harmony export */ "yieldUniqueSubsequences": () => (/* reexport safe */ _modules_combinatorics__WEBPACK_IMPORTED_MODULE_14__.yieldUniqueSubsequences),
/* harmony export */ "yieldPermutations": () => (/* reexport safe */ _modules_combinatorics__WEBPACK_IMPORTED_MODULE_14__.yieldPermutations),
/* harmony export */ "round": () => (/* reexport safe */ _modules_math__WEBPACK_IMPORTED_MODULE_15__.round),
/* harmony export */ "sum": () => (/* reexport safe */ _modules_math__WEBPACK_IMPORTED_MODULE_15__.sum),
/* harmony export */ "intDiv": () => (/* reexport safe */ _modules_math__WEBPACK_IMPORTED_MODULE_15__.intDiv),
/* harmony export */ "isEven": () => (/* reexport safe */ _modules_math__WEBPACK_IMPORTED_MODULE_15__.isEven),
/* harmony export */ "isOdd": () => (/* reexport safe */ _modules_math__WEBPACK_IMPORTED_MODULE_15__.isOdd),
/* harmony export */ "proportion": () => (/* reexport safe */ _modules_math__WEBPACK_IMPORTED_MODULE_15__.proportion),
/* harmony export */ "unshiftArray": () => (/* reexport safe */ _modules_array__WEBPACK_IMPORTED_MODULE_16__.unshiftArray),
/* harmony export */ "cloneArray": () => (/* reexport safe */ _modules_array__WEBPACK_IMPORTED_MODULE_16__.cloneArray),
/* harmony export */ "arraySliceFromValueToValue": () => (/* reexport safe */ _modules_array__WEBPACK_IMPORTED_MODULE_16__.arraySliceFromValueToValue),
/* harmony export */ "areArrayItemsAllCoercibleToNumber": () => (/* reexport safe */ _modules_array__WEBPACK_IMPORTED_MODULE_16__.areArrayItemsAllCoercibleToNumber),
/* harmony export */ "arrayOrArrayLike": () => (/* reexport safe */ _modules_array__WEBPACK_IMPORTED_MODULE_16__.arrayOrArrayLike),
/* harmony export */ "lastOfArray": () => (/* reexport safe */ _modules_array__WEBPACK_IMPORTED_MODULE_16__.lastOfArray),
/* harmony export */ "firstOfArray": () => (/* reexport safe */ _modules_array__WEBPACK_IMPORTED_MODULE_16__.firstOfArray),
/* harmony export */ "arrayFindReverse": () => (/* reexport safe */ _modules_array__WEBPACK_IMPORTED_MODULE_16__.arrayFindReverse),
/* harmony export */ "arrayMax": () => (/* reexport safe */ _modules_array__WEBPACK_IMPORTED_MODULE_16__.arrayMax),
/* harmony export */ "arrayMin": () => (/* reexport safe */ _modules_array__WEBPACK_IMPORTED_MODULE_16__.arrayMin),
/* harmony export */ "sortNums": () => (/* reexport safe */ _modules_array__WEBPACK_IMPORTED_MODULE_16__.sortNums),
/* harmony export */ "objectMin": () => (/* reexport safe */ _modules_object__WEBPACK_IMPORTED_MODULE_17__.objectMin),
/* harmony export */ "mean": () => (/* reexport safe */ _modules_stats__WEBPACK_IMPORTED_MODULE_18__.mean),
/* harmony export */ "median": () => (/* reexport safe */ _modules_stats__WEBPACK_IMPORTED_MODULE_18__.median),
/* harmony export */ "minAbsDeviationFromValue": () => (/* reexport safe */ _modules_stats__WEBPACK_IMPORTED_MODULE_18__.minAbsDeviationFromValue),
/* harmony export */ "minAbsDeviationFromExcludedValue": () => (/* reexport safe */ _modules_stats__WEBPACK_IMPORTED_MODULE_18__.minAbsDeviationFromExcludedValue),
/* harmony export */ "clampLat": () => (/* reexport safe */ _modules_map_coordinates__WEBPACK_IMPORTED_MODULE_19__.clampLat),
/* harmony export */ "wrapLng": () => (/* reexport safe */ _modules_map_coordinates__WEBPACK_IMPORTED_MODULE_19__.wrapLng),
/* harmony export */ "normalizeLat": () => (/* reexport safe */ _modules_map_coordinates__WEBPACK_IMPORTED_MODULE_19__.normalizeLat),
/* harmony export */ "normalizeLng": () => (/* reexport safe */ _modules_map_coordinates__WEBPACK_IMPORTED_MODULE_19__.normalizeLng),
/* harmony export */ "xrange": () => (/* reexport safe */ _modules_iterator__WEBPACK_IMPORTED_MODULE_20__.xrange),
/* harmony export */ "isValidDate": () => (/* reexport safe */ _modules_date__WEBPACK_IMPORTED_MODULE_21__.isValidDate),
/* harmony export */ "isValidDateTimeStr": () => (/* reexport safe */ _modules_date__WEBPACK_IMPORTED_MODULE_21__.isValidDateTimeStr),
/* harmony export */ "utcDate": () => (/* reexport safe */ _modules_date__WEBPACK_IMPORTED_MODULE_21__.utcDate),
/* harmony export */ "filterInt": () => (/* reexport safe */ _modules_constraint__WEBPACK_IMPORTED_MODULE_22__.filterInt),
/* harmony export */ "filterFloat": () => (/* reexport safe */ _modules_constraint__WEBPACK_IMPORTED_MODULE_22__.filterFloat),
/* harmony export */ "isValidHttpUrl": () => (/* reexport safe */ _modules_validate__WEBPACK_IMPORTED_MODULE_23__.isValidHttpUrl)
/* harmony export */ });
/* harmony import */ var _modules_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./modules/core */ "./src/modules/core/index.js");
/* harmony import */ var _modules_fn__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./modules/fn */ "./src/modules/fn.js");
/* harmony import */ var _modules_hash__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./modules/hash */ "./src/modules/hash.js");
/* harmony import */ var _modules_promise__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./modules/promise */ "./src/modules/promise.js");
/* harmony import */ var _modules_web__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./modules/web */ "./src/modules/web.js");
/* harmony import */ var _modules_rand__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./modules/rand */ "./src/modules/rand.js");
/* harmony import */ var _modules_time__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./modules/time */ "./src/modules/time.js");
/* harmony import */ var _modules_string__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./modules/string */ "./src/modules/string.js");
/* harmony import */ var _modules_google__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./modules/google */ "./src/modules/google.js");
/* harmony import */ var _modules_callback__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./modules/callback */ "./src/modules/callback.js");
/* harmony import */ var _modules_path__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./modules/path */ "./src/modules/path.js");
/* harmony import */ var _modules_convert__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./modules/convert */ "./src/modules/convert.js");
/* harmony import */ var _modules_bitwise__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./modules/bitwise */ "./src/modules/bitwise.js");
/* harmony import */ var _modules_color__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./modules/color */ "./src/modules/color.js");
/* harmony import */ var _modules_combinatorics__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./modules/combinatorics */ "./src/modules/combinatorics.js");
/* harmony import */ var _modules_math__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./modules/math */ "./src/modules/math.js");
/* harmony import */ var _modules_array__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./modules/array */ "./src/modules/array.js");
/* harmony import */ var _modules_object__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./modules/object */ "./src/modules/object.js");
/* harmony import */ var _modules_stats__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./modules/stats */ "./src/modules/stats.js");
/* harmony import */ var _modules_map_coordinates__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./modules/map-coordinates */ "./src/modules/map-coordinates.js");
/* harmony import */ var _modules_iterator__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./modules/iterator */ "./src/modules/iterator.js");
/* harmony import */ var _modules_date__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ./modules/date */ "./src/modules/date.js");
/* harmony import */ var _modules_constraint__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ./modules/constraint */ "./src/modules/constraint.js");
/* harmony import */ var _modules_validate__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ./modules/validate */ "./src/modules/validate.js");
/*
* Copyright (c) 2022 Anton Bagdatyev (Tonix)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Public API exposed to client code.
*/
})();
/******/ return __webpack_exports__;
/******/ })()
;
});
//# sourceMappingURL=js-utl.js.map