diff --git a/README.md b/README.md
index e96ff2f5a..9c7c75871 100644
--- a/README.md
+++ b/README.md
@@ -5490,7 +5490,6 @@ Otherwise, return the product of `n` and the factorial of `n - 1`.
Throws an exception if `n` is a negative number.
```js
-
const factorial = n =>
n < 0
? (() => {
@@ -6719,7 +6718,6 @@ Use `Object.keys(obj)` to iterate over the object's keys.
Use `Array.prototype.reduce()` to create a new object with the same values and mapped keys using `fn`.
```js
-
const deepMapKeys = (obj, f) =>
Array.isArray(obj)
? obj.map(val => deepMapKeys(val, f))
@@ -6799,7 +6797,6 @@ Use the `in` operator to check if `target` exists in `obj`.
If found, return the value of `obj[target]`, otherwise use `Object.values(obj)` and `Array.prototype.reduce()` to recursively call `dig` on each nested object until the first matching key/value pair is found.
```js
-
const dig = (obj, target) =>
target in obj
? obj[target]
diff --git a/docs/math.html b/docs/math.html
index cc23b5dd0..565c52a73 100644
--- a/docs/math.html
+++ b/docs/math.html
@@ -147,8 +147,7 @@ For teams, each rating can adjusted based on own team's average rating vs.
average rating of opposing team, with the score being added to their
own individual rating by supplying it as the third argument.
*/
-
dig Returns the target value in a nested JSON object, based on the given key.
Use the in operator to check if target exists in obj. If found, return the value of obj[target], otherwise use Object.values(obj) and Array.prototype.reduce() to recursively call dig on each nested object until the first matching key/value pair is found.
const dig = ( obj, target) =>
target in obj
? obj[ target]
: Object. values ( obj). reduce (( acc, val) => {
diff --git a/scripts/tdd.js b/scripts/tdd.js
index e8145e7a5..16f261a63 100644
--- a/scripts/tdd.js
+++ b/scripts/tdd.js
@@ -29,7 +29,7 @@ try {
undefinedTests.forEach(snippet => {
const exportTest = [
`const expect = require('expect');`,
- `const {${snippet}} = require('._30s.js');`,
+ `const {${snippet}} = require('./_30s.js');`,
`\ntest('${snippet} is a Function', () => {`,
` expect(${snippet}).toBeInstanceOf(Function);`,
`});\n`
diff --git a/snippets/deepMapKeys.md b/snippets/deepMapKeys.md
index e0223cb81..c736420ee 100644
--- a/snippets/deepMapKeys.md
+++ b/snippets/deepMapKeys.md
@@ -8,7 +8,6 @@ Use `Object.keys(obj)` to iterate over the object's keys.
Use `Array.prototype.reduce()` to create a new object with the same values and mapped keys using `fn`.
```js
-
const deepMapKeys = (obj, f) =>
Array.isArray(obj)
? obj.map(val => deepMapKeys(val, f))
diff --git a/snippets/dig.md b/snippets/dig.md
index a349ef2d3..737130b6e 100644
--- a/snippets/dig.md
+++ b/snippets/dig.md
@@ -6,7 +6,6 @@ Use the `in` operator to check if `target` exists in `obj`.
If found, return the value of `obj[target]`, otherwise use `Object.values(obj)` and `Array.prototype.reduce()` to recursively call `dig` on each nested object until the first matching key/value pair is found.
```js
-
const dig = (obj, target) =>
target in obj
? obj[target]
diff --git a/snippets/factorial.md b/snippets/factorial.md
index 2266247b4..cf3acc9cc 100644
--- a/snippets/factorial.md
+++ b/snippets/factorial.md
@@ -8,7 +8,6 @@ Otherwise, return the product of `n` and the factorial of `n - 1`.
Throws an exception if `n` is a negative number.
```js
-
const factorial = n =>
n < 0
? (() => {
diff --git a/test/_30s.js b/test/_30s.js
index 9c2824959..05f6893c5 100644
--- a/test/_30s.js
+++ b/test/_30s.js
@@ -1,36 +1,51 @@
-const fs = typeof require !== "undefined" && require('fs');
-const crypto = typeof require !== "undefined" && require('crypto');
-
-
const all = (arr, fn = Boolean) => arr.every(fn);
-
const allEqual = arr => arr.every(val => val === arr[0]);
-
const any = (arr, fn = Boolean) => arr.some(fn);
-
const approximatelyEqual = (v1, v2, epsilon = 0.001) => Math.abs(v1 - v2) < epsilon;
-
const arrayToCSV = (arr, delimiter = ',') =>
+const fs = typeof require !== "undefined" && require('fs');
+const crypto = typeof require !== "undefined" && require('crypto');
+
+
+const all = (arr, fn = Boolean) => arr.every(fn);
+
+const allEqual = arr => arr.every(val => val === arr[0]);
+
+const any = (arr, fn = Boolean) => arr.some(fn);
+
+const approximatelyEqual = (v1, v2, epsilon = 0.001) => Math.abs(v1 - v2) < epsilon;
+
+const arrayToCSV = (arr, delimiter = ',') =>
arr.map(v => v.map(x => `"${x}"`).join(delimiter)).join('\n');
-
const arrayToHtmlList = (arr, listID) =>
+
+const arrayToHtmlList = (arr, listID) =>
(el => (
(el = document.querySelector('#' + listID)),
(el.innerHTML += arr.map(item => `${item} `).join(''))
))();
-
const ary = (fn, n) => (...args) => fn(...args.slice(0, n));
-
const atob = str => Buffer.from(str, 'base64').toString('binary');
-
const attempt = (fn, ...args) => {
+
+const ary = (fn, n) => (...args) => fn(...args.slice(0, n));
+
+const atob = str => Buffer.from(str, 'base64').toString('binary');
+
+const attempt = (fn, ...args) => {
try {
return fn(...args);
} catch (e) {
return e instanceof Error ? e : new Error(e);
}
};
-
const average = (...nums) => nums.reduce((acc, val) => acc + val, 0) / nums.length;
-
const averageBy = (arr, fn) =>
+
+const average = (...nums) => nums.reduce((acc, val) => acc + val, 0) / nums.length;
+
+const averageBy = (arr, fn) =>
arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0) /
arr.length;
-
const bifurcate = (arr, filter) =>
+
+const bifurcate = (arr, filter) =>
arr.reduce((acc, val, i) => (acc[filter[i] ? 0 : 1].push(val), acc), [[], []]);
-
const bifurcateBy = (arr, fn) =>
+
+const bifurcateBy = (arr, fn) =>
arr.reduce((acc, val, i) => (acc[fn(val, i) ? 0 : 1].push(val), acc), [[], []]);
-
const bind = (fn, context, ...boundArgs) => (...args) => fn.apply(context, [...boundArgs, ...args]);
-
const bindAll = (obj, ...fns) =>
+
+const bind = (fn, context, ...boundArgs) => (...args) => fn.apply(context, [...boundArgs, ...args]);
+
+const bindAll = (obj, ...fns) =>
fns.forEach(
fn => (
(f = obj[fn]),
@@ -39,9 +54,11 @@ const crypto = typeof require !== "undefined" && require('crypto');
})
)
);
-
const bindKey = (context, fn, ...boundArgs) => (...args) =>
+
+const bindKey = (context, fn, ...boundArgs) => (...args) =>
context[fn].apply(context, [...boundArgs, ...args]);
-
const binomialCoefficient = (n, k) => {
+
+const binomialCoefficient = (n, k) => {
if (Number.isNaN(n) || Number.isNaN(k)) return NaN;
if (k < 0 || k > n) return 0;
if (k === 0 || k === n) return 1;
@@ -51,31 +68,44 @@ const crypto = typeof require !== "undefined" && require('crypto');
for (let j = 2; j <= k; j++) res *= (n - j + 1) / j;
return Math.round(res);
};
-
const bottomVisible = () =>
+
+const bottomVisible = () =>
document.documentElement.clientHeight + window.scrollY >=
(document.documentElement.scrollHeight || document.documentElement.clientHeight);
-
const btoa = str => Buffer.from(str, 'binary').toString('base64');
-
const byteSize = str => new Blob([str]).size;
-const call = (key, ...args) => context => context[key](...args);
-
const capitalize = ([first, ...rest], lowerRest = false) =>
+
+const btoa = str => Buffer.from(str, 'binary').toString('base64');
+
+const byteSize = str => new Blob([str]).size;
+const call = (key, ...args) => context => context[key](...args);
+
+const capitalize = ([first, ...rest], lowerRest = false) =>
first.toUpperCase() + (lowerRest ? rest.join('').toLowerCase() : rest.join(''));
-
const capitalizeEveryWord = str => str.replace(/\b[a-z]/g, char => char.toUpperCase());
-
const castArray = val => (Array.isArray(val) ? val : [val]);
-
const chainAsync = fns => {
+
+const capitalizeEveryWord = str => str.replace(/\b[a-z]/g, char => char.toUpperCase());
+
+const castArray = val => (Array.isArray(val) ? val : [val]);
+
+const chainAsync = fns => {
let curr = 0;
const next = () => fns[curr++](next);
next();
};
-
const chunk = (arr, size) =>
+
+const chunk = (arr, size) =>
Array.from({ length: Math.ceil(arr.length / size) }, (v, i) =>
arr.slice(i * size, i * size + size)
);
-
const clampNumber = (num, a, b) => Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b));
-
const cloneRegExp = regExp => new RegExp(regExp.source, regExp.flags);
-
const coalesce = (...args) => args.find(_ => ![undefined, null].includes(_));
-
const coalesceFactory = valid => (...args) => args.find(valid);
-const collectInto = fn => (...args) => fn(args);
-
const colorize = (...args) => ({
+
+const clampNumber = (num, a, b) => Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b));
+
+const cloneRegExp = regExp => new RegExp(regExp.source, regExp.flags);
+
+const coalesce = (...args) => args.find(_ => ![undefined, null].includes(_));
+
+const coalesceFactory = valid => (...args) => args.find(valid);
+const collectInto = fn => (...args) => fn(args);
+
+const colorize = (...args) => ({
black: `\x1b[30m${args.join(' ')}`,
red: `\x1b[31m${args.join(' ')}`,
green: `\x1b[32m${args.join(' ')}`,
@@ -93,11 +123,16 @@ const collectInto = fn => (...args) => fn(args);
bgCyan: `\x1b[46m${args.join(' ')}\x1b[0m`,
bgWhite: `\x1b[47m${args.join(' ')}\x1b[0m`
});
-
const compact = arr => arr.filter(Boolean);
-
const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args)));
-
const composeRight = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args)));
-
const converge = (converger, fns) => (...args) => converger(...fns.map(fn => fn.apply(null, args)));
-
const copyToClipboard = str => {
+
+const compact = arr => arr.filter(Boolean);
+
+const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args)));
+
+const composeRight = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args)));
+
+const converge = (converger, fns) => (...args) => converger(...fns.map(fn => fn.apply(null, args)));
+
+const copyToClipboard = str => {
const el = document.createElement('textarea');
el.value = str;
el.setAttribute('readonly', '');
@@ -114,12 +149,14 @@ const collectInto = fn => (...args) => fn(args);
document.getSelection().addRange(selected);
}
};
-
const countBy = (arr, fn) =>
+
+const countBy = (arr, fn) =>
arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => {
acc[val] = (acc[val] || 0) + 1;
return acc;
}, {});
-
const counter = (selector, start, end, step = 1, duration = 2000) => {
+
+const counter = (selector, start, end, step = 1, duration = 2000) => {
let current = start,
_step = (end - start) * step < 0 ? -step : step,
timer = setInterval(() => {
@@ -130,15 +167,19 @@ const collectInto = fn => (...args) => fn(args);
}, Math.abs(Math.floor(duration / (end - start))));
return timer;
};
-
const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0);
-
+
+const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0);
+
+
const createDirIfNotExists = dir => !fs.existsSync(dir) ? fs.mkdirSync(dir) : undefined;
-
const createElement = str => {
+
+const createElement = str => {
const el = document.createElement('div');
el.innerHTML = str;
return el.firstElementChild;
};
-
const createEventHub = () => ({
+
+const createEventHub = () => ({
hub: Object.create(null),
emit(event, data) {
(this.hub[event] || []).forEach(handler => handler(data));
@@ -152,12 +193,14 @@ const createDirIfNotExists = dir => !fs.existsSync(dir) ? fs.mkdirSync(dir) : un
if (i > -1) this.hub[event].splice(i, 1);
}
});
-
const CSVToArray = (data, delimiter = ',', omitFirstRow = false) =>
+
+const CSVToArray = (data, delimiter = ',', omitFirstRow = false) =>
data
.slice(omitFirstRow ? data.indexOf('\n') + 1 : 0)
.split('\n')
.map(v => v.split(delimiter));
-
const CSVToJSON = (data, delimiter = ',') => {
+
+const CSVToJSON = (data, delimiter = ',') => {
const titles = data.slice(0, data.indexOf('\n')).split(delimiter);
return data
.slice(data.indexOf('\n') + 1)
@@ -167,34 +210,43 @@ const createDirIfNotExists = dir => !fs.existsSync(dir) ? fs.mkdirSync(dir) : un
return titles.reduce((obj, title, index) => ((obj[title] = values[index]), obj), {});
});
};
-
const currentURL = () => window.location.href;
-
const curry = (fn, arity = fn.length, ...args) =>
+
+const currentURL = () => window.location.href;
+
+const curry = (fn, arity = fn.length, ...args) =>
arity <= args.length ? fn(...args) : curry.bind(null, fn, arity, ...args);
-
const dayOfYear = date =>
+
+const dayOfYear = date =>
Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24);
-
const debounce = (fn, ms = 0) => {
+
+const debounce = (fn, ms = 0) => {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn.apply(this, args), ms);
};
};
-
const decapitalize = ([first, ...rest], upperRest = false) =>
+
+const decapitalize = ([first, ...rest], upperRest = false) =>
first.toLowerCase() + (upperRest ? rest.join('').toUpperCase() : rest.join(''));
-
const deepClone = obj => {
+
+const deepClone = obj => {
let clone = Object.assign({}, obj);
Object.keys(clone).forEach(
key => (clone[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key])
);
return Array.isArray(obj) ? (clone.length = obj.length) && Array.from(clone) : clone;
};
-
const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));
-
const deepFreeze = obj =>
+
+const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));
+
+const deepFreeze = obj =>
Object.keys(obj).forEach(
prop =>
!(obj[prop] instanceof Object) || Object.isFrozen(obj[prop]) ? null : deepFreeze(obj[prop])
) || Object.freeze(obj);
-
+
+
const deepMapKeys = (obj, f) =>
Array.isArray(obj)
? obj.map(val => deepMapKeys(val, f))
@@ -206,24 +258,33 @@ const deepMapKeys = (obj, f) =>
return acc;
}, {})
: obj;
-
const defaults = (obj, ...defs) => Object.assign({}, obj, ...defs.reverse(), obj);
-
const defer = (fn, ...args) => setTimeout(fn, 1, ...args);
-
const degreesToRads = deg => (deg * Math.PI) / 180.0;
-
const delay = (fn, wait, ...args) => setTimeout(fn, wait, ...args);
-
const detectDeviceType = () =>
+
+const defaults = (obj, ...defs) => Object.assign({}, obj, ...defs.reverse(), obj);
+
+const defer = (fn, ...args) => setTimeout(fn, 1, ...args);
+
+const degreesToRads = deg => (deg * Math.PI) / 180.0;
+
+const delay = (fn, wait, ...args) => setTimeout(fn, wait, ...args);
+
+const detectDeviceType = () =>
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
? 'Mobile'
: 'Desktop';
-
const difference = (a, b) => {
+
+const difference = (a, b) => {
const s = new Set(b);
return a.filter(x => !s.has(x));
};
-
const differenceBy = (a, b, fn) => {
+
+const differenceBy = (a, b, fn) => {
const s = new Set(b.map(fn));
return a.filter(x => !s.has(fn(x)));
};
-
const differenceWith = (arr, val, comp) => arr.filter(a => val.findIndex(b => comp(a, b)) === -1);
-
+
+const differenceWith = (arr, val, comp) => arr.filter(a => val.findIndex(b => comp(a, b)) === -1);
+
+
const dig = (obj, target) =>
target in obj
? obj[target]
@@ -231,20 +292,28 @@ const dig = (obj, target) =>
if (acc !== undefined) return acc;
if (typeof val === 'object') return dig(val, target);
}, undefined);
-
const digitize = n => [...`${n}`].map(i => parseInt(i));
-
const distance = (x0, y0, x1, y1) => Math.hypot(x1 - x0, y1 - y0);
-
const drop = (arr, n = 1) => arr.slice(n);
-
const dropRight = (arr, n = 1) => arr.slice(0, -n);
-
const dropRightWhile = (arr, func) => {
+
+const digitize = n => [...`${n}`].map(i => parseInt(i));
+
+const distance = (x0, y0, x1, y1) => Math.hypot(x1 - x0, y1 - y0);
+
+const drop = (arr, n = 1) => arr.slice(n);
+
+const dropRight = (arr, n = 1) => arr.slice(0, -n);
+
+const dropRightWhile = (arr, func) => {
while (arr.length > 0 && !func(arr[arr.length - 1])) arr = arr.slice(0, -1);
return arr;
};
-
const dropWhile = (arr, func) => {
+
+const dropWhile = (arr, func) => {
while (arr.length > 0 && !func(arr[0])) arr = arr.slice(1);
return arr;
};
-
const elementContains = (parent, child) => parent !== child && parent.contains(child);
-
const elementIsVisibleInViewport = (el, partiallyVisible = false) => {
+
+const elementContains = (parent, child) => parent !== child && parent.contains(child);
+
+const elementIsVisibleInViewport = (el, partiallyVisible = false) => {
const { top, left, bottom, right } = el.getBoundingClientRect();
const { innerHeight, innerWidth } = window;
return partiallyVisible
@@ -252,7 +321,8 @@ const dig = (obj, target) =>
((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth))
: top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth;
};
-
const elo = ([...ratings], kFactor = 32, selfRating) => {
+
+const elo = ([...ratings], kFactor = 32, selfRating) => {
const [a, b] = ratings;
const expectedScore = (self, opponent) => 1 / (1 + 10 ** ((opponent - self) / 400));
const newRating = (rating, i) =>
@@ -268,7 +338,8 @@ const dig = (obj, target) =>
}
return ratings;
};
-
const equals = (a, b) => {
+
+const equals = (a, b) => {
if (a === b) return true;
if (a instanceof Date && b instanceof Date) return a.getTime() === b.getTime();
if (!a || !b || (typeof a !== 'object' && typeof b !== 'object')) return a === b;
@@ -278,7 +349,8 @@ const dig = (obj, target) =>
if (keys.length !== Object.keys(b).length) return false;
return keys.every(k => equals(a[k], b[k]));
};
-
const escapeHTML = str =>
+
+const escapeHTML = str =>
str.replace(
/[&<>'"]/g,
tag =>
@@ -290,16 +362,20 @@ const dig = (obj, target) =>
'"': '"'
}[tag] || tag)
);
-
const escapeRegExp = str => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
-
const everyNth = (arr, nth) => arr.filter((e, i) => i % nth === nth - 1);
-
const extendHex = shortHex =>
+
+const escapeRegExp = str => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+
+const everyNth = (arr, nth) => arr.filter((e, i) => i % nth === nth - 1);
+
+const extendHex = shortHex =>
'#' +
shortHex
.slice(shortHex.startsWith('#') ? 1 : 0)
.split('')
.map(x => x + x)
.join('');
-
+
+
const factorial = n =>
n < 0
? (() => {
@@ -308,42 +384,54 @@ const factorial = n =>
: n <= 1
? 1
: n * factorial(n - 1);
-
const fibonacci = n =>
+
+const fibonacci = n =>
Array.from({ length: n }).reduce(
(acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i),
[]
);
-const filterFalsy = arr => arr.filter(Boolean);
-
const filterNonUnique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexOf(i));
-
const filterNonUniqueBy = (arr, fn) =>
+
+const filterFalsy = arr => arr.filter(Boolean);
+
+const filterNonUnique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexOf(i));
+
+const filterNonUniqueBy = (arr, fn) =>
arr.filter((v, i) => arr.every((x, j) => (i === j) === fn(v, x, i, j)));
-
const findKey = (obj, fn) => Object.keys(obj).find(key => fn(obj[key], key, obj));
-
const findLast = (arr, fn) => arr.filter(fn).pop();
-
const findLastIndex = (arr, fn) =>
+
+const findKey = (obj, fn) => Object.keys(obj).find(key => fn(obj[key], key, obj));
+
+const findLast = (arr, fn) => arr.filter(fn).pop();
+
+const findLastIndex = (arr, fn) =>
arr
.map((val, i) => [i, val])
.filter(([i, val]) => fn(val, i, arr))
.pop()[0];
-
const findLastKey = (obj, fn) =>
+
+const findLastKey = (obj, fn) =>
Object.keys(obj)
.reverse()
.find(key => fn(obj[key], key, obj));
-
const flatten = (arr, depth = 1) =>
+
+const flatten = (arr, depth = 1) =>
arr.reduce((a, v) => a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v), []);
-
const flattenObject = (obj, prefix = '') =>
+
+const flattenObject = (obj, prefix = '') =>
Object.keys(obj).reduce((acc, k) => {
const pre = prefix.length ? prefix + '.' : '';
if (typeof obj[k] === 'object') Object.assign(acc, flattenObject(obj[k], pre + k));
else acc[pre + k] = obj[k];
return acc;
}, {});
-const flip = fn => (first, ...rest) => fn(...rest, first);
-
const forEachRight = (arr, callback) =>
+const flip = fn => (first, ...rest) => fn(...rest, first);
+
+const forEachRight = (arr, callback) =>
arr
.slice(0)
.reverse()
.forEach(callback);
-
const formatDuration = ms => {
+
+const formatDuration = ms => {
if (ms < 0) ms = -ms;
const time = {
day: Math.floor(ms / 86400000),
@@ -357,31 +445,39 @@ const flip = fn => (first, ...rest) => fn(...rest, first);
.map(([key, val]) => `${val} ${key}${val !== 1 ? 's' : ''}`)
.join(', ');
};
-
const forOwn = (obj, fn) => Object.keys(obj).forEach(key => fn(obj[key], key, obj));
-
const forOwnRight = (obj, fn) =>
+
+const forOwn = (obj, fn) => Object.keys(obj).forEach(key => fn(obj[key], key, obj));
+
+const forOwnRight = (obj, fn) =>
Object.keys(obj)
.reverse()
.forEach(key => fn(obj[key], key, obj));
-
const fromCamelCase = (str, separator = '_') =>
+
+const fromCamelCase = (str, separator = '_') =>
str
.replace(/([a-z\d])([A-Z])/g, '$1' + separator + '$2')
.replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + separator + '$2')
.toLowerCase();
-
const functionName = fn => (console.debug(fn.name), fn);
-
const functions = (obj, inherited = false) =>
+
+const functionName = fn => (console.debug(fn.name), fn);
+
+const functions = (obj, inherited = false) =>
(inherited
? [...Object.keys(obj), ...Object.keys(Object.getPrototypeOf(obj))]
: Object.keys(obj)
).filter(key => typeof obj[key] === 'function');
-
const gcd = (...arr) => {
+
+const gcd = (...arr) => {
const _gcd = (x, y) => (!y ? x : gcd(y, x % y));
return [...arr].reduce((a, b) => _gcd(a, b));
};
-
const geometricProgression = (end, start = 1, step = 2) =>
+
+const geometricProgression = (end, start = 1, step = 2) =>
Array.from({ length: Math.floor(Math.log(end / start) / Math.log(step)) + 1 }).map(
(v, i) => start * step ** i
);
-
const get = (from, ...selectors) =>
+
+const get = (from, ...selectors) =>
[...selectors].map(s =>
s
.replace(/\[([^\[\]]*)\]/g, '.$1.')
@@ -389,14 +485,18 @@ const flip = fn => (first, ...rest) => fn(...rest, first);
.filter(t => t !== '')
.reduce((prev, cur) => prev && prev[cur], from)
);
-
const getColonTimeFromDate = date => date.toTimeString().slice(0, 8);
-
const getDaysDiffBetweenDates = (dateInitial, dateFinal) =>
+
+const getColonTimeFromDate = date => date.toTimeString().slice(0, 8);
+
+const getDaysDiffBetweenDates = (dateInitial, dateFinal) =>
(dateFinal - dateInitial) / (1000 * 3600 * 24);
-
const getImages = (el, includeDuplicates = false) => {
+
+const getImages = (el, includeDuplicates = false) => {
const images = [...el.getElementsByTagName('img')].map(img => img.getAttribute('src'));
return includeDuplicates ? images : [...new Set(images)];
};
-
const getMeridiemSuffixOfInteger = num =>
+
+const getMeridiemSuffixOfInteger = num =>
num === 0 || num === 24
? 12 + 'am'
: num === 12
@@ -404,28 +504,37 @@ const flip = fn => (first, ...rest) => fn(...rest, first);
: num < 12
? (num % 12) + 'am'
: (num % 12) + 'pm';
-
const getScrollPosition = (el = window) => ({
+
+const getScrollPosition = (el = window) => ({
x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft,
y: el.pageYOffset !== undefined ? el.pageYOffset : el.scrollTop
});
-
const getStyle = (el, ruleName) => getComputedStyle(el)[ruleName];
-
const getType = v =>
+
+const getStyle = (el, ruleName) => getComputedStyle(el)[ruleName];
+
+const getType = v =>
v === undefined ? 'undefined' : v === null ? 'null' : v.constructor.name.toLowerCase();
-
const getURLParameters = url =>
+
+const getURLParameters = url =>
(url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce(
(a, v) => ((a[v.slice(0, v.indexOf('='))] = v.slice(v.indexOf('=') + 1)), a),
{}
);
-
const groupBy = (arr, fn) =>
+
+const groupBy = (arr, fn) =>
arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val, i) => {
acc[val] = (acc[val] || []).concat(arr[i]);
return acc;
}, {});
-
const hammingDistance = (num1, num2) => ((num1 ^ num2).toString(2).match(/1/g) || '').length;
-
const hasClass = (el, className) => el.classList.contains(className);
-
const hasFlags = (...flags) =>
+
+const hammingDistance = (num1, num2) => ((num1 ^ num2).toString(2).match(/1/g) || '').length;
+
+const hasClass = (el, className) => el.classList.contains(className);
+
+const hasFlags = (...flags) =>
flags.every(flag => process.argv.includes(/^-{1,2}/.test(flag) ? flag : '--' + flag));
-
const hashBrowser = val =>
+
+const hashBrowser = val =>
crypto.subtle.digest('SHA-256', new TextEncoder('utf-8').encode(val)).then(h => {
let hexes = [],
view = new DataView(h);
@@ -433,7 +542,8 @@ const flip = fn => (first, ...rest) => fn(...rest, first);
hexes.push(('00000000' + view.getUint32(i).toString(16)).slice(-8));
return hexes.join('');
});
-
+
+
const hashNode = val =>
new Promise(resolve =>
setTimeout(
@@ -447,8 +557,10 @@ const hashNode = val =>
0
)
);
-
const head = arr => arr[0];
-
const hexToRGB = hex => {
+
+const head = arr => arr[0];
+
+const hexToRGB = hex => {
let alpha = false,
h = hex.slice(hex.startsWith('#') ? 1 : 0);
if (h.length === 3) h = [...h].map(x => x + x).join('');
@@ -467,15 +579,18 @@ const hashNode = val =>
')'
);
};
-
const hide = (...el) => [...el].forEach(e => (e.style.display = 'none'));
-
const httpGet = (url, callback, err = console.error) => {
+
+const hide = (...el) => [...el].forEach(e => (e.style.display = 'none'));
+
+const httpGet = (url, callback, err = console.error) => {
const request = new XMLHttpRequest();
request.open('GET', url, true);
request.onload = () => callback(request.responseText);
request.onerror = () => err(request);
request.send();
};
-
const httpPost = (url, data, callback, err = console.error) => {
+
+const httpPost = (url, data, callback, err = console.error) => {
const request = new XMLHttpRequest();
request.open('POST', url, true);
request.setRequestHeader('Content-type', 'application/json; charset=utf-8');
@@ -483,56 +598,77 @@ const hashNode = val =>
request.onerror = () => err(request);
request.send(data);
};
-
const httpsRedirect = () => {
+
+const httpsRedirect = () => {
if (location.protocol !== 'https:') location.replace('https://' + location.href.split('//')[1]);
};
-
const hz = (fn, iterations = 100) => {
+
+const hz = (fn, iterations = 100) => {
const before = performance.now();
for (let i = 0; i < iterations; i++) fn();
return (1000 * iterations) / (performance.now() - before);
};
-
const indentString = (str, count, indent = ' ') => str.replace(/^/gm, indent.repeat(count));
-
const indexOfAll = (arr, val) => arr.reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []);
-
const initial = arr => arr.slice(0, -1);
-
const initialize2DArray = (w, h, val = null) =>
+
+const indentString = (str, count, indent = ' ') => str.replace(/^/gm, indent.repeat(count));
+
+const indexOfAll = (arr, val) => arr.reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []);
+
+const initial = arr => arr.slice(0, -1);
+
+const initialize2DArray = (w, h, val = null) =>
Array.from({ length: h }).map(() => Array.from({ length: w }).fill(val));
-
const initializeArrayWithRange = (end, start = 0, step = 1) =>
+
+const initializeArrayWithRange = (end, start = 0, step = 1) =>
Array.from({ length: Math.ceil((end - start + 1) / step) }, (v, i) => i * step + start);
-
const initializeArrayWithRangeRight = (end, start = 0, step = 1) =>
+
+const initializeArrayWithRangeRight = (end, start = 0, step = 1) =>
Array.from({ length: Math.ceil((end + 1 - start) / step) }).map(
(v, i, arr) => (arr.length - i - 1) * step + start
);
-
const initializeArrayWithValues = (n, val = 0) => Array(n).fill(val);
-
const initializeNDArray = (val, ...args) =>
+
+const initializeArrayWithValues = (n, val = 0) => Array(n).fill(val);
+
+const initializeNDArray = (val, ...args) =>
args.length === 0
? val
: Array.from({ length: args[0] }).map(() => initializeNDArray(val, ...args.slice(1)));
-
const inRange = (n, start, end = null) => {
+
+const inRange = (n, start, end = null) => {
if (end && start > end) [end, start] = [start, end];
return end == null ? n >= 0 && n < start : n >= start && n < end;
};
-
const insertAfter = (el, htmlString) => el.insertAdjacentHTML('afterend', htmlString);
-
const insertBefore = (el, htmlString) => el.insertAdjacentHTML('beforebegin', htmlString);
-
const intersection = (a, b) => {
+
+const insertAfter = (el, htmlString) => el.insertAdjacentHTML('afterend', htmlString);
+
+const insertBefore = (el, htmlString) => el.insertAdjacentHTML('beforebegin', htmlString);
+
+const intersection = (a, b) => {
const s = new Set(b);
return a.filter(x => s.has(x));
};
-
const intersectionBy = (a, b, fn) => {
+
+const intersectionBy = (a, b, fn) => {
const s = new Set(b.map(fn));
return a.filter(x => s.has(fn(x)));
};
-
const intersectionWith = (a, b, comp) => a.filter(x => b.findIndex(y => comp(x, y)) !== -1);
-
const invertKeyValues = (obj, fn) =>
+
+const intersectionWith = (a, b, comp) => a.filter(x => b.findIndex(y => comp(x, y)) !== -1);
+
+const invertKeyValues = (obj, fn) =>
Object.keys(obj).reduce((acc, key) => {
const val = fn ? fn(obj[key]) : obj[key];
acc[val] = acc[val] || [];
acc[val].push(key);
return acc;
}, {});
-
const is = (type, val) => ![, null].includes(val) && val.constructor === type;
-
const isAbsoluteURL = str => /^[a-z][a-z0-9+.-]*:/.test(str);
-
const isAfterDate = (dateA, dateB) => dateA > dateB;
-
const isAnagram = (str1, str2) => {
+
+const is = (type, val) => ![, null].includes(val) && val.constructor === type;
+
+const isAbsoluteURL = str => /^[a-z][a-z0-9+.-]*:/.test(str);
+
+const isAfterDate = (dateA, dateB) => dateA > dateB;
+
+const isAnagram = (str1, str2) => {
const normalize = str =>
str
.toLowerCase()
@@ -542,13 +678,20 @@ const hashNode = val =>
.join('');
return normalize(str1) === normalize(str2);
};
-
const isArrayLike = obj => obj != null && typeof obj[Symbol.iterator] === 'function';
-
const isBeforeDate = (dateA, dateB) => dateA < dateB;
-
const isBoolean = val => typeof val === 'boolean';
-
const isBrowser = () => ![typeof window, typeof document].includes('undefined');
-
const isBrowserTabFocused = () => !document.hidden;
-
const isDivisible = (dividend, divisor) => dividend % divisor === 0;
-
const isDuplexStream = val =>
+
+const isArrayLike = obj => obj != null && typeof obj[Symbol.iterator] === 'function';
+
+const isBeforeDate = (dateA, dateB) => dateA < dateB;
+
+const isBoolean = val => typeof val === 'boolean';
+
+const isBrowser = () => ![typeof window, typeof document].includes('undefined');
+
+const isBrowserTabFocused = () => !document.hidden;
+
+const isDivisible = (dividend, divisor) => dividend % divisor === 0;
+
+const isDuplexStream = val =>
val !== null &&
typeof val === 'object' &&
typeof val.pipe === 'function' &&
@@ -556,35 +699,52 @@ const hashNode = val =>
typeof val._readableState === 'object' &&
typeof val._write === 'function' &&
typeof val._writableState === 'object';
-
const isEmpty = val => val == null || !(Object.keys(val) || val).length;
-
const isEven = num => num % 2 === 0;
-
const isFunction = val => typeof val === 'function';
-
const isLowerCase = str => str === str.toLowerCase();
-
const isNegativeZero = val => val === 0 && 1 / val === -Infinity;
-
const isNil = val => val === undefined || val === null;
-
const isNull = val => val === null;
-
const isNumber = val => typeof val === 'number';
-
const isObject = obj => obj === Object(obj);
-
const isObjectLike = val => val !== null && typeof val === 'object';
-
const isPlainObject = val => !!val && typeof val === 'object' && val.constructor === Object;
-
const isPrime = num => {
+
+const isEmpty = val => val == null || !(Object.keys(val) || val).length;
+
+const isEven = num => num % 2 === 0;
+
+const isFunction = val => typeof val === 'function';
+
+const isLowerCase = str => str === str.toLowerCase();
+
+const isNegativeZero = val => val === 0 && 1 / val === -Infinity;
+
+const isNil = val => val === undefined || val === null;
+
+const isNull = val => val === null;
+
+const isNumber = val => typeof val === 'number';
+
+const isObject = obj => obj === Object(obj);
+
+const isObjectLike = val => val !== null && typeof val === 'object';
+
+const isPlainObject = val => !!val && typeof val === 'object' && val.constructor === Object;
+
+const isPrime = num => {
const boundary = Math.floor(Math.sqrt(num));
for (var i = 2; i <= boundary; i++) if (num % i === 0) return false;
return num >= 2;
};
-
const isPrimitive = val => Object(val) !== val;
-
const isPromiseLike = obj =>
+
+const isPrimitive = val => Object(val) !== val;
+
+const isPromiseLike = obj =>
obj !== null &&
(typeof obj === 'object' || typeof obj === 'function') &&
typeof obj.then === 'function';
-
const isReadableStream = val =>
+
+const isReadableStream = val =>
val !== null &&
typeof val === 'object' &&
typeof val.pipe === 'function' &&
typeof val._read === 'function' &&
typeof val._readableState === 'object';
-
const isSameDate = (dateA, dateB) => dateA.toISOString() === dateB.toISOString();
-
const isSorted = arr => {
+
+const isSameDate = (dateA, dateB) => dateA.toISOString() === dateB.toISOString();
+
+const isSorted = arr => {
let direction = -(arr[0] - arr[1]);
for (let [i, val] of arr.entries()) {
direction = !direction ? -(arr[i - 1] - arr[i]) : direction;
@@ -592,13 +752,20 @@ const hashNode = val =>
else if ((val - arr[i + 1]) * direction > 0) return 0;
}
};
-
const isStream = val => val !== null && typeof val === 'object' && typeof val.pipe === 'function';
-
const isString = val => typeof val === 'string';
-
const isSymbol = val => typeof val === 'symbol';
-
const isTravisCI = () => 'TRAVIS' in process.env && 'CI' in process.env;
-
const isUndefined = val => val === undefined;
-
const isUpperCase = str => str === str.toUpperCase();
-
const isValidJSON = str => {
+
+const isStream = val => val !== null && typeof val === 'object' && typeof val.pipe === 'function';
+
+const isString = val => typeof val === 'string';
+
+const isSymbol = val => typeof val === 'symbol';
+
+const isTravisCI = () => 'TRAVIS' in process.env && 'CI' in process.env;
+
+const isUndefined = val => val === undefined;
+
+const isUpperCase = str => str === str.toUpperCase();
+
+const isValidJSON = str => {
try {
JSON.parse(str);
return true;
@@ -606,13 +773,15 @@ const hashNode = val =>
return false;
}
};
-
const isWritableStream = val =>
+
+const isWritableStream = val =>
val !== null &&
typeof val === 'object' &&
typeof val.pipe === 'function' &&
typeof val._write === 'function' &&
typeof val._writableState === 'object';
-
const join = (arr, separator = ',', end = separator) =>
+
+const join = (arr, separator = ',', end = separator) =>
arr.reduce(
(acc, val, i) =>
i === arr.length - 2
@@ -622,7 +791,8 @@ const hashNode = val =>
: acc + val + separator,
''
);
-
const JSONtoCSV = (arr, columns, delimiter = ',') =>
+
+const JSONtoCSV = (arr, columns, delimiter = ',') =>
[
columns.join(delimiter),
...arr.map(obj =>
@@ -632,22 +802,28 @@ const hashNode = val =>
)
)
].join('\n');
-
+
+
const JSONToFile = (obj, filename) =>
fs.writeFile(`${filename}.json`, JSON.stringify(obj, null, 2));
-
const last = arr => arr[arr.length - 1];
-
const lcm = (...arr) => {
+
+const last = arr => arr[arr.length - 1];
+
+const lcm = (...arr) => {
const gcd = (x, y) => (!y ? x : gcd(y, x % y));
const _lcm = (x, y) => (x * y) / gcd(x, y);
return [...arr].reduce((a, b) => _lcm(a, b));
};
-
const longestItem = (...vals) => vals.reduce((a, x) => (x.length > a.length ? x : a));
-
const lowercaseKeys = obj =>
+
+const longestItem = (...vals) => vals.reduce((a, x) => (x.length > a.length ? x : a));
+
+const lowercaseKeys = obj =>
Object.keys(obj).reduce((acc, key) => {
acc[key.toLowerCase()] = obj[key];
return acc;
}, {});
-
const luhnCheck = num => {
+
+const luhnCheck = num => {
let arr = (num + '')
.split('')
.reverse()
@@ -657,44 +833,56 @@ const JSONToFile = (obj, filename) =>
sum += lastDigit;
return sum % 10 === 0;
};
-
const mapKeys = (obj, fn) =>
+
+const mapKeys = (obj, fn) =>
Object.keys(obj).reduce((acc, k) => {
acc[fn(obj[k], k, obj)] = obj[k];
return acc;
}, {});
-
const mapObject = (arr, fn) =>
+
+const mapObject = (arr, fn) =>
(a => (
(a = [arr, arr.map(fn)]), a[0].reduce((acc, val, ind) => ((acc[val] = a[1][ind]), acc), {})
))();
-
const mapString = (str, fn) =>
+
+const mapString = (str, fn) =>
str
.split('')
.map((c, i) => fn(c, i, str))
.join('');
-
const mapValues = (obj, fn) =>
+
+const mapValues = (obj, fn) =>
Object.keys(obj).reduce((acc, k) => {
acc[k] = fn(obj[k], k, obj);
return acc;
}, {});
-
const mask = (cc, num = 4, mask = '*') => `${cc}`.slice(-num).padStart(`${cc}`.length, mask);
-
const matches = (obj, source) =>
+
+const mask = (cc, num = 4, mask = '*') => `${cc}`.slice(-num).padStart(`${cc}`.length, mask);
+
+const matches = (obj, source) =>
Object.keys(source).every(key => obj.hasOwnProperty(key) && obj[key] === source[key]);
-
const matchesWith = (obj, source, fn) =>
+
+const matchesWith = (obj, source, fn) =>
Object.keys(source).every(
key =>
obj.hasOwnProperty(key) && fn
? fn(obj[key], source[key], key, obj, source)
: obj[key] == source[key]
);
-
const maxBy = (arr, fn) => Math.max(...arr.map(typeof fn === 'function' ? fn : val => val[fn]));
-
const maxDate = (...dates) => new Date(Math.max.apply(null, ...dates));
-
const maxN = (arr, n = 1) => [...arr].sort((a, b) => b - a).slice(0, n);
-
const median = arr => {
+
+const maxBy = (arr, fn) => Math.max(...arr.map(typeof fn === 'function' ? fn : val => val[fn]));
+
+const maxDate = (...dates) => new Date(Math.max.apply(null, ...dates));
+
+const maxN = (arr, n = 1) => [...arr].sort((a, b) => b - a).slice(0, n);
+
+const median = arr => {
const mid = Math.floor(arr.length / 2),
nums = [...arr].sort((a, b) => a - b);
return arr.length % 2 !== 0 ? nums[mid] : (nums[mid - 1] + nums[mid]) / 2;
};
-
const memoize = fn => {
+
+const memoize = fn => {
const cache = new Map();
const cached = function(val) {
return cache.has(val) ? cache.get(val) : cache.set(val, fn.call(this, val)) && cache.get(val);
@@ -702,7 +890,8 @@ const JSONToFile = (obj, filename) =>
cached.cache = cache;
return cached;
};
-
const merge = (...objs) =>
+
+const merge = (...objs) =>
[...objs].reduce(
(acc, obj) =>
Object.keys(obj).reduce((a, k) => {
@@ -711,11 +900,16 @@ const JSONToFile = (obj, filename) =>
}, {}),
{}
);
-
const midpoint = ([x1, y1], [x2, y2]) => [(x1 + x2) / 2, (y1 + y2) / 2];
-
const minBy = (arr, fn) => Math.min(...arr.map(typeof fn === 'function' ? fn : val => val[fn]));
-
const minDate = (...dates) => new Date(Math.min.apply(null, ...dates));
-
const minN = (arr, n = 1) => [...arr].sort((a, b) => a - b).slice(0, n);
-
const mostPerformant = (fns, iterations = 10000) => {
+
+const midpoint = ([x1, y1], [x2, y2]) => [(x1 + x2) / 2, (y1 + y2) / 2];
+
+const minBy = (arr, fn) => Math.min(...arr.map(typeof fn === 'function' ? fn : val => val[fn]));
+
+const minDate = (...dates) => new Date(Math.min.apply(null, ...dates));
+
+const minN = (arr, n = 1) => [...arr].sort((a, b) => a - b).slice(0, n);
+
+const mostPerformant = (fns, iterations = 10000) => {
const times = fns.map(fn => {
const before = performance.now();
for (let i = 0; i < iterations; i++) fn();
@@ -723,18 +917,27 @@ const JSONToFile = (obj, filename) =>
});
return times.indexOf(Math.min(...times));
};
-
const negate = func => (...args) => !func(...args);
-
const nest = (items, id = null, link = 'parent_id') =>
+
+const negate = func => (...args) => !func(...args);
+
+const nest = (items, id = null, link = 'parent_id') =>
items
.filter(item => item[link] === id)
.map(item => ({ ...item, children: nest(items, item.id) }));
-
const nodeListToArray = nodeList => [...nodeList];
-
const none = (arr, fn = Boolean) => !arr.some(fn);
-
const nthArg = n => (...args) => args.slice(n)[0];
-
const nthElement = (arr, n = 0) => (n === -1 ? arr.slice(n) : arr.slice(n, n + 1))[0];
-
const objectFromPairs = arr => arr.reduce((a, [key, val]) => ((a[key] = val), a), {});
-
const objectToPairs = obj => Object.keys(obj).map(k => [k, obj[k]]);
-
const observeMutations = (element, callback, options) => {
+
+const nodeListToArray = nodeList => [...nodeList];
+
+const none = (arr, fn = Boolean) => !arr.some(fn);
+
+const nthArg = n => (...args) => args.slice(n)[0];
+
+const nthElement = (arr, n = 0) => (n === -1 ? arr.slice(n) : arr.slice(n, n + 1))[0];
+
+const objectFromPairs = arr => arr.reduce((a, [key, val]) => ((a[key] = val), a), {});
+
+const objectToPairs = obj => Object.keys(obj).map(k => [k, obj[k]]);
+
+const observeMutations = (element, callback, options) => {
const observer = new MutationObserver(mutations => mutations.forEach(m => callback(m)));
observer.observe(
element,
@@ -752,22 +955,28 @@ const JSONToFile = (obj, filename) =>
);
return observer;
};
-
const off = (el, evt, fn, opts = false) => el.removeEventListener(evt, fn, opts);
-
const offset = (arr, offset) => [...arr.slice(offset), ...arr.slice(0, offset)];
-
const omit = (obj, arr) =>
+
+const off = (el, evt, fn, opts = false) => el.removeEventListener(evt, fn, opts);
+
+const offset = (arr, offset) => [...arr.slice(offset), ...arr.slice(0, offset)];
+
+const omit = (obj, arr) =>
Object.keys(obj)
.filter(k => !arr.includes(k))
.reduce((acc, key) => ((acc[key] = obj[key]), acc), {});
-
const omitBy = (obj, fn) =>
+
+const omitBy = (obj, fn) =>
Object.keys(obj)
.filter(k => !fn(obj[k], k))
.reduce((acc, key) => ((acc[key] = obj[key]), acc), {});
-
const on = (el, evt, fn, opts = {}) => {
+
+const on = (el, evt, fn, opts = {}) => {
const delegatorFn = e => e.target.matches(opts.target) && fn.call(e.target, e);
el.addEventListener(evt, opts.target ? delegatorFn : fn, opts.options || false);
if (opts.target) return delegatorFn;
};
-
const once = fn => {
+
+const once = fn => {
let called = false;
return function(...args) {
if (called) return;
@@ -775,7 +984,8 @@ const JSONToFile = (obj, filename) =>
return fn.apply(this, args);
};
};
-
const onUserInputChange = callback => {
+
+const onUserInputChange = callback => {
let type = 'mouse',
lastTime = 0;
const mousemoveHandler = () => {
@@ -789,7 +999,8 @@ const JSONToFile = (obj, filename) =>
(type = 'touch'), callback(type), document.addEventListener('mousemove', mousemoveHandler);
});
};
-
const orderBy = (arr, props, orders) =>
+
+const orderBy = (arr, props, orders) =>
[...arr].sort((a, b) =>
props.reduce((acc, prop, i) => {
if (acc === 0) {
@@ -799,15 +1010,20 @@ const JSONToFile = (obj, filename) =>
return acc;
}, 0)
);
-
const over = (...fns) => (...args) => fns.map(fn => fn.apply(null, args));
-
const overArgs = (fn, transforms) => (...args) => fn(...args.map((val, i) => transforms[i](val)));
-
const pad = (str, length, char = ' ') =>
+
+const over = (...fns) => (...args) => fns.map(fn => fn.apply(null, args));
+
+const overArgs = (fn, transforms) => (...args) => fn(...args.map((val, i) => transforms[i](val)));
+
+const pad = (str, length, char = ' ') =>
str.padStart((str.length + length) / 2, char).padEnd(length, char);
-
const palindrome = str => {
+
+const palindrome = str => {
const s = str.toLowerCase().replace(/[\W_]/g, '');
return s === [...s].reverse().join('');
};
-
const parseCookie = str =>
+
+const parseCookie = str =>
str
.split(';')
.map(v => v.split('='))
@@ -815,9 +1031,12 @@ const JSONToFile = (obj, filename) =>
acc[decodeURIComponent(v[0].trim())] = decodeURIComponent(v[1].trim());
return acc;
}, {});
-
const partial = (fn, ...partials) => (...args) => fn(...partials, ...args);
-
const partialRight = (fn, ...partials) => (...args) => fn(...args, ...partials);
-
const partition = (arr, fn) =>
+
+const partial = (fn, ...partials) => (...args) => fn(...partials, ...args);
+
+const partialRight = (fn, ...partials) => (...args) => fn(...args, ...partials);
+
+const partition = (arr, fn) =>
arr.reduce(
(acc, val, i, arr) => {
acc[fn(val, i, arr) ? 0 : 1].push(val);
@@ -825,9 +1044,11 @@ const JSONToFile = (obj, filename) =>
},
[[], []]
);
-
const percentile = (arr, val) =>
+
+const percentile = (arr, val) =>
(100 * arr.reduce((acc, v) => acc + (v < val ? 1 : 0) + (v === val ? 0.5 : 0), 0)) / arr.length;
-
const permutations = arr => {
+
+const permutations = arr => {
if (arr.length <= 2) return arr.length === 2 ? [arr, [arr[1], arr[0]]] : arr;
return arr.reduce(
(acc, item, i) =>
@@ -837,22 +1058,29 @@ const JSONToFile = (obj, filename) =>
[]
);
};
-
const pick = (obj, arr) =>
+
+const pick = (obj, arr) =>
arr.reduce((acc, curr) => (curr in obj && (acc[curr] = obj[curr]), acc), {});
-
const pickBy = (obj, fn) =>
+
+const pickBy = (obj, fn) =>
Object.keys(obj)
.filter(k => fn(obj[k], k))
.reduce((acc, key) => ((acc[key] = obj[key]), acc), {});
-
const pipeAsyncFunctions = (...fns) => arg => fns.reduce((p, f) => p.then(f), Promise.resolve(arg));
-
const pipeFunctions = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args)));
-
const pluralize = (val, word, plural = word + 's') => {
+
+const pipeAsyncFunctions = (...fns) => arg => fns.reduce((p, f) => p.then(f), Promise.resolve(arg));
+
+const pipeFunctions = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args)));
+
+const pluralize = (val, word, plural = word + 's') => {
const _pluralize = (num, word, plural = word + 's') =>
[1, -1].includes(Number(num)) ? word : plural;
if (typeof val === 'object') return (num, word) => _pluralize(num, word, val[word]);
return _pluralize(val, word, plural);
};
-
const powerset = arr => arr.reduce((a, v) => a.concat(a.map(r => [v].concat(r))), [[]]);
-
const prefix = prop => {
+
+const powerset = arr => arr.reduce((a, v) => a.concat(a.map(r => [v].concat(r))), [[]]);
+
+const prefix = prop => {
const capitalizedProp = prop.charAt(0).toUpperCase() + prop.slice(1);
const prefixes = ['', 'webkit', 'moz', 'ms', 'o'];
const i = prefixes.findIndex(
@@ -860,31 +1088,36 @@ const JSONToFile = (obj, filename) =>
);
return i !== -1 ? (i === 0 ? prop : prefixes[i] + capitalizedProp) : null;
};
-
const prettyBytes = (num, precision = 3, addSpace = true) => {
+
+const prettyBytes = (num, precision = 3, addSpace = true) => {
const UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
if (Math.abs(num) < 1) return num + (addSpace ? ' ' : '') + UNITS[0];
const exponent = Math.min(Math.floor(Math.log10(num < 0 ? -num : num) / 3), UNITS.length - 1);
const n = Number(((num < 0 ? -num : num) / 1000 ** exponent).toPrecision(precision));
return (num < 0 ? '-' : '') + n + (addSpace ? ' ' : '') + UNITS[exponent];
};
-
const primes = num => {
+
+const primes = num => {
let arr = Array.from({ length: num - 1 }).map((x, i) => i + 2),
sqroot = Math.floor(Math.sqrt(num)),
numsTillSqroot = Array.from({ length: sqroot - 1 }).map((x, i) => i + 2);
numsTillSqroot.forEach(x => (arr = arr.filter(y => y % x !== 0 || y === x)));
return arr;
};
-
const promisify = func => (...args) =>
+
+const promisify = func => (...args) =>
new Promise((resolve, reject) =>
func(...args, (err, result) => (err ? reject(err) : resolve(result)))
);
-
const pull = (arr, ...args) => {
+
+const pull = (arr, ...args) => {
let argState = Array.isArray(args[0]) ? args[0] : args;
let pulled = arr.filter((v, i) => !argState.includes(v));
arr.length = 0;
pulled.forEach(v => arr.push(v));
};
-
const pullAtIndex = (arr, pullArr) => {
+
+const pullAtIndex = (arr, pullArr) => {
let removed = [];
let pulled = arr
.map((v, i) => (pullArr.includes(i) ? removed.push(v) : v))
@@ -893,7 +1126,8 @@ const JSONToFile = (obj, filename) =>
pulled.forEach(v => arr.push(v));
return removed;
};
-
const pullAtValue = (arr, pullArr) => {
+
+const pullAtValue = (arr, pullArr) => {
let removed = [],
pushToRemove = arr.forEach((v, i) => (pullArr.includes(v) ? removed.push(v) : v)),
mutateTo = arr.filter((v, i) => !pullArr.includes(v));
@@ -901,7 +1135,8 @@ const JSONToFile = (obj, filename) =>
mutateTo.forEach(v => arr.push(v));
return removed;
};
-
const pullBy = (arr, ...args) => {
+
+const pullBy = (arr, ...args) => {
const length = args.length;
let fn = length > 1 ? args[length - 1] : undefined;
fn = typeof fn == 'function' ? (args.pop(), fn) : undefined;
@@ -910,23 +1145,31 @@ const JSONToFile = (obj, filename) =>
arr.length = 0;
pulled.forEach(v => arr.push(v));
};
-
const radsToDegrees = rad => (rad * 180.0) / Math.PI;
-
const randomHexColorCode = () => {
+
+const radsToDegrees = rad => (rad * 180.0) / Math.PI;
+
+const randomHexColorCode = () => {
let n = (Math.random() * 0xfffff * 1000000).toString(16);
return '#' + n.slice(0, 6);
};
-
const randomIntArrayInRange = (min, max, n = 1) =>
+
+const randomIntArrayInRange = (min, max, n = 1) =>
Array.from({ length: n }, () => Math.floor(Math.random() * (max - min + 1)) + min);
-
const randomIntegerInRange = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
-
const randomNumberInRange = (min, max) => Math.random() * (max - min) + min;
-
+
+const randomIntegerInRange = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
+
+const randomNumberInRange = (min, max) => Math.random() * (max - min) + min;
+
+
const readFileLines = filename =>
fs
.readFileSync(filename)
.toString('UTF8')
.split('\n');
-
const rearg = (fn, indexes) => (...args) => fn(...indexes.map(i => args[i]));
-
const recordAnimationFrames = (callback, autoStart = true) => {
+
+const rearg = (fn, indexes) => (...args) => fn(...indexes.map(i => args[i]));
+
+const recordAnimationFrames = (callback, autoStart = true) => {
let running = true,
raf;
const stop = () => {
@@ -946,29 +1189,37 @@ const readFileLines = filename =>
if (autoStart) start();
return { start, stop };
};
-
const redirect = (url, asLink = true) =>
+
+const redirect = (url, asLink = true) =>
asLink ? (window.location.href = url) : window.location.replace(url);
-
const reducedFilter = (data, keys, fn) =>
+
+const reducedFilter = (data, keys, fn) =>
data.filter(fn).map(el =>
keys.reduce((acc, key) => {
acc[key] = el[key];
return acc;
}, {})
);
-
const reduceSuccessive = (arr, fn, acc) =>
+
+const reduceSuccessive = (arr, fn, acc) =>
arr.reduce((res, val, i, arr) => (res.push(fn(res.slice(-1)[0], val, i, arr)), res), [acc]);
-
const reduceWhich = (arr, comparator = (a, b) => a - b) =>
+
+const reduceWhich = (arr, comparator = (a, b) => a - b) =>
arr.reduce((a, b) => (comparator(a, b) >= 0 ? b : a));
-
const reject = (pred, array) => array.filter((...args) => !pred(...args));
-
const remove = (arr, func) =>
+
+const reject = (pred, array) => array.filter((...args) => !pred(...args));
+
+const remove = (arr, func) =>
Array.isArray(arr)
? arr.filter(func).reduce((acc, val) => {
arr.splice(arr.indexOf(val), 1);
return acc.concat(val);
}, [])
: [];
-
const removeNonASCII = str => str.replace(/[^\x20-\x7E]/g, '');
-
const renameKeys = (keysMap, obj) =>
+
+const removeNonASCII = str => str.replace(/[^\x20-\x7E]/g, '');
+
+const renameKeys = (keysMap, obj) =>
Object.keys(obj).reduce(
(acc, key) => ({
...acc,
@@ -976,10 +1227,14 @@ const readFileLines = filename =>
}),
{}
);
-
const reverseString = str => [...str].reverse().join('');
-
const RGBToHex = (r, g, b) => ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0');
-
const round = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`);
-
const runAsync = fn => {
+
+const reverseString = str => [...str].reverse().join('');
+
+const RGBToHex = (r, g, b) => ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0');
+
+const round = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`);
+
+const runAsync = fn => {
const worker = new Worker(
URL.createObjectURL(new Blob([`postMessage((${fn})());`]), {
type: 'application/javascript; charset=utf-8'
@@ -994,9 +1249,12 @@ const readFileLines = filename =>
};
});
};
-
const runPromisesInSeries = ps => ps.reduce((p, next) => p.then(next), Promise.resolve());
-
const sample = arr => arr[Math.floor(Math.random() * arr.length)];
-
const sampleSize = ([...arr], n = 1) => {
+
+const runPromisesInSeries = ps => ps.reduce((p, next) => p.then(next), Promise.resolve());
+
+const sample = arr => arr[Math.floor(Math.random() * arr.length)];
+
+const sampleSize = ([...arr], n = 1) => {
let m = arr.length;
while (m) {
const i = Math.floor(Math.random() * m--);
@@ -1004,14 +1262,16 @@ const readFileLines = filename =>
}
return arr.slice(0, n);
};
-
const scrollToTop = () => {
+
+const scrollToTop = () => {
const c = document.documentElement.scrollTop || document.body.scrollTop;
if (c > 0) {
window.requestAnimationFrame(scrollToTop);
window.scrollTo(0, c - c / 8);
}
};
-
const sdbm = str => {
+
+const sdbm = str => {
let arr = str.split('');
return arr.reduce(
(hashCode, currentVal) =>
@@ -1019,16 +1279,22 @@ const readFileLines = filename =>
0
);
};
-
const serializeCookie = (name, val) => `${encodeURIComponent(name)}=${encodeURIComponent(val)}`;
-
const setStyle = (el, ruleName, val) => (el.style[ruleName] = val);
-
const shallowClone = obj => Object.assign({}, obj);
-
const shank = (arr, index = 0, delCount = 0, ...elements) =>
+
+const serializeCookie = (name, val) => `${encodeURIComponent(name)}=${encodeURIComponent(val)}`;
+
+const setStyle = (el, ruleName, val) => (el.style[ruleName] = val);
+
+const shallowClone = obj => Object.assign({}, obj);
+
+const shank = (arr, index = 0, delCount = 0, ...elements) =>
arr
.slice(0, index)
.concat(elements)
.concat(arr.slice(index + delCount));
-
const show = (...el) => [...el].forEach(e => (e.style.display = ''));
-
const shuffle = ([...arr]) => {
+
+const show = (...el) => [...el].forEach(e => (e.style.display = ''));
+
+const shuffle = ([...arr]) => {
let m = arr.length;
while (m) {
const i = Math.floor(Math.random() * m--);
@@ -1036,8 +1302,10 @@ const readFileLines = filename =>
}
return arr;
};
-
const similarity = (arr, values) => arr.filter(v => values.includes(v));
-
const size = val =>
+
+const similarity = (arr, values) => arr.filter(v => values.includes(v));
+
+const size = val =>
Array.isArray(val)
? val.length
: val && typeof val === 'object'
@@ -1045,29 +1313,36 @@ const readFileLines = filename =>
: typeof val === 'string'
? new Blob([val]).size
: 0;
-
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
-
const smoothScroll = element =>
+
+const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
+
+const smoothScroll = element =>
document.querySelector(element).scrollIntoView({
behavior: 'smooth'
});
-
const sortCharactersInString = str => [...str].sort((a, b) => a.localeCompare(b)).join('');
-
const sortedIndex = (arr, n) => {
+
+const sortCharactersInString = str => [...str].sort((a, b) => a.localeCompare(b)).join('');
+
+const sortedIndex = (arr, n) => {
const isDescending = arr[0] > arr[arr.length - 1];
const index = arr.findIndex(el => (isDescending ? n >= el : n <= el));
return index === -1 ? arr.length : index;
};
-
const sortedIndexBy = (arr, n, fn) => {
+
+const sortedIndexBy = (arr, n, fn) => {
const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]);
const val = fn(n);
const index = arr.findIndex(el => (isDescending ? val >= fn(el) : val <= fn(el)));
return index === -1 ? arr.length : index;
};
-
const sortedLastIndex = (arr, n) => {
+
+const sortedLastIndex = (arr, n) => {
const isDescending = arr[0] > arr[arr.length - 1];
const index = arr.reverse().findIndex(el => (isDescending ? n <= el : n >= el));
return index === -1 ? 0 : arr.length - index;
};
-
const sortedLastIndexBy = (arr, n, fn) => {
+
+const sortedLastIndexBy = (arr, n, fn) => {
const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]);
const val = fn(n);
const index = arr
@@ -1076,21 +1351,25 @@ const readFileLines = filename =>
.findIndex(el => (isDescending ? val <= el : val >= el));
return index === -1 ? 0 : arr.length - index;
};
-
const splitLines = str => str.split(/\r?\n/);
-const spreadOver = fn => argsArr => fn(...argsArr);
-
const stableSort = (arr, compare) =>
+
+const splitLines = str => str.split(/\r?\n/);
+const spreadOver = fn => argsArr => fn(...argsArr);
+
+const stableSort = (arr, compare) =>
arr
.map((item, index) => ({ item, index }))
.sort((a, b) => compare(a.item, b.item) || a.index - b.index)
.map(({ item }) => item);
-
const standardDeviation = (arr, usePopulation = false) => {
+
+const standardDeviation = (arr, usePopulation = false) => {
const mean = arr.reduce((acc, val) => acc + val, 0) / arr.length;
return Math.sqrt(
arr.reduce((acc, val) => acc.concat((val - mean) ** 2), []).reduce((acc, val) => acc + val, 0) /
(arr.length - (usePopulation ? 0 : 1))
);
};
-
const stringPermutations = str => {
+
+const stringPermutations = str => {
if (str.length <= 2) return str.length === 2 ? [str, str[1] + str[0]] : [str];
return str
.split('')
@@ -1100,39 +1379,52 @@ const spreadOver = fn => argsArr => fn(...argsArr);
[]
);
};
-
const stripHTMLTags = str => str.replace(/<[^>]*>/g, '');
-
const sum = (...arr) => [...arr].reduce((acc, val) => acc + val, 0);
-
const sumBy = (arr, fn) =>
+
+const stripHTMLTags = str => str.replace(/<[^>]*>/g, '');
+
+const sum = (...arr) => [...arr].reduce((acc, val) => acc + val, 0);
+
+const sumBy = (arr, fn) =>
arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0);
-
const sumPower = (end, power = 2, start = 1) =>
+
+const sumPower = (end, power = 2, start = 1) =>
Array(end + 1 - start)
.fill(0)
.map((x, i) => (i + start) ** power)
.reduce((a, b) => a + b, 0);
-
const symmetricDifference = (a, b) => {
+
+const symmetricDifference = (a, b) => {
const sA = new Set(a),
sB = new Set(b);
return [...a.filter(x => !sB.has(x)), ...b.filter(x => !sA.has(x))];
};
-
const symmetricDifferenceBy = (a, b, fn) => {
+
+const symmetricDifferenceBy = (a, b, fn) => {
const sA = new Set(a.map(v => fn(v))),
sB = new Set(b.map(v => fn(v)));
return [...a.filter(x => !sB.has(fn(x))), ...b.filter(x => !sA.has(fn(x)))];
};
-
const symmetricDifferenceWith = (arr, val, comp) => [
+
+const symmetricDifferenceWith = (arr, val, comp) => [
...arr.filter(a => val.findIndex(b => comp(a, b)) === -1),
...val.filter(a => arr.findIndex(b => comp(a, b)) === -1)
];
-
const tail = arr => (arr.length > 1 ? arr.slice(1) : arr);
-
const take = (arr, n = 1) => arr.slice(0, n);
-
const takeRight = (arr, n = 1) => arr.slice(arr.length - n, arr.length);
-
const takeRightWhile = (arr, func) =>
+
+const tail = arr => (arr.length > 1 ? arr.slice(1) : arr);
+
+const take = (arr, n = 1) => arr.slice(0, n);
+
+const takeRight = (arr, n = 1) => arr.slice(arr.length - n, arr.length);
+
+const takeRightWhile = (arr, func) =>
arr.reduceRight((acc, el) => (func(el) ? acc : [el, ...acc]), []);
-
const takeWhile = (arr, func) => {
+
+const takeWhile = (arr, func) => {
for (const [i, val] of arr.entries()) if (func(val)) return arr.slice(0, i);
return arr;
};
-
const throttle = (fn, wait) => {
+
+const throttle = (fn, wait) => {
let inThrottle, lastFn, lastTime;
return function() {
const context = this,
@@ -1152,17 +1444,20 @@ const spreadOver = fn => argsArr => fn(...argsArr);
}
};
};
-
const times = (n, fn, context = undefined) => {
+
+const times = (n, fn, context = undefined) => {
let i = 0;
while (fn.call(context, i) !== false && ++i < n) {}
};
-
const timeTaken = callback => {
+
+const timeTaken = callback => {
console.time('timeTaken');
const r = callback();
console.timeEnd('timeTaken');
return r;
};
-
const toCamelCase = str => {
+
+const toCamelCase = str => {
let s =
str &&
str
@@ -1171,23 +1466,29 @@ const spreadOver = fn => argsArr => fn(...argsArr);
.join('');
return s.slice(0, 1).toLowerCase() + s.slice(1);
};
-
const toCurrency = (n, curr, LanguageFormat = undefined) =>
+
+const toCurrency = (n, curr, LanguageFormat = undefined) =>
Intl.NumberFormat(LanguageFormat, { style: 'currency', currency: curr }).format(n);
-
const toDecimalMark = num => num.toLocaleString('en-US');
-
const toggleClass = (el, className) => el.classList.toggle(className);
-
const toHash = (object, key) =>
+
+const toDecimalMark = num => num.toLocaleString('en-US');
+
+const toggleClass = (el, className) => el.classList.toggle(className);
+
+const toHash = (object, key) =>
Array.prototype.reduce.call(
object,
(acc, data, index) => ((acc[!key ? index : data[key]] = data), acc),
{}
);
-
const toKebabCase = str =>
+
+const toKebabCase = str =>
str &&
str
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
.map(x => x.toLowerCase())
.join('-');
-
const tomorrow = (long = false) => {
+
+const tomorrow = (long = false) => {
let t = new Date();
t.setDate(t.getDate() + 1);
const ret = `${t.getFullYear()}-${String(t.getMonth() + 1).padStart(2, '0')}-${String(
@@ -1195,7 +1496,8 @@ const spreadOver = fn => argsArr => fn(...argsArr);
).padStart(2, '0')}`;
return !long ? ret : `${ret}T00:00:00`;
};
-
const toOrdinalSuffix = num => {
+
+const toOrdinalSuffix = num => {
const int = parseInt(num),
digits = [int % 10, int % 100],
ordinals = ['st', 'nd', 'rd', 'th'],
@@ -1205,32 +1507,42 @@ const spreadOver = fn => argsArr => fn(...argsArr);
? int + ordinals[digits[0] - 1]
: int + ordinals[3];
};
-
const toSafeInteger = num =>
+
+const toSafeInteger = num =>
Math.round(Math.max(Math.min(num, Number.MAX_SAFE_INTEGER), Number.MIN_SAFE_INTEGER));
-
const toSnakeCase = str =>
+
+const toSnakeCase = str =>
str &&
str
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
.map(x => x.toLowerCase())
.join('_');
-
const toTitleCase = str =>
+
+const toTitleCase = str =>
str
.match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
.map(x => x.charAt(0).toUpperCase() + x.slice(1))
.join(' ');
-
const transform = (obj, fn, acc) => Object.keys(obj).reduce((a, k) => fn(a, obj[k], k, obj), acc);
-
const triggerEvent = (el, eventType, detail) =>
+
+const transform = (obj, fn, acc) => Object.keys(obj).reduce((a, k) => fn(a, obj[k], k, obj), acc);
+
+const triggerEvent = (el, eventType, detail) =>
el.dispatchEvent(new CustomEvent(eventType, { detail }));
-
const truncateString = (str, num) =>
+
+const truncateString = (str, num) =>
str.length > num ? str.slice(0, num > 3 ? num - 3 : num) + '...' : str;
-
const truthCheckCollection = (collection, pre) => collection.every(obj => obj[pre]);
-
const unary = fn => val => fn(val);
-
const uncurry = (fn, n = 1) => (...args) => {
+
+const truthCheckCollection = (collection, pre) => collection.every(obj => obj[pre]);
+
+const unary = fn => val => fn(val);
+
+const uncurry = (fn, n = 1) => (...args) => {
const next = acc => args => args.reduce((x, y) => x(y), acc);
if (n > args.length) throw new RangeError('Arguments too few!');
return next(fn)(args.slice(0, n));
};
-
const unescapeHTML = str =>
+
+const unescapeHTML = str =>
str.replace(
/&|<|>|'|"/g,
tag =>
@@ -1242,7 +1554,8 @@ const spreadOver = fn => argsArr => fn(...argsArr);
'"': '"'
}[tag] || tag)
);
-
const unflattenObject = obj =>
+
+const unflattenObject = obj =>
Object.keys(obj).reduce((acc, k) => {
if (k.indexOf('.') !== -1) {
const keys = k.split('.');
@@ -1258,42 +1571,53 @@ const spreadOver = fn => argsArr => fn(...argsArr);
} else acc[k] = obj[k];
return acc;
}, {});
-
const unfold = (fn, seed) => {
+
+const unfold = (fn, seed) => {
let result = [],
val = [null, seed];
while ((val = fn(val[1]))) result.push(val[0]);
return result;
};
-
const union = (a, b) => Array.from(new Set([...a, ...b]));
-
const unionBy = (a, b, fn) => {
+
+const union = (a, b) => Array.from(new Set([...a, ...b]));
+
+const unionBy = (a, b, fn) => {
const s = new Set(a.map(fn));
return Array.from(new Set([...a, ...b.filter(x => !s.has(fn(x)))]));
};
-
const unionWith = (a, b, comp) =>
+
+const unionWith = (a, b, comp) =>
Array.from(new Set([...a, ...b.filter(x => a.findIndex(y => comp(x, y)) === -1)]));
-
const uniqueElements = arr => [...new Set(arr)];
-
const uniqueElementsBy = (arr, fn) =>
+
+const uniqueElements = arr => [...new Set(arr)];
+
+const uniqueElementsBy = (arr, fn) =>
arr.reduce((acc, v) => {
if (!acc.some(x => fn(v, x))) acc.push(v);
return acc;
}, []);
-
const uniqueElementsByRight = (arr, fn) =>
+
+const uniqueElementsByRight = (arr, fn) =>
arr.reduceRight((acc, v) => {
if (!acc.some(x => fn(v, x))) acc.push(v);
return acc;
}, []);
-
const uniqueSymmetricDifference = (a, b) => [
+
+const uniqueSymmetricDifference = (a, b) => [
...new Set([...a.filter(v => !b.includes(v)), ...b.filter(v => !a.includes(v))])
];
-
const untildify = str => str.replace(/^~($|\/|\\)/, `${require('os').homedir()}$1`);
-
const unzip = arr =>
+
+const untildify = str => str.replace(/^~($|\/|\\)/, `${require('os').homedir()}$1`);
+
+const unzip = arr =>
arr.reduce(
(acc, val) => (val.forEach((v, i) => acc[i].push(v)), acc),
Array.from({
length: Math.max(...arr.map(x => x.length))
}).map(x => [])
);
-
const unzipWith = (arr, fn) =>
+
+const unzipWith = (arr, fn) =>
arr
.reduce(
(acc, val) => (val.forEach((v, i) => acc[i].push(v)), acc),
@@ -1302,7 +1626,8 @@ const spreadOver = fn => argsArr => fn(...argsArr);
}).map(x => [])
)
.map(val => fn(...val));
-
const URLJoin = (...args) =>
+
+const URLJoin = (...args) =>
args
.join('/')
.replace(/[\/]+/g, '/')
@@ -1311,46 +1636,60 @@ const spreadOver = fn => argsArr => fn(...argsArr);
.replace(/\/(\?|&|#[^!])/g, '$1')
.replace(/\?/g, '&')
.replace('&', '?');
-
const UUIDGeneratorBrowser = () =>
+
+const UUIDGeneratorBrowser = () =>
([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
(c ^ (crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))).toString(16)
);
-
+
+
const UUIDGeneratorNode = () =>
([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
(c ^ (crypto.randomBytes(1)[0] & (15 >> (c / 4)))).toString(16)
);
-
const validateNumber = n => !isNaN(parseFloat(n)) && isFinite(n) && Number(n) == n;
-
const when = (pred, whenTrue) => x => (pred(x) ? whenTrue(x) : x);
-
const without = (arr, ...args) => arr.filter(v => !args.includes(v));
-
const words = (str, pattern = /[^a-zA-Z-]+/) => str.split(pattern).filter(Boolean);
-
const xProd = (a, b) => a.reduce((acc, x) => acc.concat(b.map(y => [x, y])), []);
-
const yesNo = (val, def = false) =>
+
+const validateNumber = n => !isNaN(parseFloat(n)) && isFinite(n) && Number(n) == n;
+
+const when = (pred, whenTrue) => x => (pred(x) ? whenTrue(x) : x);
+
+const without = (arr, ...args) => arr.filter(v => !args.includes(v));
+
+const words = (str, pattern = /[^a-zA-Z-]+/) => str.split(pattern).filter(Boolean);
+
+const xProd = (a, b) => a.reduce((acc, x) => acc.concat(b.map(y => [x, y])), []);
+
+const yesNo = (val, def = false) =>
/^(y|yes)$/i.test(val) ? true : /^(n|no)$/i.test(val) ? false : def;
-
const zip = (...arrays) => {
+
+const zip = (...arrays) => {
const maxLength = Math.max(...arrays.map(x => x.length));
return Array.from({ length: maxLength }).map((_, i) => {
return Array.from({ length: arrays.length }, (_, k) => arrays[k][i]);
});
};
-
const zipObject = (props, values) =>
+
+const zipObject = (props, values) =>
props.reduce((obj, prop, index) => ((obj[prop] = values[index]), obj), {});
-
const zipWith = (...array) => {
+
+const zipWith = (...array) => {
const fn = typeof array[array.length - 1] === 'function' ? array.pop() : undefined;
return Array.from(
{ length: Math.max(...array.map(a => a.length)) },
(_, i) => (fn ? fn(...array.map(a => a[i])) : array.map(a => a[i]))
);
};
-
const binarySearch = (arr, val, start = 0, end = arr.length - 1) => {
+
+const binarySearch = (arr, val, start = 0, end = arr.length - 1) => {
if (start > end) return -1;
const mid = Math.floor((start + end) / 2);
if (arr[mid] > val) return binarySearch(arr, val, start, mid - 1);
if (arr[mid] < val) return binarySearch(arr, val, mid + 1, end);
return mid;
};
-
const celsiusToFahrenheit = degrees => 1.8 * degrees + 32;
-
const cleanObj = (obj, keysToKeep = [], childIndicator) => {
+
+const celsiusToFahrenheit = degrees => 1.8 * degrees + 32;
+
+const cleanObj = (obj, keysToKeep = [], childIndicator) => {
Object.keys(obj).forEach(key => {
if (key === childIndicator) {
cleanObj(obj[key], keysToKeep, childIndicator);
@@ -1360,9 +1699,12 @@ const UUIDGeneratorNode = () =>
});
return obj;
};
-
const collatz = n => (n % 2 === 0 ? n / 2 : 3 * n + 1);
-
const countVowels = str => (str.match(/[aeiou]/gi) || []).length;
-
const factors = (num, primes = false) => {
+
+const collatz = n => (n % 2 === 0 ? n / 2 : 3 * n + 1);
+
+const countVowels = str => (str.match(/[aeiou]/gi) || []).length;
+
+const factors = (num, primes = false) => {
const isPrime = num => {
const boundary = Math.floor(Math.sqrt(num));
for (var i = 2; i <= boundary; i++) if (num % i === 0) return false;
@@ -1381,21 +1723,26 @@ const UUIDGeneratorNode = () =>
}, []);
return primes ? array.filter(isPrime) : array;
};
-
const fahrenheitToCelsius = degrees => (degrees - 32) * 5/9;
-
const fibonacciCountUntilNum = num =>
+
+const fahrenheitToCelsius = degrees => (degrees - 32) * 5/9;
+
+const fibonacciCountUntilNum = num =>
Math.ceil(Math.log(num * Math.sqrt(5) + 1 / 2) / Math.log((Math.sqrt(5) + 1) / 2));
-
const fibonacciUntilNum = num => {
+
+const fibonacciUntilNum = num => {
let n = Math.ceil(Math.log(num * Math.sqrt(5) + 1 / 2) / Math.log((Math.sqrt(5) + 1) / 2));
return Array.from({ length: n }).reduce(
(acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i),
[]
);
};
-
const heronArea = (side_a, side_b, side_c) => {
+
+const heronArea = (side_a, side_b, side_c) => {
const p = (side_a + side_b + side_c) / 2
return Math.sqrt(p * (p-side_a) * (p-side_b) * (p-side_c))
};
-
const howManyTimes = (num, divisor) => {
+
+const howManyTimes = (num, divisor) => {
if (divisor === 1 || divisor === -1) return Infinity;
if (divisor === 0) return 0;
let i = 0;
@@ -1405,14 +1752,16 @@ const UUIDGeneratorNode = () =>
}
return i;
};
-
const httpDelete = (url, callback, err = console.error) => {
+
+const httpDelete = (url, callback, err = console.error) => {
const request = new XMLHttpRequest();
request.open('DELETE', url, true);
request.onload = () => callback(request);
request.onerror = () => err(request);
request.send();
};
-
const httpPut = (url, data, callback, err = console.error) => {
+
+const httpPut = (url, data, callback, err = console.error) => {
const request = new XMLHttpRequest();
request.open("PUT", url, true);
request.setRequestHeader('Content-type','application/json; charset=utf-8');
@@ -1420,11 +1769,13 @@ const UUIDGeneratorNode = () =>
request.onerror = () => err(request);
request.send(data);
};
-
const isArmstrongNumber = digits =>
+
+const isArmstrongNumber = digits =>
(arr => arr.reduce((a, d) => a + parseInt(d) ** arr.length, 0) == digits)(
(digits + '').split('')
);
-
const isSimilar = (pattern, str) =>
+
+const isSimilar = (pattern, str) =>
[...str].reduce(
(matchIndex, char) =>
char.toLowerCase() === (pattern[matchIndex] || '').toLowerCase()
@@ -1432,12 +1783,15 @@ const UUIDGeneratorNode = () =>
: matchIndex,
0
) === pattern.length;
-
const JSONToDate = arr => {
+
+const JSONToDate = arr => {
const dt = new Date(parseInt(arr.toString().substr(6)));
return `${dt.getDate()}/${dt.getMonth() + 1}/${dt.getFullYear()}`;
};
-
const kmphToMph = (kmph) => 0.621371192 * kmph;
-
const levenshteinDistance = (string1, string2) => {
+
+const kmphToMph = (kmph) => 0.621371192 * kmph;
+
+const levenshteinDistance = (string1, string2) => {
if (string1.length === 0) return string2.length;
if (string2.length === 0) return string1.length;
let matrix = Array(string2.length + 1)
@@ -1461,9 +1815,12 @@ const UUIDGeneratorNode = () =>
}
return matrix[string2.length][string1.length];
};
-
const mphToKmph = (mph) => 1.6093440006146922 * mph;
-
const pipeLog = data => console.log(data) || data;
-
const quickSort = ([n, ...nums], desc) =>
+
+const mphToKmph = (mph) => 1.6093440006146922 * mph;
+
+const pipeLog = data => console.log(data) || data;
+
+const quickSort = ([n, ...nums], desc) =>
isNaN(n)
? []
: [
@@ -1471,8 +1828,10 @@ const UUIDGeneratorNode = () =>
n,
...quickSort(nums.filter(v => (!desc ? v > n : v <= n)), desc)
];
-
const removeVowels = (str, repl = '') => str.replace(/[aeiou]/gi, repl);
-
const solveRPN = rpn => {
+
+const removeVowels = (str, repl = '') => str.replace(/[aeiou]/gi, repl);
+
+const solveRPN = rpn => {
const OPERATORS = {
'*': (a, b) => a * b,
'+': (a, b) => a + b,
@@ -1500,12 +1859,14 @@ const UUIDGeneratorNode = () =>
if (stack.length === 1) return stack.pop();
else throw `${rpn} is not a proper RPN. Please check it and try again`;
};
-
const speechSynthesis = message => {
+
+const speechSynthesis = message => {
const msg = new SpeechSynthesisUtterance(message);
msg.voice = window.speechSynthesis.getVoices()[0];
window.speechSynthesis.speak(msg);
};
-
const squareSum = (...args) => args.reduce((squareSum, number) => squareSum + Math.pow(number, 2), 0);
-
-
+
+const squareSum = (...args) => args.reduce((squareSum, number) => squareSum + Math.pow(number, 2), 0);
+
+
module.exports = {all,allEqual,any,approximatelyEqual,arrayToCSV,arrayToHtmlList,ary,atob,attempt,average,averageBy,bifurcate,bifurcateBy,bind,bindAll,bindKey,binomialCoefficient,bottomVisible,btoa,byteSize,call,capitalize,capitalizeEveryWord,castArray,chainAsync,chunk,clampNumber,cloneRegExp,coalesce,coalesceFactory,collectInto,colorize,compact,compose,composeRight,converge,copyToClipboard,countBy,counter,countOccurrences,createDirIfNotExists,createElement,createEventHub,CSVToArray,CSVToJSON,currentURL,curry,dayOfYear,debounce,decapitalize,deepClone,deepFlatten,deepFreeze,deepMapKeys,defaults,defer,degreesToRads,delay,detectDeviceType,difference,differenceBy,differenceWith,dig,digitize,distance,drop,dropRight,dropRightWhile,dropWhile,elementContains,elementIsVisibleInViewport,elo,equals,escapeHTML,escapeRegExp,everyNth,extendHex,factorial,fibonacci,filterFalsy,filterNonUnique,filterNonUniqueBy,findKey,findLast,findLastIndex,findLastKey,flatten,flattenObject,flip,forEachRight,formatDuration,forOwn,forOwnRight,fromCamelCase,functionName,functions,gcd,geometricProgression,get,getColonTimeFromDate,getDaysDiffBetweenDates,getImages,getMeridiemSuffixOfInteger,getScrollPosition,getStyle,getType,getURLParameters,groupBy,hammingDistance,hasClass,hasFlags,hashBrowser,hashNode,head,hexToRGB,hide,httpGet,httpPost,httpsRedirect,hz,indentString,indexOfAll,initial,initialize2DArray,initializeArrayWithRange,initializeArrayWithRangeRight,initializeArrayWithValues,initializeNDArray,inRange,insertAfter,insertBefore,intersection,intersectionBy,intersectionWith,invertKeyValues,is,isAbsoluteURL,isAfterDate,isAnagram,isArrayLike,isBeforeDate,isBoolean,isBrowser,isBrowserTabFocused,isDivisible,isDuplexStream,isEmpty,isEven,isFunction,isLowerCase,isNegativeZero,isNil,isNull,isNumber,isObject,isObjectLike,isPlainObject,isPrime,isPrimitive,isPromiseLike,isReadableStream,isSameDate,isSorted,isStream,isString,isSymbol,isTravisCI,isUndefined,isUpperCase,isValidJSON,isWritableStream,join,JSONtoCSV,JSONToFile,last,lcm,longestItem,lowercaseKeys,luhnCheck,mapKeys,mapObject,mapString,mapValues,mask,matches,matchesWith,maxBy,maxDate,maxN,median,memoize,merge,midpoint,minBy,minDate,minN,mostPerformant,negate,nest,nodeListToArray,none,nthArg,nthElement,objectFromPairs,objectToPairs,observeMutations,off,offset,omit,omitBy,on,once,onUserInputChange,orderBy,over,overArgs,pad,palindrome,parseCookie,partial,partialRight,partition,percentile,permutations,pick,pickBy,pipeAsyncFunctions,pipeFunctions,pluralize,powerset,prefix,prettyBytes,primes,promisify,pull,pullAtIndex,pullAtValue,pullBy,radsToDegrees,randomHexColorCode,randomIntArrayInRange,randomIntegerInRange,randomNumberInRange,readFileLines,rearg,recordAnimationFrames,redirect,reducedFilter,reduceSuccessive,reduceWhich,reject,remove,removeNonASCII,renameKeys,reverseString,RGBToHex,round,runAsync,runPromisesInSeries,sample,sampleSize,scrollToTop,sdbm,serializeCookie,setStyle,shallowClone,shank,show,shuffle,similarity,size,sleep,smoothScroll,sortCharactersInString,sortedIndex,sortedIndexBy,sortedLastIndex,sortedLastIndexBy,splitLines,spreadOver,stableSort,standardDeviation,stringPermutations,stripHTMLTags,sum,sumBy,sumPower,symmetricDifference,symmetricDifferenceBy,symmetricDifferenceWith,tail,take,takeRight,takeRightWhile,takeWhile,throttle,times,timeTaken,toCamelCase,toCurrency,toDecimalMark,toggleClass,toHash,toKebabCase,tomorrow,toOrdinalSuffix,toSafeInteger,toSnakeCase,toTitleCase,transform,triggerEvent,truncateString,truthCheckCollection,unary,uncurry,unescapeHTML,unflattenObject,unfold,union,unionBy,unionWith,uniqueElements,uniqueElementsBy,uniqueElementsByRight,uniqueSymmetricDifference,untildify,unzip,unzipWith,URLJoin,UUIDGeneratorBrowser,UUIDGeneratorNode,validateNumber,when,without,words,xProd,yesNo,zip,zipObject,zipWith,binarySearch,celsiusToFahrenheit,cleanObj,collatz,countVowels,factors,fahrenheitToCelsius,fibonacciCountUntilNum,fibonacciUntilNum,heronArea,howManyTimes,httpDelete,httpPut,isArmstrongNumber,isSimilar,JSONToDate,kmphToMph,levenshteinDistance,mphToKmph,pipeLog,quickSort,removeVowels,solveRPN,speechSynthesis,squareSum}
\ No newline at end of file