From af0f433975acfde4145d2bff8cbc0302ade5353b Mon Sep 17 00:00:00 2001 From: Angelos Chalaris Date: Sat, 12 Jan 2019 11:42:14 +0200 Subject: [PATCH] Fixed issues with deepClone, built everything --- README.md | 5729 ++++++++++++++++---------------- dist/_30s.es5.js | 452 +-- dist/_30s.es5.min.js | 2 +- dist/_30s.esm.js | 158 +- dist/_30s.js | 188 +- docs/adapter.html | 2 +- docs/index.html | 3 +- docs/math.html | 4 +- docs/object.html | 12 +- snippets/deepClone.md | 6 +- snippets/dig.md | 6 +- snippets/factorial.md | 4 +- snippets/pipeAsyncFunctions.md | 2 +- snippets/remove.md | 1 - test/_30s.js | 3002 ++++++++--------- test/deepClone.test.js | 43 +- 16 files changed, 4816 insertions(+), 4798 deletions(-) diff --git a/README.md b/README.md index 662798ee4..c07e77033 100644 --- a/README.md +++ b/README.md @@ -1,73 +1,73 @@ -[![Logo](/logo.png)](https://30secondsofcode.org/) - -# 30 seconds of code - -[![License](https://img.shields.io/badge/license-CC0--1.0-blue.svg)](https://github.com/30-seconds/30-seconds-of-code/blob/master/LICENSE) [![npm Downloads](https://img.shields.io/npm/dt/30-seconds-of-code.svg)](https://www.npmjs.com/package/30-seconds-of-code) [![npm Version](https://img.shields.io/npm/v/30-seconds-of-code.svg)](https://www.npmjs.com/package/30-seconds-of-code) [![Known Vulnerabilities](https://snyk.io/test/github/30-seconds/30-seconds-of-code/badge.svg?targetFile=package.json)](https://snyk.io/test/github/30-seconds/30-seconds-of-code?targetFile=package.json)
-[![Travis Build](https://travis-ci.com/30-seconds/30-seconds-of-code.svg?branch=master)](https://travis-ci.com/30-seconds/30-seconds-of-code) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/6ab7791fb1ea40b4a576d658fb96807f)](https://www.codacy.com/app/Chalarangelo/30-seconds-of-code?utm_source=github.com&utm_medium=referral&utm_content=30-seconds/30-seconds-of-code&utm_campaign=Badge_Grade) [![js-semistandard-style](https://img.shields.io/badge/code%20style-semistandard-brightgreen.svg)](https://github.com/Flet/semistandard)
-[![Awesome](https://awesome.re/badge.svg)](https://awesome.re) [![ProductHunt](https://img.shields.io/badge/producthunt-vote-orange.svg)](https://www.producthunt.com/posts/30-seconds-of-code) [![Gitter chat](https://img.shields.io/badge/chat-on%20gitter-4FB999.svg)](https://gitter.im/30-seconds-of-code/Lobby) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com) - -> Curated collection of useful JavaScript snippets that you can understand in 30 seconds or less. - -[![Sponsored by DigitalOcean](/sponsored_by_DigitalOcean.png)](https://www.digitalocean.com) - -* Use Ctrl + F or command + F to search for a snippet. -* Contributions welcome, please read the [contribution guide](CONTRIBUTING.md). -* Snippets are written in ES6, use the [Babel transpiler](https://babeljs.io/) to ensure backwards-compatibility. -* You can import these snippets into VSCode, by following the instructions found [here](https://github.com/30-seconds/30-seconds-of-code/tree/master/vscode_snippets). -* You can search, view and copy these snippets from a terminal, using the CLI application from [this repo](https://github.com/sQVe/30s). -* If you want to follow 30-seconds-of-code on social media, you can find us on [Facebook](https://www.facebook.com/30secondsofcode), [Instagram](https://www.instagram.com/30secondsofcode) and [Twitter](https://twitter.com/30secondsofcode). - -#### Related projects - -* [30 Seconds of CSS](https://30-seconds.github.io/30-seconds-of-css/) -* [30 Seconds of Interviews](https://30secondsofinterviews.org/) -* [30 Seconds of React](https://github.com/30-seconds/30-seconds-of-react) -* [30 Seconds of Python](https://github.com/kriadmin/30-seconds-of-python-code) _(unofficial)_ -* [30 Seconds of PHP](https://github.com/appzcoder/30-seconds-of-php-code) _(unofficial)_ - -#### Package - -⚠️ **NOTICE:** A few of our snippets are not yet optimized for production (see disclaimers for individual snippet issues). - -You can find a package with all the snippets on [npm](https://www.npmjs.com/package/30-seconds-of-code). - -```bash -# With npm -npm install 30-seconds-of-code - -# With yarn -yarn add 30-seconds-of-code -``` - -[CDN link](https://unpkg.com/30-seconds-of-code/) - -
-Details - -**Browser** - -```html - - -``` - -**Node** - -```js -// CommonJS -const _30s = require('30-seconds-of-code'); -_30s.average(1, 2, 3); - -// ES Modules -import _30s from '30-seconds-of-code'; -_30s.average(1, 2, 3); -``` - -
- -## Contents +[![Logo](/logo.png)](https://30secondsofcode.org/) + +# 30 seconds of code + +[![License](https://img.shields.io/badge/license-CC0--1.0-blue.svg)](https://github.com/30-seconds/30-seconds-of-code/blob/master/LICENSE) [![npm Downloads](https://img.shields.io/npm/dt/30-seconds-of-code.svg)](https://www.npmjs.com/package/30-seconds-of-code) [![npm Version](https://img.shields.io/npm/v/30-seconds-of-code.svg)](https://www.npmjs.com/package/30-seconds-of-code) [![Known Vulnerabilities](https://snyk.io/test/github/30-seconds/30-seconds-of-code/badge.svg?targetFile=package.json)](https://snyk.io/test/github/30-seconds/30-seconds-of-code?targetFile=package.json)
+[![Travis Build](https://travis-ci.com/30-seconds/30-seconds-of-code.svg?branch=master)](https://travis-ci.com/30-seconds/30-seconds-of-code) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/6ab7791fb1ea40b4a576d658fb96807f)](https://www.codacy.com/app/Chalarangelo/30-seconds-of-code?utm_source=github.com&utm_medium=referral&utm_content=30-seconds/30-seconds-of-code&utm_campaign=Badge_Grade) [![js-semistandard-style](https://img.shields.io/badge/code%20style-semistandard-brightgreen.svg)](https://github.com/Flet/semistandard)
+[![Awesome](https://awesome.re/badge.svg)](https://awesome.re) [![ProductHunt](https://img.shields.io/badge/producthunt-vote-orange.svg)](https://www.producthunt.com/posts/30-seconds-of-code) [![Gitter chat](https://img.shields.io/badge/chat-on%20gitter-4FB999.svg)](https://gitter.im/30-seconds-of-code/Lobby) [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com) + +> Curated collection of useful JavaScript snippets that you can understand in 30 seconds or less. + +[![Sponsored by DigitalOcean](/sponsored_by_DigitalOcean.png)](https://www.digitalocean.com) + +* Use Ctrl + F or command + F to search for a snippet. +* Contributions welcome, please read the [contribution guide](CONTRIBUTING.md). +* Snippets are written in ES6, use the [Babel transpiler](https://babeljs.io/) to ensure backwards-compatibility. +* You can import these snippets into VSCode, by following the instructions found [here](https://github.com/30-seconds/30-seconds-of-code/tree/master/vscode_snippets). +* You can search, view and copy these snippets from a terminal, using the CLI application from [this repo](https://github.com/sQVe/30s). +* If you want to follow 30-seconds-of-code on social media, you can find us on [Facebook](https://www.facebook.com/30secondsofcode), [Instagram](https://www.instagram.com/30secondsofcode) and [Twitter](https://twitter.com/30secondsofcode). + +#### Related projects + +* [30 Seconds of CSS](https://30-seconds.github.io/30-seconds-of-css/) +* [30 Seconds of Interviews](https://30secondsofinterviews.org/) +* [30 Seconds of React](https://github.com/30-seconds/30-seconds-of-react) +* [30 Seconds of Python](https://github.com/kriadmin/30-seconds-of-python-code) _(unofficial)_ +* [30 Seconds of PHP](https://github.com/appzcoder/30-seconds-of-php-code) _(unofficial)_ + +#### Package + +⚠️ **NOTICE:** A few of our snippets are not yet optimized for production (see disclaimers for individual snippet issues). + +You can find a package with all the snippets on [npm](https://www.npmjs.com/package/30-seconds-of-code). + +```bash +# With npm +npm install 30-seconds-of-code + +# With yarn +yarn add 30-seconds-of-code +``` + +[CDN link](https://unpkg.com/30-seconds-of-code/) + +
+Details + +**Browser** + +```html + + +``` + +**Node** + +```js +// CommonJS +const _30s = require('30-seconds-of-code'); +_30s.average(1, 2, 3); + +// ES Modules +import _30s from '30-seconds-of-code'; +_30s.average(1, 2, 3); +``` + +
+ +## Contents ### 🔌 Adapter @@ -503,12 +503,12 @@ _30s.average(1, 2, 3); ## 🔌 Adapter -### ary - -Creates a function that accepts up to `n` arguments, ignoring any additional arguments. - -Call the provided function, `fn`, with up to `n` arguments, using `Array.prototype.slice(0,n)` and the spread operator (`...`). - +### ary + +Creates a function that accepts up to `n` arguments, ignoring any additional arguments. + +Call the provided function, `fn`, with up to `n` arguments, using `Array.prototype.slice(0,n)` and the spread operator (`...`). + ```js const ary = (fn, n) => (...args) => fn(...args.slice(0, n)); ``` @@ -519,7 +519,7 @@ const ary = (fn, n) => (...args) => fn(...args.slice(0, n)); ```js const firstTwoMax = ary(Math.max, 2); [[2, 6, 'a'], [8, 4, 6], [10]].map(x => firstTwoMax(...x)); // [6, 8, 10] -``` +``` @@ -604,12 +604,12 @@ Object.assign(b, a); // == b
[⬆ Back to top](#contents) -### over - -Creates a function that invokes each provided function with the arguments it receives and returns the results. - -Use `Array.prototype.map()` and `Function.prototype.apply()` to apply each function to the given arguments. - +### over + +Creates a function that invokes each provided function with the arguments it receives and returns the results. + +Use `Array.prototype.map()` and `Function.prototype.apply()` to apply each function to the given arguments. + ```js const over = (...fns) => (...args) => fns.map(fn => fn.apply(null, args)); ``` @@ -620,18 +620,18 @@ const over = (...fns) => (...args) => fns.map(fn => fn.apply(null, args)); ```js const minMax = over(Math.min, Math.max); minMax(1, 2, 3, 4, 5); // [1,5] -``` +```
[⬆ Back to top](#contents) -### overArgs - -Creates a function that invokes the provided function with its arguments transformed. - -Use `Array.prototype.map()` to apply `transforms` to `args` in combination with the spread operator (`...`) to pass the transformed arguments to `fn`. - +### overArgs + +Creates a function that invokes the provided function with its arguments transformed. + +Use `Array.prototype.map()` to apply `transforms` to `args` in combination with the spread operator (`...`) to pass the transformed arguments to `fn`. + ```js const overArgs = (fn, transforms) => (...args) => fn(...args.map((val, i) => transforms[i](val))); ``` @@ -644,50 +644,50 @@ const square = n => n * n; const double = n => n * 2; const fn = overArgs((x, y) => [x, y], [square, double]); fn(9, 3); // [81, 6] -``` +```
[⬆ Back to top](#contents) -### pipeAsyncFunctions - -Performs left-to-right function composition for asynchronous functions. - -Use `Array.prototype.reduce()` with the spread operator (`...`) to perform left-to-right function composition using `Promise.then()`. -The functions can return a combination of: simple values, `Promise`'s, or they can be defined as `async` ones returning through `await`. -All functions must be unary. - +### pipeAsyncFunctions + +Performs left-to-right function composition for asynchronous functions. + +Use `Array.prototype.reduce()` with the spread operator (`...`) to perform left-to-right function composition using `Promise.then()`. +The functions can return a combination of: simple values, `Promise`'s, or they can be defined as `async` ones returning through `await`. +All functions must be unary. + ```js -const pipeAsyncFunctions = (...fns) => arg => fns.reduce((p, f) => p.then(f), Promise.resolve(arg)); +const pipeAsyncFunctions = (...fns) => arg => fns.reduce((p, f) => p.then(f), Promise.resolve(arg)); ```
Examples ```js -const sum = pipeAsyncFunctions( - x => x + 1, - x => new Promise(resolve => setTimeout(() => resolve(x + 2), 1000)), - x => x + 3, - async x => (await x) + 4 -); -(async () => { - console.log(await sum(5)); // 15 (after one second) -})(); -``` +const sum = pipeAsyncFunctions( + x => x + 1, + x => new Promise(resolve => setTimeout(() => resolve(x + 2), 1000)), + x => x + 3, + async x => (await x) + 4 +); +(async() => { + console.log(await sum(5)); // 15 (after one second) +})(); +```

[⬆ Back to top](#contents) -### pipeFunctions - -Performs left-to-right function composition. - -Use `Array.prototype.reduce()` with the spread operator (`...`) to perform left-to-right function composition. -The first (leftmost) function can accept one or more arguments; the remaining functions must be unary. - +### pipeFunctions + +Performs left-to-right function composition. + +Use `Array.prototype.reduce()` with the spread operator (`...`) to perform left-to-right function composition. +The first (leftmost) function can accept one or more arguments; the remaining functions must be unary. + ```js const pipeFunctions = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args))); ``` @@ -700,21 +700,21 @@ const add5 = x => x + 5; const multiply = (x, y) => x * y; const multiplyAndAdd5 = pipeFunctions(multiply, add5); multiplyAndAdd5(5, 2); // 15 -``` +```
[⬆ Back to top](#contents) -### promisify - -Converts an asynchronous function to return a promise. - -Use currying to return a function returning a `Promise` that calls the original function. -Use the `...rest` operator to pass in all the parameters. - -*In Node 8+, you can use [`util.promisify`](https://nodejs.org/api/util.html#util_util_promisify_original)* - +### promisify + +Converts an asynchronous function to return a promise. + +Use currying to return a function returning a `Promise` that calls the original function. +Use the `...rest` operator to pass in all the parameters. + +*In Node 8+, you can use [`util.promisify`](https://nodejs.org/api/util.html#util_util_promisify_original)* + ```js const promisify = func => (...args) => new Promise((resolve, reject) => @@ -728,18 +728,18 @@ const promisify = func => (...args) => ```js const delay = promisify((d, cb) => setTimeout(cb, d)); delay(2000).then(() => console.log('Hi!')); // // Promise resolves after 2s -``` +```
[⬆ Back to top](#contents) -### rearg - -Creates a function that invokes the provided function with its arguments arranged according to the specified indexes. - -Use `Array.prototype.map()` to reorder arguments based on `indexes` in combination with the spread operator (`...`) to pass the transformed arguments to `fn`. - +### rearg + +Creates a function that invokes the provided function with its arguments arranged according to the specified indexes. + +Use `Array.prototype.map()` to reorder arguments based on `indexes` in combination with the spread operator (`...`) to pass the transformed arguments to `fn`. + ```js const rearg = (fn, indexes) => (...args) => fn(...indexes.map(i => args[i])); ``` @@ -755,7 +755,7 @@ var rearged = rearg( [2, 0, 1] ); rearged('b', 'c', 'a'); // ['a', 'b', 'c'] -``` +``` @@ -783,12 +783,12 @@ arrayMax([1, 2, 3]); // 3
[⬆ Back to top](#contents) -### unary - -Creates a function that accepts up to one argument, ignoring any additional arguments. - -Call the provided function, `fn`, with just the first argument given. - +### unary + +Creates a function that accepts up to one argument, ignoring any additional arguments. + +Call the provided function, `fn`, with just the first argument given. + ```js const unary = fn => val => fn(val); ``` @@ -798,7 +798,7 @@ const unary = fn => val => fn(val); ```js ['6', '8', '10'].map(unary(parseInt)); // [6, 8, 10] -``` +``` @@ -809,13 +809,13 @@ const unary = fn => val => fn(val); ## 📚 Array -### all - -Returns `true` if the provided predicate function returns `true` for all elements in a collection, `false` otherwise. - -Use `Array.prototype.every()` to test if all elements in the collection return `true` based on `fn`. -Omit the second argument, `fn`, to use `Boolean` as a default. - +### all + +Returns `true` if the provided predicate function returns `true` for all elements in a collection, `false` otherwise. + +Use `Array.prototype.every()` to test if all elements in the collection return `true` based on `fn`. +Omit the second argument, `fn`, to use `Boolean` as a default. + ```js const all = (arr, fn = Boolean) => arr.every(fn); ``` @@ -826,18 +826,18 @@ const all = (arr, fn = Boolean) => arr.every(fn); ```js all([4, 2, 3], x => x > 1); // true all([1, 2, 3]); // true -``` +```
[⬆ Back to top](#contents) -### allEqual - -Check if all elements in an array are equal. - -Use `Array.prototype.every()` to check if all the elements of the array are the same as the first one. - +### allEqual + +Check if all elements in an array are equal. + +Use `Array.prototype.every()` to check if all the elements of the array are the same as the first one. + ```js const allEqual = arr => arr.every(val => val === arr[0]); ``` @@ -848,19 +848,19 @@ const allEqual = arr => arr.every(val => val === arr[0]); ```js allEqual([1, 2, 3, 4, 5, 6]); // false allEqual([1, 1, 1, 1]); // true -``` +```
[⬆ Back to top](#contents) -### any - -Returns `true` if the provided predicate function returns `true` for at least one element in a collection, `false` otherwise. - -Use `Array.prototype.some()` to test if any elements in the collection return `true` based on `fn`. -Omit the second argument, `fn`, to use `Boolean` as a default. - +### any + +Returns `true` if the provided predicate function returns `true` for at least one element in a collection, `false` otherwise. + +Use `Array.prototype.some()` to test if any elements in the collection return `true` based on `fn`. +Omit the second argument, `fn`, to use `Boolean` as a default. + ```js const any = (arr, fn = Boolean) => arr.some(fn); ``` @@ -871,20 +871,20 @@ const any = (arr, fn = Boolean) => arr.some(fn); ```js any([0, 1, 2, 0], x => x >= 2); // true any([0, 0, 1, 0]); // true -``` +```
[⬆ Back to top](#contents) -### arrayToCSV - -Converts a 2D array to a comma-separated values (CSV) string. - -Use `Array.prototype.map()` and `Array.prototype.join(delimiter)` to combine individual 1D arrays (rows) into strings. -Use `Array.prototype.join('\n')` to combine all rows into a CSV string, separating each row with a newline. -Omit the second argument, `delimiter`, to use a default delimiter of `,`. - +### arrayToCSV + +Converts a 2D array to a comma-separated values (CSV) string. + +Use `Array.prototype.map()` and `Array.prototype.join(delimiter)` to combine individual 1D arrays (rows) into strings. +Use `Array.prototype.join('\n')` to combine all rows into a CSV string, separating each row with a newline. +Omit the second argument, `delimiter`, to use a default delimiter of `,`. + ```js const arrayToCSV = (arr, delimiter = ',') => arr.map(v => v.map(x => `"${x}"`).join(delimiter)).join('\n'); @@ -896,18 +896,18 @@ const arrayToCSV = (arr, delimiter = ',') => ```js arrayToCSV([['a', 'b'], ['c', 'd']]); // '"a","b"\n"c","d"' arrayToCSV([['a', 'b'], ['c', 'd']], ';'); // '"a";"b"\n"c";"d"' -``` +```
[⬆ Back to top](#contents) -### bifurcate - -Splits values into two groups. If an element in `filter` is truthy, the corresponding element in the collection belongs to the first group; otherwise, it belongs to the second group. - -Use `Array.prototype.reduce()` and `Array.prototype.push()` to add elements to groups, based on `filter`. - +### bifurcate + +Splits values into two groups. If an element in `filter` is truthy, the corresponding element in the collection belongs to the first group; otherwise, it belongs to the second group. + +Use `Array.prototype.reduce()` and `Array.prototype.push()` to add elements to groups, based on `filter`. + ```js const bifurcate = (arr, filter) => arr.reduce((acc, val, i) => (acc[filter[i] ? 0 : 1].push(val), acc), [[], []]); @@ -918,18 +918,18 @@ const bifurcate = (arr, filter) => ```js bifurcate(['beep', 'boop', 'foo', 'bar'], [true, true, false, true]); // [ ['beep', 'boop', 'bar'], ['foo'] ] -``` +```
[⬆ Back to top](#contents) -### bifurcateBy - -Splits values into two groups according to a predicate function, which specifies which group an element in the input collection belongs to. If the predicate function returns a truthy value, the collection element belongs to the first group; otherwise, it belongs to the second group. - -Use `Array.prototype.reduce()` and `Array.prototype.push()` to add elements to groups, based on the value returned by `fn` for each element. - +### bifurcateBy + +Splits values into two groups according to a predicate function, which specifies which group an element in the input collection belongs to. If the predicate function returns a truthy value, the collection element belongs to the first group; otherwise, it belongs to the second group. + +Use `Array.prototype.reduce()` and `Array.prototype.push()` to add elements to groups, based on the value returned by `fn` for each element. + ```js const bifurcateBy = (arr, fn) => arr.reduce((acc, val, i) => (acc[fn(val, i) ? 0 : 1].push(val), acc), [[], []]); @@ -940,20 +940,20 @@ const bifurcateBy = (arr, fn) => ```js bifurcateBy(['beep', 'boop', 'foo', 'bar'], x => x[0] === 'b'); // [ ['beep', 'boop', 'bar'], ['foo'] ] -``` +```
[⬆ Back to top](#contents) -### chunk - -Chunks an array into smaller arrays of a specified size. - -Use `Array.from()` to create a new array, that fits the number of chunks that will be produced. -Use `Array.prototype.slice()` to map each element of the new array to a chunk the length of `size`. -If the original array can't be split evenly, the final chunk will contain the remaining elements. - +### chunk + +Chunks an array into smaller arrays of a specified size. + +Use `Array.from()` to create a new array, that fits the number of chunks that will be produced. +Use `Array.prototype.slice()` to map each element of the new array to a chunk the length of `size`. +If the original array can't be split evenly, the final chunk will contain the remaining elements. + ```js const chunk = (arr, size) => Array.from({ length: Math.ceil(arr.length / size) }, (v, i) => @@ -966,18 +966,18 @@ const chunk = (arr, size) => ```js chunk([1, 2, 3, 4, 5], 2); // [[1,2],[3,4],[5]] -``` +```
[⬆ Back to top](#contents) -### compact - -Removes falsey values from an array. - -Use `Array.prototype.filter()` to filter out falsey values (`false`, `null`, `0`, `""`, `undefined`, and `NaN`). - +### compact + +Removes falsey values from an array. + +Use `Array.prototype.filter()` to filter out falsey values (`false`, `null`, `0`, `""`, `undefined`, and `NaN`). + ```js const compact = arr => arr.filter(Boolean); ``` @@ -987,45 +987,45 @@ const compact = arr => arr.filter(Boolean); ```js compact([0, 1, false, 2, '', 3, 'a', 'e' * 23, NaN, 's', 34]); // [ 1, 2, 3, 'a', 's', 34 ] -``` +```
[⬆ Back to top](#contents) -### countBy - -Groups the elements of an array based on the given function and returns the count of elements in each group. - -Use `Array.prototype.map()` to map the values of an array to a function or property name. -Use `Array.prototype.reduce()` to create an object, where the keys are produced from the mapped results. - +### countBy + +Groups the elements of an array based on the given function and returns the count of elements in each group. + +Use `Array.prototype.map()` to map the values of an array to a function or property name. +Use `Array.prototype.reduce()` to create an object, where the keys are produced from the mapped results. + ```js -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 countBy = (arr, fn) => + arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => { + acc[val] = (acc[val] || 0) + 1; + return acc; + }, {}); ```
Examples ```js -countBy([6.1, 4.2, 6.3], Math.floor); // {4: 1, 6: 2} -countBy(['one', 'two', 'three'], 'length'); // {3: 2, 5: 1} -``` +countBy([6.1, 4.2, 6.3], Math.floor); // {4: 1, 6: 2} +countBy(['one', 'two', 'three'], 'length'); // {3: 2, 5: 1} +```

[⬆ Back to top](#contents) -### countOccurrences - -Counts the occurrences of a value in an array. - -Use `Array.prototype.reduce()` to increment a counter each time you encounter the specific value inside the array. - +### countOccurrences + +Counts the occurrences of a value in an array. + +Use `Array.prototype.reduce()` to increment a counter each time you encounter the specific value inside the array. + ```js const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0); ``` @@ -1035,20 +1035,20 @@ const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : ```js countOccurrences([1, 1, 2, 1, 2, 3], 1); // 3 -``` +```
[⬆ Back to top](#contents) -### deepFlatten - -Deep flattens an array. - -Use recursion. -Use `Array.prototype.concat()` with an empty array (`[]`) and the spread operator (`...`) to flatten an array. -Recursively flatten each element that is an array. - +### deepFlatten + +Deep flattens an array. + +Use recursion. +Use `Array.prototype.concat()` with an empty array (`[]`) and the spread operator (`...`) to flatten an array. +Recursively flatten each element that is an array. + ```js const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v))); ``` @@ -1058,18 +1058,18 @@ const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFla ```js deepFlatten([1, [2], [[3], 4], 5]); // [1,2,3,4,5] -``` +```
[⬆ Back to top](#contents) -### difference - -Returns the difference between two arrays. - -Create a `Set` from `b`, then use `Array.prototype.filter()` on `a` to only keep values not contained in `b`. - +### difference + +Returns the difference between two arrays. + +Create a `Set` from `b`, then use `Array.prototype.filter()` on `a` to only keep values not contained in `b`. + ```js const difference = (a, b) => { const s = new Set(b); @@ -1082,43 +1082,43 @@ const difference = (a, b) => { ```js difference([1, 2, 3], [1, 2, 4]); // [3] -``` +```
[⬆ Back to top](#contents) -### differenceBy - -Returns the difference between two arrays, after applying the provided function to each array element of both. - -Create a `Set` by applying `fn` to each element in `b`, then use `Array.prototype.filter()` in combination with `fn` on `a` to only keep values not contained in the previously created set. - +### differenceBy + +Returns the difference between two arrays, after applying the provided function to each array element of both. + +Create a `Set` by applying `fn` to each element in `b`, then use `Array.prototype.filter()` in combination with `fn` on `a` to only keep values not contained in the previously created set. + ```js -const differenceBy = (a, b, fn) => { - const s = new Set(b.map(fn)); - return a.filter(x => !s.has(fn(x))); -}; +const differenceBy = (a, b, fn) => { + const s = new Set(b.map(fn)); + return a.filter(x => !s.has(fn(x))); +}; ```
Examples ```js -differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [1.2] -differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], v => v.x); // [ { x: 2 } ] -``` +differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [1.2] +differenceBy([{ x: 2 }, { x: 1 }], [{ x: 1 }], v => v.x); // [ { x: 2 } ] +```

[⬆ Back to top](#contents) -### differenceWith - -Filters out all values from an array for which the comparator function does not return `true`. - -Use `Array.prototype.filter()` and `Array.prototype.findIndex()` to find the appropriate values. - +### differenceWith + +Filters out all values from an array for which the comparator function does not return `true`. + +Use `Array.prototype.filter()` and `Array.prototype.findIndex()` to find the appropriate values. + ```js const differenceWith = (arr, val, comp) => arr.filter(a => val.findIndex(b => comp(a, b)) === -1); ``` @@ -1128,18 +1128,18 @@ const differenceWith = (arr, val, comp) => arr.filter(a => val.findIndex(b => co ```js differenceWith([1, 1.2, 1.5, 3, 0], [1.9, 3, 0], (a, b) => Math.round(a) === Math.round(b)); // [1, 1.2] -``` +```
[⬆ Back to top](#contents) -### drop - -Returns a new array with `n` elements removed from the left. - -Use `Array.prototype.slice()` to slice the remove the specified number of elements from the left. - +### drop + +Returns a new array with `n` elements removed from the left. + +Use `Array.prototype.slice()` to slice the remove the specified number of elements from the left. + ```js const drop = (arr, n = 1) => arr.slice(n); ``` @@ -1151,18 +1151,18 @@ const drop = (arr, n = 1) => arr.slice(n); drop([1, 2, 3]); // [2,3] drop([1, 2, 3], 2); // [3] drop([1, 2, 3], 42); // [] -``` +```
[⬆ Back to top](#contents) -### dropRight - -Returns a new array with `n` elements removed from the right. - -Use `Array.prototype.slice()` to slice the remove the specified number of elements from the right. - +### dropRight + +Returns a new array with `n` elements removed from the right. + +Use `Array.prototype.slice()` to slice the remove the specified number of elements from the right. + ```js const dropRight = (arr, n = 1) => arr.slice(0, -n); ``` @@ -1174,19 +1174,19 @@ const dropRight = (arr, n = 1) => arr.slice(0, -n); dropRight([1, 2, 3]); // [1,2] dropRight([1, 2, 3], 2); // [1] dropRight([1, 2, 3], 42); // [] -``` +```
[⬆ Back to top](#contents) -### dropRightWhile - -Removes elements from the end of an array until the passed function returns `true`. Returns the remaining elements in the array. - -Loop through the array, using `Array.prototype.slice()` to drop the last element of the array until the returned value from the function is `true`. -Returns the remaining elements. - +### dropRightWhile + +Removes elements from the end of an array until the passed function returns `true`. Returns the remaining elements in the array. + +Loop through the array, using `Array.prototype.slice()` to drop the last element of the array until the returned value from the function is `true`. +Returns the remaining elements. + ```js const dropRightWhile = (arr, func) => { while (arr.length > 0 && !func(arr[arr.length - 1])) arr = arr.slice(0, -1); @@ -1199,19 +1199,19 @@ const dropRightWhile = (arr, func) => { ```js dropRightWhile([1, 2, 3, 4], n => n < 3); // [1, 2] -``` +```
[⬆ Back to top](#contents) -### dropWhile - -Removes elements in an array until the passed function returns `true`. Returns the remaining elements in the array. - -Loop through the array, using `Array.prototype.slice()` to drop the first element of the array until the returned value from the function is `true`. -Returns the remaining elements. - +### dropWhile + +Removes elements in an array until the passed function returns `true`. Returns the remaining elements in the array. + +Loop through the array, using `Array.prototype.slice()` to drop the first element of the array until the returned value from the function is `true`. +Returns the remaining elements. + ```js const dropWhile = (arr, func) => { while (arr.length > 0 && !func(arr[0])) arr = arr.slice(1); @@ -1224,18 +1224,18 @@ const dropWhile = (arr, func) => { ```js dropWhile([1, 2, 3, 4], n => n >= 3); // [3,4] -``` +```
[⬆ Back to top](#contents) -### everyNth - -Returns every nth element in an array. - -Use `Array.prototype.filter()` to create a new array that contains every nth element of a given array. - +### everyNth + +Returns every nth element in an array. + +Use `Array.prototype.filter()` to create a new array that contains every nth element of a given array. + ```js const everyNth = (arr, nth) => arr.filter((e, i) => i % nth === nth - 1); ``` @@ -1245,7 +1245,7 @@ const everyNth = (arr, nth) => arr.filter((e, i) => i % nth === nth - 1); ```js everyNth([1, 2, 3, 4, 5, 6], 2); // [ 2, 4, 6 ] -``` +``` @@ -1272,12 +1272,12 @@ filterFalsy(['', true, {}, false, 'sample', 1, 0]); // [true, {}, 'sample', 1]
[⬆ Back to top](#contents) -### filterNonUnique - -Filters out the non-unique values in an array. - -Use `Array.prototype.filter()` for an array containing only the unique values. - +### filterNonUnique + +Filters out the non-unique values in an array. + +Use `Array.prototype.filter()` for an array containing only the unique values. + ```js const filterNonUnique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexOf(i)); ``` @@ -1287,19 +1287,19 @@ const filterNonUnique = arr => arr.filter(i => arr.indexOf(i) === arr.lastIndexO ```js filterNonUnique([1, 2, 2, 3, 4, 4, 5]); // [1, 3, 5] -``` +```
[⬆ Back to top](#contents) -### filterNonUniqueBy - -Filters out the non-unique values in an array, based on a provided comparator function. - -Use `Array.prototype.filter()` and `Array.prototype.every()` for an array containing only the unique values, based on the comparator function, `fn`. -The comparator function takes four arguments: the values of the two elements being compared and their indexes. - +### filterNonUniqueBy + +Filters out the non-unique values in an array, based on a provided comparator function. + +Use `Array.prototype.filter()` and `Array.prototype.every()` for an array containing only the unique values, based on the comparator function, `fn`. +The comparator function takes four arguments: the values of the two elements being compared and their indexes. + ```js const filterNonUniqueBy = (arr, fn) => arr.filter((v, i) => arr.every((x, j) => (i === j) === fn(v, x, i, j))); @@ -1319,18 +1319,18 @@ filterNonUniqueBy( ], (a, b) => a.id == b.id ); // [ { id: 2, value: 'c' } ] -``` +```
[⬆ Back to top](#contents) -### findLast - -Returns the last element for which the provided function returns a truthy value. - -Use `Array.prototype.filter()` to remove elements for which `fn` returns falsey values, `Array.prototype.pop()` to get the last one. - +### findLast + +Returns the last element for which the provided function returns a truthy value. + +Use `Array.prototype.filter()` to remove elements for which `fn` returns falsey values, `Array.prototype.pop()` to get the last one. + ```js const findLast = (arr, fn) => arr.filter(fn).pop(); ``` @@ -1340,19 +1340,19 @@ const findLast = (arr, fn) => arr.filter(fn).pop(); ```js findLast([1, 2, 3, 4], n => n % 2 === 1); // 3 -``` +```
[⬆ Back to top](#contents) -### findLastIndex - -Returns the index of the last element for which the provided function returns a truthy value. - -Use `Array.prototype.map()` to map each element to an array with its index and value. -Use `Array.prototype.filter()` to remove elements for which `fn` returns falsey values, `Array.prototype.pop()` to get the last one. - +### findLastIndex + +Returns the index of the last element for which the provided function returns a truthy value. + +Use `Array.prototype.map()` to map each element to an array with its index and value. +Use `Array.prototype.filter()` to remove elements for which `fn` returns falsey values, `Array.prototype.pop()` to get the last one. + ```js const findLastIndex = (arr, fn) => arr @@ -1366,21 +1366,21 @@ const findLastIndex = (arr, fn) => ```js findLastIndex([1, 2, 3, 4], n => n % 2 === 1); // 2 (index of the value 3) -``` +```
[⬆ Back to top](#contents) -### flatten - -Flattens an array up to the specified depth. - -Use recursion, decrementing `depth` by 1 for each level of depth. -Use `Array.prototype.reduce()` and `Array.prototype.concat()` to merge elements or arrays. -Base case, for `depth` equal to `1` stops recursion. -Omit the second argument, `depth` to flatten only to a depth of `1` (single flatten). - +### flatten + +Flattens an array up to the specified depth. + +Use recursion, decrementing `depth` by 1 for each level of depth. +Use `Array.prototype.reduce()` and `Array.prototype.concat()` to merge elements or arrays. +Base case, for `depth` equal to `1` stops recursion. +Omit the second argument, `depth` to flatten only to a depth of `1` (single flatten). + ```js const flatten = (arr, depth = 1) => arr.reduce((a, v) => a.concat(depth > 1 && Array.isArray(v) ? flatten(v, depth - 1) : v), []); @@ -1392,18 +1392,18 @@ const flatten = (arr, depth = 1) => ```js flatten([1, [2], 3, 4]); // [1, 2, 3, 4] flatten([1, [2, [3, [4, 5], 6], 7], 8], 2); // [1, 2, 3, [4, 5], 6, 7, 8] -``` +```
[⬆ Back to top](#contents) -### forEachRight - -Executes a provided function once for each array element, starting from the array's last element. - -Use `Array.prototype.slice(0)` to clone the given array, `Array.prototype.reverse()` to reverse it and `Array.prototype.forEach()` to iterate over the reversed array. - +### forEachRight + +Executes a provided function once for each array element, starting from the array's last element. + +Use `Array.prototype.slice(0)` to clone the given array, `Array.prototype.reverse()` to reverse it and `Array.prototype.forEach()` to iterate over the reversed array. + ```js const forEachRight = (arr, callback) => arr @@ -1417,19 +1417,19 @@ const forEachRight = (arr, callback) => ```js forEachRight([1, 2, 3, 4], val => console.log(val)); // '4', '3', '2', '1' -``` +```
[⬆ Back to top](#contents) -### groupBy - -Groups the elements of an array based on the given function. - -Use `Array.prototype.map()` to map the values of an array to a function or property name. -Use `Array.prototype.reduce()` to create an object, where the keys are produced from the mapped results. - +### groupBy + +Groups the elements of an array based on the given function. + +Use `Array.prototype.map()` to map the values of an array to a function or property name. +Use `Array.prototype.reduce()` to create an object, where the keys are produced from the mapped results. + ```js const groupBy = (arr, fn) => arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val, i) => { @@ -1444,18 +1444,18 @@ const groupBy = (arr, fn) => ```js groupBy([6.1, 4.2, 6.3], Math.floor); // {4: [4.2], 6: [6.1, 6.3]} groupBy(['one', 'two', 'three'], 'length'); // {3: ['one', 'two'], 5: ['three']} -``` +```
[⬆ Back to top](#contents) -### head - -Returns the head of a list. - -Use `arr[0]` to return the first element of the passed array. - +### head + +Returns the head of a list. + +Use `arr[0]` to return the first element of the passed array. + ```js const head = arr => arr[0]; ``` @@ -1465,20 +1465,20 @@ const head = arr => arr[0]; ```js head([1, 2, 3]); // 1 -``` +```
[⬆ Back to top](#contents) -### indexOfAll - -Returns all indices of `val` in an array. -If `val` never occurs, returns `[]`. - -Use `Array.prototype.reduce()` to loop over elements and store indices for matching elements. -Return the array of indices. - +### indexOfAll + +Returns all indices of `val` in an array. +If `val` never occurs, returns `[]`. + +Use `Array.prototype.reduce()` to loop over elements and store indices for matching elements. +Return the array of indices. + ```js const indexOfAll = (arr, val) => arr.reduce((acc, el, i) => (el === val ? [...acc, i] : acc), []); ``` @@ -1489,18 +1489,18 @@ const indexOfAll = (arr, val) => arr.reduce((acc, el, i) => (el === val ? [...ac ```js indexOfAll([1, 2, 3, 1, 2, 3], 1); // [0,3] indexOfAll([1, 2, 3], 4); // [] -``` +```
[⬆ Back to top](#contents) -### initial - -Returns all the elements of an array except the last one. - -Use `arr.slice(0,-1)` to return all but the last element of the array. - +### initial + +Returns all the elements of an array except the last one. + +Use `arr.slice(0,-1)` to return all but the last element of the array. + ```js const initial = arr => arr.slice(0, -1); ``` @@ -1510,18 +1510,18 @@ const initial = arr => arr.slice(0, -1); ```js initial([1, 2, 3]); // [1,2] -``` +```
[⬆ Back to top](#contents) -### initialize2DArray - -Initializes a 2D array of given width and height and value. - -Use `Array.prototype.map()` to generate h rows where each is a new array of size w initialize with value. If the value is not provided, default to `null`. - +### initialize2DArray + +Initializes a 2D array of given width and height and value. + +Use `Array.prototype.map()` to generate h rows where each is a new array of size w initialize with value. If the value is not provided, default to `null`. + ```js const initialize2DArray = (w, h, val = null) => Array.from({ length: h }).map(() => Array.from({ length: w }).fill(val)); @@ -1532,20 +1532,20 @@ const initialize2DArray = (w, h, val = null) => ```js initialize2DArray(2, 2, 0); // [[0,0], [0,0]] -``` +```
[⬆ Back to top](#contents) -### initializeArrayWithRange - -Initializes an array containing the numbers in the specified range where `start` and `end` are inclusive with their common difference `step`. - -Use `Array.from()` to create an array of the desired length, `(end - start + 1)/step`, and a map function to fill it with the desired values in the given range. -You can omit `start` to use a default value of `0`. -You can omit `step` to use a default value of `1`. - +### initializeArrayWithRange + +Initializes an array containing the numbers in the specified range where `start` and `end` are inclusive with their common difference `step`. + +Use `Array.from()` to create an array of the desired length, `(end - start + 1)/step`, and a map function to fill it with the desired values in the given range. +You can omit `start` to use a default value of `0`. +You can omit `step` to use a default value of `1`. + ```js const initializeArrayWithRange = (end, start = 0, step = 1) => Array.from({ length: Math.ceil((end - start + 1) / step) }, (v, i) => i * step + start); @@ -1558,20 +1558,20 @@ const initializeArrayWithRange = (end, start = 0, step = 1) => initializeArrayWithRange(5); // [0,1,2,3,4,5] initializeArrayWithRange(7, 3); // [3,4,5,6,7] initializeArrayWithRange(9, 0, 2); // [0,2,4,6,8] -``` +```
[⬆ Back to top](#contents) -### initializeArrayWithRangeRight - -Initializes an array containing the numbers in the specified range (in reverse) where `start` and `end` are inclusive with their common difference `step`. - -Use `Array.from(Math.ceil((end+1-start)/step))` to create an array of the desired length(the amounts of elements is equal to `(end-start)/step` or `(end+1-start)/step` for inclusive end), `Array.prototype.map()` to fill with the desired values in a range. -You can omit `start` to use a default value of `0`. -You can omit `step` to use a default value of `1`. - +### initializeArrayWithRangeRight + +Initializes an array containing the numbers in the specified range (in reverse) where `start` and `end` are inclusive with their common difference `step`. + +Use `Array.from(Math.ceil((end+1-start)/step))` to create an array of the desired length(the amounts of elements is equal to `(end-start)/step` or `(end+1-start)/step` for inclusive end), `Array.prototype.map()` to fill with the desired values in a range. +You can omit `start` to use a default value of `0`. +You can omit `step` to use a default value of `1`. + ```js const initializeArrayWithRangeRight = (end, start = 0, step = 1) => Array.from({ length: Math.ceil((end + 1 - start) / step) }).map( @@ -1586,19 +1586,19 @@ const initializeArrayWithRangeRight = (end, start = 0, step = 1) => initializeArrayWithRangeRight(5); // [5,4,3,2,1,0] initializeArrayWithRangeRight(7, 3); // [7,6,5,4,3] initializeArrayWithRangeRight(9, 0, 2); // [8,6,4,2,0] -``` +```
[⬆ Back to top](#contents) -### initializeArrayWithValues - -Initializes and fills an array with the specified values. - -Use `Array(n)` to create an array of the desired length, `fill(v)` to fill it with the desired values. -You can omit `val` to use a default value of `0`. - +### initializeArrayWithValues + +Initializes and fills an array with the specified values. + +Use `Array(n)` to create an array of the desired length, `fill(v)` to fill it with the desired values. +You can omit `val` to use a default value of `0`. + ```js const initializeArrayWithValues = (n, val = 0) => Array(n).fill(val); ``` @@ -1608,19 +1608,19 @@ const initializeArrayWithValues = (n, val = 0) => Array(n).fill(val); ```js initializeArrayWithValues(5, 2); // [2, 2, 2, 2, 2] -``` +```
[⬆ Back to top](#contents) -### initializeNDArray - -Create a n-dimensional array with given value. - -Use recursion. -Use `Array.prototype.map()` to generate rows where each is a new array initialized using `initializeNDArray`. - +### initializeNDArray + +Create a n-dimensional array with given value. + +Use recursion. +Use `Array.prototype.map()` to generate rows where each is a new array initialized using `initializeNDArray`. + ```js const initializeNDArray = (val, ...args) => args.length === 0 @@ -1634,18 +1634,18 @@ const initializeNDArray = (val, ...args) => ```js initializeNDArray(1, 3); // [1,1,1] initializeNDArray(5, 2, 2, 2); // [[[5,5],[5,5]],[[5,5],[5,5]]] -``` +```
[⬆ Back to top](#contents) -### intersection - -Returns a list of elements that exist in both arrays. - -Create a `Set` from `b`, then use `Array.prototype.filter()` on `a` to only keep values contained in `b`. - +### intersection + +Returns a list of elements that exist in both arrays. + +Create a `Set` from `b`, then use `Array.prototype.filter()` on `a` to only keep values contained in `b`. + ```js const intersection = (a, b) => { const s = new Set(b); @@ -1658,18 +1658,18 @@ const intersection = (a, b) => { ```js intersection([1, 2, 3], [4, 3, 2]); // [2, 3] -``` +```
[⬆ Back to top](#contents) -### intersectionBy - -Returns a list of elements that exist in both arrays, after applying the provided function to each array element of both. - -Create a `Set` by applying `fn` to all elements in `b`, then use `Array.prototype.filter()` on `a` to only keep elements, which produce values contained in `b` when `fn` is applied to them. - +### intersectionBy + +Returns a list of elements that exist in both arrays, after applying the provided function to each array element of both. + +Create a `Set` by applying `fn` to all elements in `b`, then use `Array.prototype.filter()` on `a` to only keep elements, which produce values contained in `b` when `fn` is applied to them. + ```js const intersectionBy = (a, b, fn) => { const s = new Set(b.map(fn)); @@ -1682,18 +1682,18 @@ const intersectionBy = (a, b, fn) => { ```js intersectionBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [2.1] -``` +```
[⬆ Back to top](#contents) -### intersectionWith - -Returns a list of elements that exist in both arrays, using a provided comparator function. - -Use `Array.prototype.filter()` and `Array.prototype.findIndex()` in combination with the provided comparator to determine intersecting values. - +### intersectionWith + +Returns a list of elements that exist in both arrays, using a provided comparator function. + +Use `Array.prototype.filter()` and `Array.prototype.findIndex()` in combination with the provided comparator to determine intersecting values. + ```js const intersectionWith = (a, b, comp) => a.filter(x => b.findIndex(y => comp(x, y)) !== -1); ``` @@ -1703,20 +1703,20 @@ const intersectionWith = (a, b, comp) => a.filter(x => b.findIndex(y => comp(x, ```js intersectionWith([1, 1.2, 1.5, 3, 0], [1.9, 3, 0, 3.9], (a, b) => Math.round(a) === Math.round(b)); // [1.5, 3, 0] -``` +```
[⬆ Back to top](#contents) -### isSorted - -Returns `1` if the array is sorted in ascending order, `-1` if it is sorted in descending order or `0` if it is not sorted. - -Calculate the ordering `direction` for the first two elements. -Use `Object.entries()` to loop over array objects and compare them in pairs. -Return `0` if the `direction` changes or the `direction` if the last element is reached. - +### isSorted + +Returns `1` if the array is sorted in ascending order, `-1` if it is sorted in descending order or `0` if it is not sorted. + +Calculate the ordering `direction` for the first two elements. +Use `Object.entries()` to loop over array objects and compare them in pairs. +Return `0` if the `direction` changes or the `direction` if the last element is reached. + ```js const isSorted = arr => { let direction = -(arr[0] - arr[1]); @@ -1735,21 +1735,21 @@ const isSorted = arr => { isSorted([0, 1, 2, 2]); // 1 isSorted([4, 3, 2]); // -1 isSorted([4, 3, 5]); // 0 -``` +```
[⬆ Back to top](#contents) -### join - -Joins all elements of an array into a string and returns this string. -Uses a separator and an end separator. - -Use `Array.prototype.reduce()` to combine elements into a string. -Omit the second argument, `separator`, to use a default separator of `','`. -Omit the third argument, `end`, to use the same value as `separator` by default. - +### join + +Joins all elements of an array into a string and returns this string. +Uses a separator and an end separator. + +Use `Array.prototype.reduce()` to combine elements into a string. +Omit the second argument, `separator`, to use a default separator of `','`. +Omit the third argument, `end`, to use the same value as `separator` by default. + ```js const join = (arr, separator = ',', end = separator) => arr.reduce( @@ -1770,7 +1770,7 @@ const join = (arr, separator = ',', end = separator) => join(['pen', 'pineapple', 'apple', 'pen'], ',', '&'); // "pen,pineapple,apple&pen" join(['pen', 'pineapple', 'apple', 'pen'], ','); // "pen,pineapple,apple,pen" join(['pen', 'pineapple', 'apple', 'pen']); // "pen,pineapple,apple,pen" -``` +``` @@ -1810,12 +1810,12 @@ JSONtoCSV([{ a: 1, b: 2 }, { a: 3, b: 4, c: 5 }, { a: 6 }, { b: 7 }], ['a', 'b']
[⬆ Back to top](#contents) -### last - -Returns the last element in an array. - -Use `arr.length - 1` to compute the index of the last element of the given array and returning it. - +### last + +Returns the last element in an array. + +Use `arr.length - 1` to compute the index of the last element of the given array and returning it. + ```js const last = arr => arr[arr.length - 1]; ``` @@ -1825,34 +1825,34 @@ const last = arr => arr[arr.length - 1]; ```js last([1, 2, 3]); // 3 -``` +```
[⬆ Back to top](#contents) -### longestItem - -Takes any number of iterable objects or objects with a `length` property and returns the longest one. -If multiple objects have the same length, the first one will be returned. -Returns `undefined` if no arguments are provided. - -Use `Array.prototype.reduce()`, comparing the `length` of objects to find the longest one. - +### longestItem + +Takes any number of iterable objects or objects with a `length` property and returns the longest one. +If multiple objects have the same length, the first one will be returned. +Returns `undefined` if no arguments are provided. + +Use `Array.prototype.reduce()`, comparing the `length` of objects to find the longest one. + ```js -const longestItem = (...vals) => vals.reduce((a, x) => (x.length > a.length ? x : a)); +const longestItem = (...vals) => vals.reduce((a, x) => (x.length > a.length ? x : a)); ```
Examples ```js -longestItem('this', 'is', 'a', 'testcase'); // 'testcase' -longestItem(...['a', 'ab', 'abc']); // 'abc' -longestItem(...['a', 'ab', 'abc'], 'abcd'); // 'abcd' -longestItem([1, 2, 3], [1, 2], [1, 2, 3, 4, 5]); // [1, 2, 3, 4, 5] -longestItem([1, 2, 3], 'foobar'); // 'foobar' -``` +longestItem('this', 'is', 'a', 'testcase'); // 'testcase' +longestItem(...['a', 'ab', 'abc']); // 'abc' +longestItem(...['a', 'ab', 'abc'], 'abcd'); // 'abcd' +longestItem([1, 2, 3], [1, 2], [1, 2, 3, 4, 5]); // [1, 2, 3, 4, 5] +longestItem([1, 2, 3], 'foobar'); // 'foobar' +```
@@ -1883,15 +1883,15 @@ squareIt([1, 2, 3]); // { 1: 1, 2: 4, 3: 9 }
[⬆ Back to top](#contents) -### maxN - -Returns the `n` maximum elements from the provided array. -If `n` is greater than or equal to the provided array's length, then return the original array (sorted in descending order). - -Use `Array.prototype.sort()` combined with the spread operator (`...`) to create a shallow clone of the array and sort it in descending order. -Use `Array.prototype.slice()` to get the specified number of elements. -Omit the second argument, `n`, to get a one-element array. - +### maxN + +Returns the `n` maximum elements from the provided array. +If `n` is greater than or equal to the provided array's length, then return the original array (sorted in descending order). + +Use `Array.prototype.sort()` combined with the spread operator (`...`) to create a shallow clone of the array and sort it in descending order. +Use `Array.prototype.slice()` to get the specified number of elements. +Omit the second argument, `n`, to get a one-element array. + ```js const maxN = (arr, n = 1) => [...arr].sort((a, b) => b - a).slice(0, n); ``` @@ -1902,21 +1902,21 @@ const maxN = (arr, n = 1) => [...arr].sort((a, b) => b - a).slice(0, n); ```js maxN([1, 2, 3]); // [3] maxN([1, 2, 3], 2); // [3,2] -``` +```
[⬆ Back to top](#contents) -### minN - -Returns the `n` minimum elements from the provided array. -If `n` is greater than or equal to the provided array's length, then return the original array (sorted in ascending order). - -Use `Array.prototype.sort()` combined with the spread operator (`...`) to create a shallow clone of the array and sort it in ascending order. -Use `Array.prototype.slice()` to get the specified number of elements. -Omit the second argument, `n`, to get a one-element array. - +### minN + +Returns the `n` minimum elements from the provided array. +If `n` is greater than or equal to the provided array's length, then return the original array (sorted in ascending order). + +Use `Array.prototype.sort()` combined with the spread operator (`...`) to create a shallow clone of the array and sort it in ascending order. +Use `Array.prototype.slice()` to get the specified number of elements. +Omit the second argument, `n`, to get a one-element array. + ```js const minN = (arr, n = 1) => [...arr].sort((a, b) => a - b).slice(0, n); ``` @@ -1927,19 +1927,19 @@ const minN = (arr, n = 1) => [...arr].sort((a, b) => a - b).slice(0, n); ```js minN([1, 2, 3]); // [1] minN([1, 2, 3], 2); // [1,2] -``` +```
[⬆ Back to top](#contents) -### none - -Returns `true` if the provided predicate function returns `false` for all elements in a collection, `false` otherwise. - -Use `Array.prototype.some()` to test if any elements in the collection return `true` based on `fn`. -Omit the second argument, `fn`, to use `Boolean` as a default. - +### none + +Returns `true` if the provided predicate function returns `false` for all elements in a collection, `false` otherwise. + +Use `Array.prototype.some()` to test if any elements in the collection return `true` based on `fn`. +Omit the second argument, `fn`, to use `Boolean` as a default. + ```js const none = (arr, fn = Boolean) => !arr.some(fn); ``` @@ -1950,20 +1950,20 @@ const none = (arr, fn = Boolean) => !arr.some(fn); ```js none([0, 1, 3, 0], x => x == 2); // true none([0, 0, 0]); // true -``` +```
[⬆ Back to top](#contents) -### nthElement - -Returns the nth element of an array. - -Use `Array.prototype.slice()` to get an array containing the nth element at the first place. -If the index is out of bounds, return `undefined`. -Omit the second argument, `n`, to get the first element of the array. - +### nthElement + +Returns the nth element of an array. + +Use `Array.prototype.slice()` to get an array containing the nth element at the first place. +If the index is out of bounds, return `undefined`. +Omit the second argument, `n`, to get the first element of the array. + ```js const nthElement = (arr, n = 0) => (n === -1 ? arr.slice(n) : arr.slice(n, n + 1))[0]; ``` @@ -1974,20 +1974,20 @@ const nthElement = (arr, n = 0) => (n === -1 ? arr.slice(n) : arr.slice(n, n + 1 ```js nthElement(['a', 'b', 'c'], 1); // 'b' nthElement(['a', 'b', 'b'], -3); // 'a' -``` +```
[⬆ Back to top](#contents) -### offset - -Moves the specified amount of elements to the end of the array. - -Use `Array.prototype.slice()` twice to get the elements after the specified index and the elements before that. -Use the spread operator(`...`) to combine the two into one array. -If `offset` is negative, the elements will be moved from end to start. - +### offset + +Moves the specified amount of elements to the end of the array. + +Use `Array.prototype.slice()` twice to get the elements after the specified index and the elements before that. +Use the spread operator(`...`) to combine the two into one array. +If `offset` is negative, the elements will be moved from end to start. + ```js const offset = (arr, offset) => [...arr.slice(offset), ...arr.slice(0, offset)]; ``` @@ -1998,19 +1998,19 @@ const offset = (arr, offset) => [...arr.slice(offset), ...arr.slice(0, offset)]; ```js offset([1, 2, 3, 4, 5], 2); // [3, 4, 5, 1, 2] offset([1, 2, 3, 4, 5], -2); // [4, 5, 1, 2, 3] -``` +```
[⬆ Back to top](#contents) -### partition - -Groups the elements into two arrays, depending on the provided function's truthiness for each element. - -Use `Array.prototype.reduce()` to create an array of two arrays. -Use `Array.prototype.push()` to add elements for which `fn` returns `true` to the first array and elements for which `fn` returns `false` to the second one. - +### partition + +Groups the elements into two arrays, depending on the provided function's truthiness for each element. + +Use `Array.prototype.reduce()` to create an array of two arrays. +Use `Array.prototype.push()` to add elements for which `fn` returns `true` to the first array and elements for which `fn` returns `false` to the second one. + ```js const partition = (arr, fn) => arr.reduce( @@ -2028,7 +2028,7 @@ const partition = (arr, fn) => ```js const users = [{ user: 'barney', age: 36, active: false }, { user: 'fred', age: 40, active: true }]; partition(users, o => o.active); // [[{ 'user': 'fred', 'age': 40, 'active': true }],[{ 'user': 'barney', 'age': 36, 'active': false }]] -``` +``` @@ -2069,15 +2069,15 @@ permutations([1, 33, 5]); // [ [ 1, 33, 5 ], [ 1, 5, 33 ], [ 33, 1, 5 ], [ 33, 5
[⬆ Back to top](#contents) -### pull - -Mutates the original array to filter out the values specified. - -Use `Array.prototype.filter()` and `Array.prototype.includes()` to pull out the values that are not needed. -Use `Array.prototype.length = 0` to mutate the passed in an array by resetting it's length to zero and `Array.prototype.push()` to re-populate it with only the pulled values. - -_(For a snippet that does not mutate the original array see [`without`](#without))_ - +### pull + +Mutates the original array to filter out the values specified. + +Use `Array.prototype.filter()` and `Array.prototype.includes()` to pull out the values that are not needed. +Use `Array.prototype.length = 0` to mutate the passed in an array by resetting it's length to zero and `Array.prototype.push()` to re-populate it with only the pulled values. + +_(For a snippet that does not mutate the original array see [`without`](#without))_ + ```js const pull = (arr, ...args) => { let argState = Array.isArray(args[0]) ? args[0] : args; @@ -2093,7 +2093,7 @@ const pull = (arr, ...args) => { ```js let myArray = ['a', 'b', 'c', 'a', 'b', 'c']; pull(myArray, 'a', 'c'); // myArray = [ 'b', 'b' ] -``` +``` @@ -2195,13 +2195,13 @@ pullBy(myArray, [{ x: 1 }, { x: 3 }], o => o.x); // myArray = [{ x: 2 }]
[⬆ Back to top](#contents) -### reducedFilter - -Filter an array of objects based on a condition while also filtering out unspecified keys. - -Use `Array.prototype.filter()` to filter the array based on the predicate `fn` so that it returns the objects for which the condition returned a truthy value. -On the filtered array, use `Array.prototype.map()` to return the new object using `Array.prototype.reduce()` to filter out the keys which were not supplied as the `keys` argument. - +### reducedFilter + +Filter an array of objects based on a condition while also filtering out unspecified keys. + +Use `Array.prototype.filter()` to filter the array based on the predicate `fn` so that it returns the objects for which the condition returned a truthy value. +On the filtered array, use `Array.prototype.map()` to return the new object using `Array.prototype.reduce()` to filter out the keys which were not supplied as the `keys` argument. + ```js const reducedFilter = (data, keys, fn) => data.filter(fn).map(el => @@ -2230,18 +2230,18 @@ const data = [ ]; reducedFilter(data, ['id', 'name'], item => item.age > 24); // [{ id: 2, name: 'mike'}] -``` +```
[⬆ Back to top](#contents) -### reduceSuccessive - -Applies a function against an accumulator and each element in the array (from left to right), returning an array of successively reduced values. - -Use `Array.prototype.reduce()` to apply the given function to the given array, storing each new result. - +### reduceSuccessive + +Applies a function against an accumulator and each element in the array (from left to right), returning an array of successively reduced values. + +Use `Array.prototype.reduce()` to apply the given function to the given array, storing each new result. + ```js const reduceSuccessive = (arr, fn, acc) => arr.reduce((res, val, i, arr) => (res.push(fn(res.slice(-1)[0], val, i, arr)), res), [acc]); @@ -2252,19 +2252,19 @@ const reduceSuccessive = (arr, fn, acc) => ```js reduceSuccessive([1, 2, 3, 4, 5, 6], (acc, val) => acc + val, 0); // [0, 1, 3, 6, 10, 15, 21] -``` +```
[⬆ Back to top](#contents) -### reduceWhich - -Returns the minimum/maximum value of an array, after applying the provided function to set comparing rule. - -Use `Array.prototype.reduce()` in combination with the `comparator` function to get the appropriate element in the array. -You can omit the second parameter, `comparator`, to use the default one that returns the minimum element in the array. - +### reduceWhich + +Returns the minimum/maximum value of an array, after applying the provided function to set comparing rule. + +Use `Array.prototype.reduce()` in combination with the `comparator` function to get the appropriate element in the array. +You can omit the second parameter, `comparator`, to use the default one that returns the minimum element in the array. + ```js const reduceWhich = (arr, comparator = (a, b) => a - b) => arr.reduce((a, b) => (comparator(a, b) >= 0 ? b : a)); @@ -2280,16 +2280,16 @@ reduceWhich( [{ name: 'Tom', age: 12 }, { name: 'Jack', age: 18 }, { name: 'Lucy', age: 9 }], (a, b) => a.age - b.age ); // {name: "Lucy", age: 9} -``` +```
[⬆ Back to top](#contents) -### reject - -Takes a predicate and array, like `Array.prototype.filter()`, but only keeps `x` if `pred(x) === false`. - +### reject + +Takes a predicate and array, like `Array.prototype.filter()`, but only keeps `x` if `pred(x) === false`. + ```js const reject = (pred, array) => array.filter((...args) => !pred(...args)); ``` @@ -2300,71 +2300,70 @@ const reject = (pred, array) => array.filter((...args) => !pred(...args)); ```js reject(x => x % 2 === 0, [1, 2, 3, 4, 5]); // [1, 3, 5] reject(word => word.length > 4, ['Apple', 'Pear', 'Kiwi', 'Banana']); // ['Pear', 'Kiwi'] -``` +```
[⬆ Back to top](#contents) -### remove - -Removes elements from an array for which the given function returns `false`. - -Use `Array.prototype.filter()` to find array elements that return truthy values and `Array.prototype.reduce()` to remove elements using `Array.prototype.splice()`. -The `func` is invoked with three arguments (`value, index, array`). - +### remove + +Removes elements from an array for which the given function returns `false`. + +Use `Array.prototype.filter()` to find array elements that return truthy values and `Array.prototype.reduce()` to remove elements using `Array.prototype.splice()`. +The `func` is invoked with three arguments (`value, index, array`). + ```js - -const remove = (arr, func) => - Array.isArray(arr) - ? arr.filter(func).reduce((acc, val) => { - arr.splice(arr.indexOf(val), 1); - return acc.concat(val); - }, []) - : []; +const remove = (arr, func) => + Array.isArray(arr) + ? arr.filter(func).reduce((acc, val) => { + arr.splice(arr.indexOf(val), 1); + return acc.concat(val); + }, []) + : []; ```
Examples ```js -remove([1, 2, 3, 4], n => n % 2 === 0); // [2, 4] -``` +remove([1, 2, 3, 4], n => n % 2 === 0); // [2, 4] +```

[⬆ Back to top](#contents) -### sample - -Returns a random element from an array. - -Use `Math.random()` to generate a random number, multiply it by `length` and round it off to the nearest whole number using `Math.floor()`. -This method also works with strings. - +### sample + +Returns a random element from an array. + +Use `Math.random()` to generate a random number, multiply it by `length` and round it off to the nearest whole number using `Math.floor()`. +This method also works with strings. + ```js -const sample = arr => arr[Math.floor(Math.random() * arr.length)]; +const sample = arr => arr[Math.floor(Math.random() * arr.length)]; ```
Examples ```js -sample([3, 7, 9, 11]); // 9 -``` +sample([3, 7, 9, 11]); // 9 +```

[⬆ Back to top](#contents) -### sampleSize - -Gets `n` random elements at unique keys from `array` up to the size of `array`. - -Shuffle the array using the [Fisher-Yates algorithm](https://github.com/30-seconds/30-seconds-of-code#shuffle). -Use `Array.prototype.slice()` to get the first `n` elements. -Omit the second argument, `n` to get only one element at random from the array. - +### sampleSize + +Gets `n` random elements at unique keys from `array` up to the size of `array`. + +Shuffle the array using the [Fisher-Yates algorithm](https://github.com/30-seconds/30-seconds-of-code#shuffle). +Use `Array.prototype.slice()` to get the first `n` elements. +Omit the second argument, `n` to get only one element at random from the array. + ```js const sampleSize = ([...arr], n = 1) => { let m = arr.length; @@ -2382,49 +2381,49 @@ const sampleSize = ([...arr], n = 1) => { ```js sampleSize([1, 2, 3], 2); // [3,1] sampleSize([1, 2, 3], 4); // [2,3,1] -``` +```
[⬆ Back to top](#contents) -### shank - -Has the same functionality as [`Array.prototype.splice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice), but returning a new array instead of mutating the original array. - -Use `Array.prototype.slice()` and `Array.prototype.concat()` to get a new array with the new contents after removing existing elements and/or adding new elements. -Omit the second argument, `index`, to start at `0`. -Omit the third argument, `delCount`, to remove `0` elements. -Omit the fourth argument, `elements`, in order to not add any new elements. - +### shank + +Has the same functionality as [`Array.prototype.splice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice), but returning a new array instead of mutating the original array. + +Use `Array.prototype.slice()` and `Array.prototype.concat()` to get a new array with the new contents after removing existing elements and/or adding new elements. +Omit the second argument, `index`, to start at `0`. +Omit the third argument, `delCount`, to remove `0` elements. +Omit the fourth argument, `elements`, in order to not add any new elements. + ```js -const shank = (arr, index = 0, delCount = 0, ...elements) => - arr - .slice(0, index) - .concat(elements) - .concat(arr.slice(index + delCount)); +const shank = (arr, index = 0, delCount = 0, ...elements) => + arr + .slice(0, index) + .concat(elements) + .concat(arr.slice(index + delCount)); ```
Examples ```js -const names = ['alpha', 'bravo', 'charlie']; -const namesAndDelta = shank(names, 1, 0, 'delta'); // [ 'alpha', 'delta', 'bravo', 'charlie' ] -const namesNoBravo = shank(names, 1, 1); // [ 'alpha', 'charlie' ] -console.log(names); // ['alpha', 'bravo', 'charlie'] -``` +const names = ['alpha', 'bravo', 'charlie']; +const namesAndDelta = shank(names, 1, 0, 'delta'); // [ 'alpha', 'delta', 'bravo', 'charlie' ] +const namesNoBravo = shank(names, 1, 1); // [ 'alpha', 'charlie' ] +console.log(names); // ['alpha', 'bravo', 'charlie'] +```

[⬆ Back to top](#contents) -### shuffle - -Randomizes the order of the values of an array, returning a new array. - -Uses the [Fisher-Yates algorithm](https://github.com/30-seconds/30-seconds-of-code#shuffle) to reorder the elements of the array. - +### shuffle + +Randomizes the order of the values of an array, returning a new array. + +Uses the [Fisher-Yates algorithm](https://github.com/30-seconds/30-seconds-of-code#shuffle) to reorder the elements of the array. + ```js const shuffle = ([...arr]) => { let m = arr.length; @@ -2442,18 +2441,18 @@ const shuffle = ([...arr]) => { ```js const foo = [1, 2, 3]; shuffle(foo); // [2, 3, 1], foo = [1, 2, 3] -``` +```
[⬆ Back to top](#contents) -### similarity - -Returns an array of elements that appear in both arrays. - -Use `Array.prototype.filter()` to remove values that are not part of `values`, determined using `Array.prototype.includes()`. - +### similarity + +Returns an array of elements that appear in both arrays. + +Use `Array.prototype.filter()` to remove values that are not part of `values`, determined using `Array.prototype.includes()`. + ```js const similarity = (arr, values) => arr.filter(v => values.includes(v)); ``` @@ -2463,19 +2462,19 @@ const similarity = (arr, values) => arr.filter(v => values.includes(v)); ```js similarity([1, 2, 3], [1, 2, 4]); // [1, 2] -``` +```
[⬆ Back to top](#contents) -### sortedIndex - -Returns the lowest index at which value should be inserted into array in order to maintain its sort order. - -Check if the array is sorted in descending order (loosely). -Use `Array.prototype.findIndex()` to find the appropriate index where the element should be inserted. - +### sortedIndex + +Returns the lowest index at which value should be inserted into array in order to maintain its sort order. + +Check if the array is sorted in descending order (loosely). +Use `Array.prototype.findIndex()` to find the appropriate index where the element should be inserted. + ```js const sortedIndex = (arr, n) => { const isDescending = arr[0] > arr[arr.length - 1]; @@ -2490,19 +2489,19 @@ const sortedIndex = (arr, n) => { ```js sortedIndex([5, 3, 2, 1], 4); // 1 sortedIndex([30, 50], 40); // 1 -``` +```
[⬆ Back to top](#contents) -### sortedIndexBy - -Returns the lowest index at which value should be inserted into array in order to maintain its sort order, based on a provided iterator function. - -Check if the array is sorted in descending order (loosely). -Use `Array.prototype.findIndex()` to find the appropriate index where the element should be inserted, based on the iterator function `fn`. - +### sortedIndexBy + +Returns the lowest index at which value should be inserted into array in order to maintain its sort order, based on a provided iterator function. + +Check if the array is sorted in descending order (loosely). +Use `Array.prototype.findIndex()` to find the appropriate index where the element should be inserted, based on the iterator function `fn`. + ```js const sortedIndexBy = (arr, n, fn) => { const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]); @@ -2517,19 +2516,19 @@ const sortedIndexBy = (arr, n, fn) => { ```js sortedIndexBy([{ x: 4 }, { x: 5 }], { x: 4 }, o => o.x); // 0 -``` +```
[⬆ Back to top](#contents) -### sortedLastIndex - -Returns the highest index at which value should be inserted into array in order to maintain its sort order. - -Check if the array is sorted in descending order (loosely). -Use `Array.prototype.reverse()` and `Array.prototype.findIndex()` to find the appropriate last index where the element should be inserted. - +### sortedLastIndex + +Returns the highest index at which value should be inserted into array in order to maintain its sort order. + +Check if the array is sorted in descending order (loosely). +Use `Array.prototype.reverse()` and `Array.prototype.findIndex()` to find the appropriate last index where the element should be inserted. + ```js const sortedLastIndex = (arr, n) => { const isDescending = arr[0] > arr[arr.length - 1]; @@ -2543,20 +2542,20 @@ const sortedLastIndex = (arr, n) => { ```js sortedLastIndex([10, 20, 30, 30, 40], 30); // 4 -``` +```
[⬆ Back to top](#contents) -### sortedLastIndexBy - -Returns the highest index at which value should be inserted into array in order to maintain its sort order, based on a provided iterator function. - -Check if the array is sorted in descending order (loosely). -Use `Array.prototype.map()` to apply the iterator function to all elements of the array. -Use `Array.prototype.reverse()` and `Array.prototype.findIndex()` to find the appropriate last index where the element should be inserted, based on the provided iterator function. - +### sortedLastIndexBy + +Returns the highest index at which value should be inserted into array in order to maintain its sort order, based on a provided iterator function. + +Check if the array is sorted in descending order (loosely). +Use `Array.prototype.map()` to apply the iterator function to all elements of the array. +Use `Array.prototype.reverse()` and `Array.prototype.findIndex()` to find the appropriate last index where the element should be inserted, based on the provided iterator function. + ```js const sortedLastIndexBy = (arr, n, fn) => { const isDescending = fn(arr[0]) > fn(arr[arr.length - 1]); @@ -2574,7 +2573,7 @@ const sortedLastIndexBy = (arr, n, fn) => { ```js sortedLastIndexBy([{ x: 4 }, { x: 5 }], { x: 4 }, o => o.x); // 1 -``` +``` @@ -2609,12 +2608,12 @@ const stable = stableSort(arr, () => 0); // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
[⬆ Back to top](#contents) -### symmetricDifference - -Returns the symmetric difference between two arrays, without filtering out duplicate values. - -Create a `Set` from each array, then use `Array.prototype.filter()` on each of them to only keep values not contained in the other. - +### symmetricDifference + +Returns the symmetric difference between two arrays, without filtering out duplicate values. + +Create a `Set` from each array, then use `Array.prototype.filter()` on each of them to only keep values not contained in the other. + ```js const symmetricDifference = (a, b) => { const sA = new Set(a), @@ -2629,18 +2628,18 @@ const symmetricDifference = (a, b) => { ```js symmetricDifference([1, 2, 3], [1, 2, 4]); // [3, 4] symmetricDifference([1, 2, 2], [1, 3, 1]); // [2, 2, 3] -``` +```
[⬆ Back to top](#contents) -### symmetricDifferenceBy - -Returns the symmetric difference between two arrays, after applying the provided function to each array element of both. - -Create a `Set` by applying `fn` to each array's elements, then use `Array.prototype.filter()` on each of them to only keep values not contained in the other. - +### symmetricDifferenceBy + +Returns the symmetric difference between two arrays, after applying the provided function to each array element of both. + +Create a `Set` by applying `fn` to each array's elements, then use `Array.prototype.filter()` on each of them to only keep values not contained in the other. + ```js const symmetricDifferenceBy = (a, b, fn) => { const sA = new Set(a.map(v => fn(v))), @@ -2654,18 +2653,18 @@ const symmetricDifferenceBy = (a, b, fn) => { ```js symmetricDifferenceBy([2.1, 1.2], [2.3, 3.4], Math.floor); // [ 1.2, 3.4 ] -``` +```
[⬆ Back to top](#contents) -### symmetricDifferenceWith - -Returns the symmetric difference between two arrays, using a provided function as a comparator. - -Use `Array.prototype.filter()` and `Array.prototype.findIndex()` to find the appropriate values. - +### symmetricDifferenceWith + +Returns the symmetric difference between two arrays, using a provided function as a comparator. + +Use `Array.prototype.filter()` and `Array.prototype.findIndex()` to find the appropriate values. + ```js const symmetricDifferenceWith = (arr, val, comp) => [ ...arr.filter(a => val.findIndex(b => comp(a, b)) === -1), @@ -2682,18 +2681,18 @@ symmetricDifferenceWith( [1.9, 3, 0, 3.9], (a, b) => Math.round(a) === Math.round(b) ); // [1, 1.2, 3.9] -``` +```
[⬆ Back to top](#contents) -### tail - -Returns all elements in an array except for the first one. - -Return `Array.prototype.slice(1)` if the array's `length` is more than `1`, otherwise, return the whole array. - +### tail + +Returns all elements in an array except for the first one. + +Return `Array.prototype.slice(1)` if the array's `length` is more than `1`, otherwise, return the whole array. + ```js const tail = arr => (arr.length > 1 ? arr.slice(1) : arr); ``` @@ -2704,18 +2703,18 @@ const tail = arr => (arr.length > 1 ? arr.slice(1) : arr); ```js tail([1, 2, 3]); // [2,3] tail([1]); // [1] -``` +```
[⬆ Back to top](#contents) -### take - -Returns an array with n elements removed from the beginning. - -Use `Array.prototype.slice()` to create a slice of the array with `n` elements taken from the beginning. - +### take + +Returns an array with n elements removed from the beginning. + +Use `Array.prototype.slice()` to create a slice of the array with `n` elements taken from the beginning. + ```js const take = (arr, n = 1) => arr.slice(0, n); ``` @@ -2726,18 +2725,18 @@ const take = (arr, n = 1) => arr.slice(0, n); ```js take([1, 2, 3], 5); // [1, 2, 3] take([1, 2, 3], 0); // [] -``` +```
[⬆ Back to top](#contents) -### takeRight - -Returns an array with n elements removed from the end. - -Use `Array.prototype.slice()` to create a slice of the array with `n` elements taken from the end. - +### takeRight + +Returns an array with n elements removed from the end. + +Use `Array.prototype.slice()` to create a slice of the array with `n` elements taken from the end. + ```js const takeRight = (arr, n = 1) => arr.slice(arr.length - n, arr.length); ``` @@ -2748,41 +2747,41 @@ const takeRight = (arr, n = 1) => arr.slice(arr.length - n, arr.length); ```js takeRight([1, 2, 3], 2); // [ 2, 3 ] takeRight([1, 2, 3]); // [3] -``` +```
[⬆ Back to top](#contents) -### takeRightWhile - -Removes elements from the end of an array until the passed function returns `true`. Returns the removed elements. - -Loop through the array, using a `Array.prototype.reduceRight()` and accumulating elements while the function returns falsy value. - +### takeRightWhile + +Removes elements from the end of an array until the passed function returns `true`. Returns the removed elements. + +Loop through the array, using a `Array.prototype.reduceRight()` and accumulating elements while the function returns falsy value. + ```js -const takeRightWhile = (arr, func) => - arr.reduceRight((acc, el) => (func(el) ? acc : [el, ...acc]), []); +const takeRightWhile = (arr, func) => + arr.reduceRight((acc, el) => (func(el) ? acc : [el, ...acc]), []); ```
Examples ```js -takeRightWhile([1, 2, 3, 4], n => n < 3); // [3, 4] -``` +takeRightWhile([1, 2, 3, 4], n => n < 3); // [3, 4] +```

[⬆ Back to top](#contents) -### takeWhile - -Removes elements in an array until the passed function returns `true`. Returns the removed elements. - -Loop through the array, using a `for...of` loop over `Array.prototype.entries()` until the returned value from the function is `true`. -Return the removed elements, using `Array.prototype.slice()`. - +### takeWhile + +Removes elements in an array until the passed function returns `true`. Returns the removed elements. + +Loop through the array, using a `for...of` loop over `Array.prototype.entries()` until the returned value from the function is `true`. +Return the removed elements, using `Array.prototype.slice()`. + ```js const takeWhile = (arr, func) => { for (const [i, val] of arr.entries()) if (func(val)) return arr.slice(0, i); @@ -2795,56 +2794,56 @@ const takeWhile = (arr, func) => { ```js takeWhile([1, 2, 3, 4], n => n >= 3); // [1, 2] -``` +```
[⬆ Back to top](#contents) -### toHash - -Reduces a given Array-like into a value hash (keyed data store). - -Given an Iterable or Array-like structure, call `Array.prototype.reduce.call()` on the provided object to step over it and return an Object, keyed by the reference value. - +### toHash + +Reduces a given Array-like into a value hash (keyed data store). + +Given an Iterable or Array-like structure, call `Array.prototype.reduce.call()` on the provided object to step over it and return an Object, keyed by the reference value. + ```js -const toHash = (object, key) => - Array.prototype.reduce.call( - object, - (acc, data, index) => ((acc[!key ? index : data[key]] = data), acc), - {} - ); +const toHash = (object, key) => + Array.prototype.reduce.call( + object, + (acc, data, index) => ((acc[!key ? index : data[key]] = data), acc), + {} + ); ```
Examples ```js -toHash([4, 3, 2, 1]); // { 0: 4, 1: 3, 2: 2, 3: 1 } -toHash([{ a: 'label' }], 'a'); // { label: { a: 'label' } } -// A more in depth example: -let users = [{ id: 1, first: 'Jon' }, { id: 2, first: 'Joe' }, { id: 3, first: 'Moe' }]; -let managers = [{ manager: 1, employees: [2, 3] }]; -// We use function here because we want a bindable reference, but a closure referencing the hash would work, too. -managers.forEach( - manager => - (manager.employees = manager.employees.map(function(id) { - return this[id]; - }, toHash(users, 'id'))) -); -managers; // [ { manager:1, employees: [ { id: 2, first: "Joe" }, { id: 3, first: "Moe" } ] } ] -``` +toHash([4, 3, 2, 1]); // { 0: 4, 1: 3, 2: 2, 3: 1 } +toHash([{ a: 'label' }], 'a'); // { label: { a: 'label' } } +// A more in depth example: +let users = [{ id: 1, first: 'Jon' }, { id: 2, first: 'Joe' }, { id: 3, first: 'Moe' }]; +let managers = [{ manager: 1, employees: [2, 3] }]; +// We use function here because we want a bindable reference, but a closure referencing the hash would work, too. +managers.forEach( + manager => + (manager.employees = manager.employees.map(function(id) { + return this[id]; + }, toHash(users, 'id'))) +); +managers; // [ { manager:1, employees: [ { id: 2, first: "Joe" }, { id: 3, first: "Moe" } ] } ] +```

[⬆ Back to top](#contents) -### union - -Returns every element that exists in any of the two arrays once. - -Create a `Set` with all values of `a` and `b` and convert to an array. - +### union + +Returns every element that exists in any of the two arrays once. + +Create a `Set` with all values of `a` and `b` and convert to an array. + ```js const union = (a, b) => Array.from(new Set([...a, ...b])); ``` @@ -2854,44 +2853,44 @@ const union = (a, b) => Array.from(new Set([...a, ...b])); ```js union([1, 2, 3], [4, 3, 2]); // [1,2,3,4] -``` +```
[⬆ Back to top](#contents) -### unionBy - -Returns every element that exists in any of the two arrays once, after applying the provided function to each array element of both. - -Create a `Set` by applying all `fn` to all values of `a`. -Create a `Set` from `a` and all elements in `b` whose value, after applying `fn` does not match a value in the previously created set. -Return the last set converted to an array. - +### unionBy + +Returns every element that exists in any of the two arrays once, after applying the provided function to each array element of both. + +Create a `Set` by applying all `fn` to all values of `a`. +Create a `Set` from `a` and all elements in `b` whose value, after applying `fn` does not match a value in the previously created set. +Return the last set converted to an array. + ```js -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 unionBy = (a, b, fn) => { + const s = new Set(a.map(fn)); + return Array.from(new Set([...a, ...b.filter(x => !s.has(fn(x)))])); +}; ```
Examples ```js -unionBy([2.1], [1.2, 2.3], Math.floor); // [2.1, 1.2] -``` +unionBy([2.1], [1.2, 2.3], Math.floor); // [2.1, 1.2] +```

[⬆ Back to top](#contents) -### unionWith - -Returns every element that exists in any of the two arrays once, using a provided comparator function. - -Create a `Set` with all values of `a` and values in `b` for which the comparator finds no matches in `a`, using `Array.prototype.findIndex()`. - +### unionWith + +Returns every element that exists in any of the two arrays once, using a provided comparator function. + +Create a `Set` with all values of `a` and values in `b` for which the comparator finds no matches in `a`, using `Array.prototype.findIndex()`. + ```js const unionWith = (a, b, comp) => Array.from(new Set([...a, ...b.filter(x => a.findIndex(y => comp(x, y)) === -1)])); @@ -2902,18 +2901,18 @@ const unionWith = (a, b, comp) => ```js unionWith([1, 1.2, 1.5, 3, 0], [1.9, 3, 0, 3.9], (a, b) => Math.round(a) === Math.round(b)); // [1, 1.2, 1.5, 3, 0, 3.9] -``` +```
[⬆ Back to top](#contents) -### uniqueElements - -Returns all unique values of an array. - -Use ES6 `Set` and the `...rest` operator to discard all duplicated values. - +### uniqueElements + +Returns all unique values of an array. + +Use ES6 `Set` and the `...rest` operator to discard all duplicated values. + ```js const uniqueElements = arr => [...new Set(arr)]; ``` @@ -2923,19 +2922,19 @@ const uniqueElements = arr => [...new Set(arr)]; ```js uniqueElements([1, 2, 2, 3, 4, 4, 5]); // [1, 2, 3, 4, 5] -``` +```
[⬆ Back to top](#contents) -### uniqueElementsBy - -Returns all unique values of an array, based on a provided comparator function. - -Use `Array.prototype.reduce()` and `Array.prototype.some()` for an array containing only the first unique occurence of each value, based on the comparator function, `fn`. -The comparator function takes two arguments: the values of the two elements being compared. - +### uniqueElementsBy + +Returns all unique values of an array, based on a provided comparator function. + +Use `Array.prototype.reduce()` and `Array.prototype.some()` for an array containing only the first unique occurence of each value, based on the comparator function, `fn`. +The comparator function takes two arguments: the values of the two elements being compared. + ```js const uniqueElementsBy = (arr, fn) => arr.reduce((acc, v) => { @@ -2958,19 +2957,19 @@ uniqueElementsBy( ], (a, b) => a.id == b.id ); // [ { id: 0, value: 'a' }, { id: 1, value: 'b' }, { id: 2, value: 'c' } ] -``` +```
[⬆ Back to top](#contents) -### uniqueElementsByRight - -Returns all unique values of an array, based on a provided comparator function. - -Use `Array.prototype.reduce()` and `Array.prototype.some()` for an array containing only the last unique occurence of each value, based on the comparator function, `fn`. -The comparator function takes two arguments: the values of the two elements being compared. - +### uniqueElementsByRight + +Returns all unique values of an array, based on a provided comparator function. + +Use `Array.prototype.reduce()` and `Array.prototype.some()` for an array containing only the last unique occurence of each value, based on the comparator function, `fn`. +The comparator function takes two arguments: the values of the two elements being compared. + ```js const uniqueElementsByRight = (arr, fn) => arr.reduceRight((acc, v) => { @@ -2993,18 +2992,18 @@ uniqueElementsByRight( ], (a, b) => a.id == b.id ); // [ { id: 0, value: 'e' }, { id: 1, value: 'd' }, { id: 2, value: 'c' } ] -``` +```
[⬆ Back to top](#contents) -### uniqueSymmetricDifference - -Returns the unique symmetric difference between two arrays, not containing duplicate values from either array. - -Use `Array.prototype.filter()` and `Array.prototype.includes()` on each array to remove values contained in the other, then create a `Set` from the results, removing duplicate values. - +### uniqueSymmetricDifference + +Returns the unique symmetric difference between two arrays, not containing duplicate values from either array. + +Use `Array.prototype.filter()` and `Array.prototype.includes()` on each array to remove values contained in the other, then create a `Set` from the results, removing duplicate values. + ```js const uniqueSymmetricDifference = (a, b) => [ ...new Set([...a.filter(v => !b.includes(v)), ...b.filter(v => !a.includes(v))]) @@ -3017,36 +3016,36 @@ const uniqueSymmetricDifference = (a, b) => [ ```js uniqueSymmetricDifference([1, 2, 3], [1, 2, 4]); // [3, 4] uniqueSymmetricDifference([1, 2, 2], [1, 3, 1]); // [2, 3] -``` +```
[⬆ Back to top](#contents) -### unzip - -Creates an array of arrays, ungrouping the elements in an array produced by [zip](#zip). - -Use `Math.max.apply()` to get the longest subarray in the array, `Array.prototype.map()` to make each element an array. -Use `Array.prototype.reduce()` and `Array.prototype.forEach()` to map grouped values to individual arrays. - +### unzip + +Creates an array of arrays, ungrouping the elements in an array produced by [zip](#zip). + +Use `Math.max.apply()` to get the longest subarray in the array, `Array.prototype.map()` to make each element an array. +Use `Array.prototype.reduce()` and `Array.prototype.forEach()` to map grouped values to individual arrays. + ```js -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 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 => []) + ); ```
Examples ```js -unzip([['a', 1, true], ['b', 2, false]]); // [['a', 'b'], [1, 2], [true, false]] -unzip([['a', 1, true], ['b', 2]]); // [['a', 'b'], [1, 2], [true]] -``` +unzip([['a', 1, true], ['b', 2, false]]); // [['a', 'b'], [1, 2], [true, false]] +unzip([['a', 1, true], ['b', 2]]); // [['a', 'b'], [1, 2], [true]] +```
@@ -3083,14 +3082,14 @@ unzipWith([[1, 10, 100], [2, 20, 200]], (...args) => args.reduce((acc, v) => acc
[⬆ Back to top](#contents) -### without - -Filters out the elements of an array, that have one of the specified values. - -Use `Array.prototype.filter()` to create an array excluding(using `!Array.includes()`) all given values. - -_(For a snippet that mutates the original array see [`pull`](#pull))_ - +### without + +Filters out the elements of an array, that have one of the specified values. + +Use `Array.prototype.filter()` to create an array excluding(using `!Array.includes()`) all given values. + +_(For a snippet that mutates the original array see [`pull`](#pull))_ + ```js const without = (arr, ...args) => arr.filter(v => !args.includes(v)); ``` @@ -3100,18 +3099,18 @@ const without = (arr, ...args) => arr.filter(v => !args.includes(v)); ```js without([2, 1, 2, 3], 1, 2); // [3] -``` +```
[⬆ Back to top](#contents) -### xProd - -Creates a new array out of the two supplied by creating each possible pair from the arrays. - -Use `Array.prototype.reduce()`, `Array.prototype.map()` and `Array.prototype.concat()` to produce every possible pair from the elements of the two arrays and save them in an array. - +### xProd + +Creates a new array out of the two supplied by creating each possible pair from the arrays. + +Use `Array.prototype.reduce()`, `Array.prototype.map()` and `Array.prototype.concat()` to produce every possible pair from the elements of the two arrays and save them in an array. + ```js const xProd = (a, b) => a.reduce((acc, x) => acc.concat(b.map(y => [x, y])), []); ``` @@ -3121,20 +3120,20 @@ const xProd = (a, b) => a.reduce((acc, x) => acc.concat(b.map(y => [x, y])), []) ```js xProd([1, 2], ['a', 'b']); // [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b']] -``` +```
[⬆ Back to top](#contents) -### zip - -Creates an array of elements, grouped based on the position in the original arrays. - -Use `Math.max.apply()` to get the longest array in the arguments. -Creates an array with that length as return value and use `Array.from()` with a map-function to create an array of grouped elements. -If lengths of the argument-arrays vary, `undefined` is used where no value could be found. - +### zip + +Creates an array of elements, grouped based on the position in the original arrays. + +Use `Math.max.apply()` to get the longest array in the arguments. +Creates an array with that length as return value and use `Array.from()` with a map-function to create an array of grouped elements. +If lengths of the argument-arrays vary, `undefined` is used where no value could be found. + ```js const zip = (...arrays) => { const maxLength = Math.max(...arrays.map(x => x.length)); @@ -3150,18 +3149,18 @@ const zip = (...arrays) => { ```js zip(['a', 'b'], [1, 2], [true, false]); // [['a', 1, true], ['b', 2, false]] zip(['a'], [1, 2], [true, false]); // [['a', 1, true], [undefined, 2, false]] -``` +```
[⬆ Back to top](#contents) -### zipObject - -Given an array of valid property identifiers and an array of values, return an object associating the properties to the values. - -Since an object can have undefined values but not undefined property pointers, the array of properties is used to decide the structure of the resulting object using `Array.prototype.reduce()`. - +### zipObject + +Given an array of valid property identifiers and an array of values, return an object associating the properties to the values. + +Since an object can have undefined values but not undefined property pointers, the array of properties is used to decide the structure of the resulting object using `Array.prototype.reduce()`. + ```js const zipObject = (props, values) => props.reduce((obj, prop, index) => ((obj[prop] = values[index]), obj), {}); @@ -3173,7 +3172,7 @@ const zipObject = (props, values) => ```js zipObject(['a', 'b', 'c'], [1, 2]); // {a: 1, b: 2, c: undefined} zipObject(['a', 'b'], [1, 2, 3]); // {a: 1, b: 2} -``` +``` @@ -3221,12 +3220,12 @@ zipWith( ## 🌐 Browser -### arrayToHtmlList - -Converts the given array elements into `
  • ` tags and appends them to the list of the given id. - -Use `Array.prototype.map()`, `document.querySelector()`, and an anonymous inner closure to create a list of html tags. - +### arrayToHtmlList + +Converts the given array elements into `
  • ` tags and appends them to the list of the given id. + +Use `Array.prototype.map()`, `document.querySelector()`, and an anonymous inner closure to create a list of html tags. + ```js const arrayToHtmlList = (arr, listID) => (el => ( @@ -3240,18 +3239,18 @@ const arrayToHtmlList = (arr, listID) => ```js arrayToHtmlList(['item 1', 'item 2'], 'myListID'); -``` +```
    [⬆ Back to top](#contents) -### bottomVisible - -Returns `true` if the bottom of the page is visible, `false` otherwise. - -Use `scrollY`, `scrollHeight` and `clientHeight` to determine if the bottom of the page is visible. - +### bottomVisible + +Returns `true` if the bottom of the page is visible, `false` otherwise. + +Use `scrollY`, `scrollHeight` and `clientHeight` to determine if the bottom of the page is visible. + ```js const bottomVisible = () => document.documentElement.clientHeight + window.scrollY >= @@ -3263,7 +3262,7 @@ const bottomVisible = () => ```js bottomVisible(); // true -``` +``` @@ -3348,15 +3347,15 @@ counter('#my-id', 1, 1000, 5, 2000); // Creates a 2-second timer for the element
    [⬆ Back to top](#contents) -### createElement - -Creates an element from a string (without appending it to the document). -If the given string contains multiple elements, only the first one will be returned. - -Use `document.createElement()` to create a new element. -Set its `innerHTML` to the string supplied as the argument. -Use `ParentNode.firstElementChild` to return the element version of the string. - +### createElement + +Creates an element from a string (without appending it to the document). +If the given string contains multiple elements, only the first one will be returned. + +Use `document.createElement()` to create a new element. +Set its `innerHTML` to the string supplied as the argument. +Use `ParentNode.firstElementChild` to return the element version of the string. + ```js const createElement = str => { const el = document.createElement('div'); @@ -3375,7 +3374,7 @@ const el = createElement( ` ); console.log(el.className); // 'container' -``` +``` @@ -3434,12 +3433,12 @@ hub.off('message', handler);
    [⬆ Back to top](#contents) -### currentURL - -Returns the current URL. - -Use `window.location.href` to get current URL. - +### currentURL + +Returns the current URL. + +Use `window.location.href` to get current URL. + ```js const currentURL = () => window.location.href; ``` @@ -3449,18 +3448,18 @@ const currentURL = () => window.location.href; ```js currentURL(); // 'https://google.com' -``` +```
    [⬆ Back to top](#contents) -### detectDeviceType - -Detects wether the website is being opened in a mobile device or a desktop/laptop. - -Use a regular expression to test the `navigator.userAgent` property to figure out if the device is a mobile device or a desktop/laptop. - +### detectDeviceType + +Detects wether the website is being opened in a mobile device or a desktop/laptop. + +Use a regular expression to test the `navigator.userAgent` property to figure out if the device is a mobile device or a desktop/laptop. + ```js const detectDeviceType = () => /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) @@ -3473,18 +3472,18 @@ const detectDeviceType = () => ```js detectDeviceType(); // "Mobile" or "Desktop" -``` +```
    [⬆ Back to top](#contents) -### elementContains - -Returns `true` if the `parent` element contains the `child` element, `false` otherwise. - -Check that `parent` is not the same element as `child`, use `parent.contains(child)` to check if the `parent` element contains the `child` element. - +### elementContains + +Returns `true` if the `parent` element contains the `child` element, `false` otherwise. + +Check that `parent` is not the same element as `child`, use `parent.contains(child)` to check if the `parent` element contains the `child` element. + ```js const elementContains = (parent, child) => parent !== child && parent.contains(child); ``` @@ -3495,7 +3494,7 @@ const elementContains = (parent, child) => parent !== child && parent.contains(c ```js elementContains(document.querySelector('head'), document.querySelector('title')); // true elementContains(document.querySelector('body'), document.querySelector('body')); // false -``` +``` @@ -3534,38 +3533,38 @@ elementIsVisibleInViewport(el, true); // true - (partially visible)
    [⬆ Back to top](#contents) -### getImages - -Fetches all images from within an element and puts them into an array - -Use `Element.prototype.getElementsByTagName()` to fetch all `` elements inside the provided element, `Array.prototype.map()` to map every `src` attribute of their respective `` element, then create a `Set` to eliminate duplicates and return the array. - +### getImages + +Fetches all images from within an element and puts them into an array + +Use `Element.prototype.getElementsByTagName()` to fetch all `` elements inside the provided element, `Array.prototype.map()` to map every `src` attribute of their respective `` element, then create a `Set` to eliminate duplicates and return the array. + ```js -const getImages = (el, includeDuplicates = false) => { - const images = [...el.getElementsByTagName('img')].map(img => img.getAttribute('src')); - return includeDuplicates ? images : [...new Set(images)]; -}; +const getImages = (el, includeDuplicates = false) => { + const images = [...el.getElementsByTagName('img')].map(img => img.getAttribute('src')); + return includeDuplicates ? images : [...new Set(images)]; +}; ```
    Examples ```js -getImages(document, true); // ['image1.jpg', 'image2.png', 'image1.png', '...'] -getImages(document, false); // ['image1.jpg', 'image2.png', '...'] -``` +getImages(document, true); // ['image1.jpg', 'image2.png', 'image1.png', '...'] +getImages(document, false); // ['image1.jpg', 'image2.png', '...'] +```

    [⬆ Back to top](#contents) -### getScrollPosition - -Returns the scroll position of the current page. - -Use `pageXOffset` and `pageYOffset` if they are defined, otherwise `scrollLeft` and `scrollTop`. -You can omit `el` to use a default value of `window`. - +### getScrollPosition + +Returns the scroll position of the current page. + +Use `pageXOffset` and `pageYOffset` if they are defined, otherwise `scrollLeft` and `scrollTop`. +You can omit `el` to use a default value of `window`. + ```js const getScrollPosition = (el = window) => ({ x: el.pageXOffset !== undefined ? el.pageXOffset : el.scrollLeft, @@ -3578,18 +3577,18 @@ const getScrollPosition = (el = window) => ({ ```js getScrollPosition(); // {x: 0, y: 200} -``` +```
    [⬆ Back to top](#contents) -### getStyle - -Returns the value of a CSS rule for the specified element. - -Use `Window.getComputedStyle()` to get the value of the CSS rule for the specified element. - +### getStyle + +Returns the value of a CSS rule for the specified element. + +Use `Window.getComputedStyle()` to get the value of the CSS rule for the specified element. + ```js const getStyle = (el, ruleName) => getComputedStyle(el)[ruleName]; ``` @@ -3599,18 +3598,18 @@ const getStyle = (el, ruleName) => getComputedStyle(el)[ruleName]; ```js getStyle(document.querySelector('p'), 'font-size'); // '16px' -``` +```
    [⬆ Back to top](#contents) -### hasClass - -Returns `true` if the element has the specified class, `false` otherwise. - -Use `element.classList.contains()` to check if the element has the specified class. - +### hasClass + +Returns `true` if the element has the specified class, `false` otherwise. + +Use `element.classList.contains()` to check if the element has the specified class. + ```js const hasClass = (el, className) => el.classList.contains(className); ``` @@ -3620,7 +3619,7 @@ const hasClass = (el, className) => el.classList.contains(className); ```js hasClass(document.querySelector('p.special'), 'special'); // true -``` +``` @@ -3654,33 +3653,33 @@ hashBrowser(JSON.stringify({ a: 'a', b: [1, 2, 3, 4], foo: { c: 'bar' } })).then
    [⬆ Back to top](#contents) -### hide - -Hides all the elements specified. - -Use `NodeList.prototype.forEach()` to apply `display: none` to each element specified. - +### hide + +Hides all the elements specified. + +Use `NodeList.prototype.forEach()` to apply `display: none` to each element specified. + ```js -const hide = (...el) => [...el].forEach(e => (e.style.display = 'none')); +const hide = (...el) => [...el].forEach(e => (e.style.display = 'none')); ```
    Examples ```js -hide(document.querySelectorAll('img')); // Hides all elements on the page -``` +hide(document.querySelectorAll('img')); // Hides all elements on the page +```

    [⬆ Back to top](#contents) -### httpsRedirect - -Redirects the page to HTTPS if its currently in HTTP. Also, pressing the back button doesn't take it back to the HTTP page as its replaced in the history. - -Use `location.protocol` to get the protocol currently being used. If it's not HTTPS, use `location.replace()` to replace the existing page with the HTTPS version of the page. Use `location.href` to get the full address, split it with `String.prototype.split()` and remove the protocol part of the URL. - +### httpsRedirect + +Redirects the page to HTTPS if its currently in HTTP. Also, pressing the back button doesn't take it back to the HTTP page as its replaced in the history. + +Use `location.protocol` to get the protocol currently being used. If it's not HTTPS, use `location.replace()` to replace the existing page with the HTTPS version of the page. Use `location.href` to get the full address, split it with `String.prototype.split()` and remove the protocol part of the URL. + ```js const httpsRedirect = () => { if (location.protocol !== 'https:') location.replace('https://' + location.href.split('//')[1]); @@ -3692,18 +3691,18 @@ const httpsRedirect = () => { ```js httpsRedirect(); // If you are on http://mydomain.com, you are redirected to https://mydomain.com -``` +```
    [⬆ Back to top](#contents) -### insertAfter - -Inserts an HTML string after the end of the specified element. - -Use `el.insertAdjacentHTML()` with a position of `'afterend'` to parse `htmlString` and insert it after the end of `el`. - +### insertAfter + +Inserts an HTML string after the end of the specified element. + +Use `el.insertAdjacentHTML()` with a position of `'afterend'` to parse `htmlString` and insert it after the end of `el`. + ```js const insertAfter = (el, htmlString) => el.insertAdjacentHTML('afterend', htmlString); ``` @@ -3713,18 +3712,18 @@ const insertAfter = (el, htmlString) => el.insertAdjacentHTML('afterend', htmlSt ```js insertAfter(document.getElementById('myId'), '

    after

    '); //
    ...

    after

    -``` +```
    [⬆ Back to top](#contents) -### insertBefore - -Inserts an HTML string before the start of the specified element. - -Use `el.insertAdjacentHTML()` with a position of `'beforebegin'` to parse `htmlString` and insert it before the start of `el`. - +### insertBefore + +Inserts an HTML string before the start of the specified element. + +Use `el.insertAdjacentHTML()` with a position of `'beforebegin'` to parse `htmlString` and insert it before the start of `el`. + ```js const insertBefore = (el, htmlString) => el.insertAdjacentHTML('beforebegin', htmlString); ``` @@ -3734,18 +3733,18 @@ const insertBefore = (el, htmlString) => el.insertAdjacentHTML('beforebegin', ht ```js insertBefore(document.getElementById('myId'), '

    before

    '); //

    before

    ...
    -``` +```
    [⬆ Back to top](#contents) -### isBrowserTabFocused - -Returns `true` if the browser tab of the page is focused, `false` otherwise. - -Use the `Document.hidden` property, introduced by the Page Visibility API to check if the browser tab of the page is visible or hidden. - +### isBrowserTabFocused + +Returns `true` if the browser tab of the page is focused, `false` otherwise. + +Use the `Document.hidden` property, introduced by the Page Visibility API to check if the browser tab of the page is visible or hidden. + ```js const isBrowserTabFocused = () => !document.hidden; ``` @@ -3755,18 +3754,18 @@ const isBrowserTabFocused = () => !document.hidden; ```js isBrowserTabFocused(); // true -``` +```
    [⬆ Back to top](#contents) -### nodeListToArray - -Converts a `NodeList` to an array. - -Use spread operator inside new array to convert a `NodeList` to an array. - +### nodeListToArray + +Converts a `NodeList` to an array. + +Use spread operator inside new array to convert a `NodeList` to an array. + ```js const nodeListToArray = nodeList => [...nodeList]; ``` @@ -3776,7 +3775,7 @@ const nodeListToArray = nodeList => [...nodeList]; ```js nodeListToArray(document.childNodes); // [ , html ] -``` +``` @@ -3823,13 +3822,13 @@ obs.disconnect(); // Disconnects the observer and stops logging mutations on the
    [⬆ Back to top](#contents) -### off - -Removes an event listener from an element. - -Use `EventTarget.removeEventListener()` to remove an event listener from an element. -Omit the fourth argument `opts` to use `false` or specify it based on the options used when the event listener was added. - +### off + +Removes an event listener from an element. + +Use `EventTarget.removeEventListener()` to remove an event listener from an element. +Omit the fourth argument `opts` to use `false` or specify it based on the options used when the event listener was added. + ```js const off = (el, evt, fn, opts = false) => el.removeEventListener(evt, fn, opts); ``` @@ -3841,20 +3840,20 @@ const off = (el, evt, fn, opts = false) => el.removeEventListener(evt, fn, opts) const fn = () => console.log('!'); document.body.addEventListener('click', fn); off(document.body, 'click', fn); // no longer logs '!' upon clicking on the page -``` +```
    [⬆ Back to top](#contents) -### on - -Adds an event listener to an element with the ability to use event delegation. - -Use `EventTarget.addEventListener()` to add an event listener to an element. If there is a `target` property supplied to the options object, ensure the event target matches the target specified and then invoke the callback by supplying the correct `this` context. -Returns a reference to the custom delegator function, in order to be possible to use with [`off`](#off). -Omit `opts` to default to non-delegation behavior and event bubbling. - +### on + +Adds an event listener to an element with the ability to use event delegation. + +Use `EventTarget.addEventListener()` to add an event listener to an element. If there is a `target` property supplied to the options object, ensure the event target matches the target specified and then invoke the callback by supplying the correct `this` context. +Returns a reference to the custom delegator function, in order to be possible to use with [`off`](#off). +Omit `opts` to default to non-delegation behavior and event bubbling. + ```js const on = (el, evt, fn, opts = {}) => { const delegatorFn = e => e.target.matches(opts.target) && fn.call(e.target, e); @@ -3871,7 +3870,7 @@ const fn = () => console.log('!'); on(document.body, 'click', fn); // logs '!' upon clicking the body on(document.body, 'click', fn, { target: 'p' }); // logs '!' upon clicking a `p` element child of the body on(document.body, 'click', fn, { options: true }); // use capturing instead of bubbling -``` +``` @@ -3915,13 +3914,13 @@ onUserInputChange(type => {
    [⬆ Back to top](#contents) -### prefix - -Returns the prefixed version (if necessary) of a CSS property that the browser supports. - -Use `Array.prototype.findIndex()` on an array of vendor prefix strings to test if `document.body` has one of them defined in its `CSSStyleDeclaration` object, otherwise return `null`. -Use `String.prototype.charAt()` and `String.prototype.toUpperCase()` to capitalize the property, which will be appended to the vendor prefix string. - +### prefix + +Returns the prefixed version (if necessary) of a CSS property that the browser supports. + +Use `Array.prototype.findIndex()` on an array of vendor prefix strings to test if `document.body` has one of them defined in its `CSSStyleDeclaration` object, otherwise return `null`. +Use `String.prototype.charAt()` and `String.prototype.toUpperCase()` to capitalize the property, which will be appended to the vendor prefix string. + ```js const prefix = prop => { const capitalizedProp = prop.charAt(0).toUpperCase() + prop.slice(1); @@ -3938,21 +3937,21 @@ const prefix = prop => { ```js prefix('appearance'); // 'appearance' on a supported browser, otherwise 'webkitAppearance', 'mozAppearance', 'msAppearance' or 'oAppearance' -``` +```
    [⬆ Back to top](#contents) -### recordAnimationFrames - -Invokes the provided callback on each animation frame. - -Use recursion. -Provided that `running` is `true`, continue invoking `window.requestAnimationFrame()` which invokes the provided callback. -Return an object with two methods `start` and `stop` to allow manual control of the recording. -Omit the second argument, `autoStart`, to implicitly call `start` when the function is invoked. - +### recordAnimationFrames + +Invokes the provided callback on each animation frame. + +Use recursion. +Provided that `running` is `true`, continue invoking `window.requestAnimationFrame()` which invokes the provided callback. +Return an object with two methods `start` and `stop` to allow manual control of the recording. +Omit the second argument, `autoStart`, to implicitly call `start` when the function is invoked. + ```js const recordAnimationFrames = (callback, autoStart = true) => { let running = true, @@ -3985,19 +3984,19 @@ const recorder = recordAnimationFrames(cb); // logs 'Animation frame fired' on e recorder.stop(); // stops logging recorder.start(); // starts again const recorder2 = recordAnimationFrames(cb, false); // `start` needs to be explicitly called to begin recording frames -``` +```
    [⬆ Back to top](#contents) -### redirect - -Redirects to a specified URL. - -Use `window.location.href` or `window.location.replace()` to redirect to `url`. -Pass a second argument to simulate a link click (`true` - default) or an HTTP redirect (`false`). - +### redirect + +Redirects to a specified URL. + +Use `window.location.href` or `window.location.replace()` to redirect to `url`. +Pass a second argument to simulate a link click (`true` - default) or an HTTP redirect (`false`). + ```js const redirect = (url, asLink = true) => asLink ? (window.location.href = url) : window.location.replace(url); @@ -4008,7 +4007,7 @@ const redirect = (url, asLink = true) => ```js redirect('https://google.com'); -``` +``` @@ -4066,13 +4065,13 @@ runAsync(() => typeof outsideVariable).then(console.log); // 'undefined'
    [⬆ Back to top](#contents) -### scrollToTop - -Smooth-scrolls to the top of the page. - -Get distance from top using `document.documentElement.scrollTop` or `document.body.scrollTop`. -Scroll by a fraction of the distance from the top. Use `window.requestAnimationFrame()` to animate the scrolling. - +### scrollToTop + +Smooth-scrolls to the top of the page. + +Get distance from top using `document.documentElement.scrollTop` or `document.body.scrollTop`. +Scroll by a fraction of the distance from the top. Use `window.requestAnimationFrame()` to animate the scrolling. + ```js const scrollToTop = () => { const c = document.documentElement.scrollTop || document.body.scrollTop; @@ -4088,18 +4087,18 @@ const scrollToTop = () => { ```js scrollToTop(); -``` +```
    [⬆ Back to top](#contents) -### setStyle - -Sets the value of a CSS rule for the specified element. - -Use `element.style` to set the value of the CSS rule for the specified element to `val`. - +### setStyle + +Sets the value of a CSS rule for the specified element. + +Use `element.style` to set the value of the CSS rule for the specified element to `val`. + ```js const setStyle = (el, ruleName, val) => (el.style[ruleName] = val); ``` @@ -4109,18 +4108,18 @@ const setStyle = (el, ruleName, val) => (el.style[ruleName] = val); ```js setStyle(document.querySelector('p'), 'font-size', '20px'); // The first

    element on the page will have a font-size of 20px -``` +```
    [⬆ Back to top](#contents) -### show - -Shows all the elements specified. - -Use the spread operator (`...`) and `Array.prototype.forEach()` to clear the `display` property for each element specified. - +### show + +Shows all the elements specified. + +Use the spread operator (`...`) and `Array.prototype.forEach()` to clear the `display` property for each element specified. + ```js const show = (...el) => [...el].forEach(e => (e.style.display = '')); ``` @@ -4130,19 +4129,19 @@ const show = (...el) => [...el].forEach(e => (e.style.display = '')); ```js show(...document.querySelectorAll('img')); // Shows all elements on the page -``` +```
    [⬆ Back to top](#contents) -### smoothScroll - -Smoothly scrolls the element on which it's called into the visible area of the browser window. - -Use `.scrollIntoView` method to scroll the element. -Pass `{ behavior: 'smooth' }` to `.scrollIntoView` so it scrolls smoothly. - +### smoothScroll + +Smoothly scrolls the element on which it's called into the visible area of the browser window. + +Use `.scrollIntoView` method to scroll the element. +Pass `{ behavior: 'smooth' }` to `.scrollIntoView` so it scrolls smoothly. + ```js const smoothScroll = element => document.querySelector(element).scrollIntoView({ @@ -4156,18 +4155,18 @@ const smoothScroll = element => ```js smoothScroll('#fooBar'); // scrolls smoothly to the element with the id fooBar smoothScroll('.fooBar'); // scrolls smoothly to the first element with a class of fooBar -``` +```
    [⬆ Back to top](#contents) -### toggleClass - -Toggle a class for an element. - -Use `element.classList.toggle()` to toggle the specified class for the element. - +### toggleClass + +Toggle a class for an element. + +Use `element.classList.toggle()` to toggle the specified class for the element. + ```js const toggleClass = (el, className) => el.classList.toggle(className); ``` @@ -4177,43 +4176,43 @@ const toggleClass = (el, className) => el.classList.toggle(className); ```js toggleClass(document.querySelector('p.special'), 'special'); // The paragraph will not have the 'special' class anymore -``` +```
    [⬆ Back to top](#contents) -### triggerEvent - -Triggers a specific event on a given element, optionally passing custom data. - -Use `new CustomEvent()` to create an event from the specified `eventType` and details. -Use `el.dispatchEvent()` to trigger the newly created event on the given element. -Omit the third argument, `detail`, if you do not want to pass custom data to the triggered event. - +### triggerEvent + +Triggers a specific event on a given element, optionally passing custom data. + +Use `new CustomEvent()` to create an event from the specified `eventType` and details. +Use `el.dispatchEvent()` to trigger the newly created event on the given element. +Omit the third argument, `detail`, if you do not want to pass custom data to the triggered event. + ```js -const triggerEvent = (el, eventType, detail) => - el.dispatchEvent(new CustomEvent(eventType, { detail })); +const triggerEvent = (el, eventType, detail) => + el.dispatchEvent(new CustomEvent(eventType, { detail })); ```

    Examples ```js -triggerEvent(document.getElementById('myId'), 'click'); -triggerEvent(document.getElementById('myId'), 'click', { username: 'bob' }); -``` +triggerEvent(document.getElementById('myId'), 'click'); +triggerEvent(document.getElementById('myId'), 'click', { username: 'bob' }); +```

    [⬆ Back to top](#contents) -### UUIDGeneratorBrowser - -Generates a UUID in a browser. - -Use `crypto` API to generate a UUID, compliant with [RFC4122](https://www.ietf.org/rfc/rfc4122.txt) version 4. - +### UUIDGeneratorBrowser + +Generates a UUID in a browser. + +Use `crypto` API to generate a UUID, compliant with [RFC4122](https://www.ietf.org/rfc/rfc4122.txt) version 4. + ```js const UUIDGeneratorBrowser = () => ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => @@ -4226,7 +4225,7 @@ const UUIDGeneratorBrowser = () => ```js UUIDGeneratorBrowser(); // '7982fcfe-5721-4632-bede-6000885be57d' -``` +``` @@ -4237,38 +4236,38 @@ UUIDGeneratorBrowser(); // '7982fcfe-5721-4632-bede-6000885be57d' ## ⏱️ Date -### dayOfYear - -Gets the day of the year from a `Date` object. - -Use `new Date()` and `Date.prototype.getFullYear()` to get the first day of the year as a `Date` object, subtract it from the provided `date` and divide with the milliseconds in each day to get the result. -Use `Math.floor()` to appropriately round the resulting day count to an integer. - +### dayOfYear + +Gets the day of the year from a `Date` object. + +Use `new Date()` and `Date.prototype.getFullYear()` to get the first day of the year as a `Date` object, subtract it from the provided `date` and divide with the milliseconds in each day to get the result. +Use `Math.floor()` to appropriately round the resulting day count to an integer. + ```js -const dayOfYear = date => - Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24); +const dayOfYear = date => + Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24); ```
    Examples ```js -dayOfYear(new Date()); // 272 -``` +dayOfYear(new Date()); // 272 +```

    [⬆ Back to top](#contents) -### formatDuration - -Returns the human readable format of the given number of milliseconds. - -Divide `ms` with the appropriate values to obtain the appropriate values for `day`, `hour`, `minute`, `second` and `millisecond`. -Use `Object.entries()` with `Array.prototype.filter()` to keep only non-zero values. -Use `Array.prototype.map()` to create the string for each value, pluralizing appropriately. -Use `String.prototype.join(', ')` to combine the values into a string. - +### formatDuration + +Returns the human readable format of the given number of milliseconds. + +Divide `ms` with the appropriate values to obtain the appropriate values for `day`, `hour`, `minute`, `second` and `millisecond`. +Use `Object.entries()` with `Array.prototype.filter()` to keep only non-zero values. +Use `Array.prototype.map()` to create the string for each value, pluralizing appropriately. +Use `String.prototype.join(', ')` to combine the values into a string. + ```js const formatDuration = ms => { if (ms < 0) ms = -ms; @@ -4292,39 +4291,39 @@ const formatDuration = ms => { ```js formatDuration(1001); // '1 second, 1 millisecond' formatDuration(34325055574); // '397 days, 6 hours, 44 minutes, 15 seconds, 574 milliseconds' -``` +```
    [⬆ Back to top](#contents) -### getColonTimeFromDate - -Returns a string of the form `HH:MM:SS` from a `Date` object. - -Use `Date.prototype.toTimeString()` and `String.prototype.slice()` to get the `HH:MM:SS` part of a given `Date` object. - +### getColonTimeFromDate + +Returns a string of the form `HH:MM:SS` from a `Date` object. + +Use `Date.prototype.toTimeString()` and `String.prototype.slice()` to get the `HH:MM:SS` part of a given `Date` object. + ```js -const getColonTimeFromDate = date => date.toTimeString().slice(0, 8); +const getColonTimeFromDate = date => date.toTimeString().slice(0, 8); ```
    Examples ```js -getColonTimeFromDate(new Date()); // "08:38:00" -``` +getColonTimeFromDate(new Date()); // "08:38:00" +```

    [⬆ Back to top](#contents) -### getDaysDiffBetweenDates - -Returns the difference (in days) between two dates. - -Calculate the difference (in days) between two `Date` objects. - +### getDaysDiffBetweenDates + +Returns the difference (in days) between two dates. + +Calculate the difference (in days) between two `Date` objects. + ```js const getDaysDiffBetweenDates = (dateInitial, dateFinal) => (dateFinal - dateInitial) / (1000 * 3600 * 24); @@ -4335,181 +4334,181 @@ const getDaysDiffBetweenDates = (dateInitial, dateFinal) => ```js getDaysDiffBetweenDates(new Date('2017-12-13'), new Date('2017-12-22')); // 9 -``` +```
    [⬆ Back to top](#contents) -### getMeridiemSuffixOfInteger - -Converts an integer to a suffixed string, adding `am` or `pm` based on its value. - -Use the modulo operator (`%`) and conditional checks to transform an integer to a stringified 12-hour format with meridiem suffix. - +### getMeridiemSuffixOfInteger + +Converts an integer to a suffixed string, adding `am` or `pm` based on its value. + +Use the modulo operator (`%`) and conditional checks to transform an integer to a stringified 12-hour format with meridiem suffix. + ```js -const getMeridiemSuffixOfInteger = num => - num === 0 || num === 24 - ? 12 + 'am' - : num === 12 - ? 12 + 'pm' - : num < 12 - ? (num % 12) + 'am' - : (num % 12) + 'pm'; +const getMeridiemSuffixOfInteger = num => + num === 0 || num === 24 + ? 12 + 'am' + : num === 12 + ? 12 + 'pm' + : num < 12 + ? (num % 12) + 'am' + : (num % 12) + 'pm'; ```
    Examples ```js -getMeridiemSuffixOfInteger(0); // "12am" -getMeridiemSuffixOfInteger(11); // "11am" -getMeridiemSuffixOfInteger(13); // "1pm" -getMeridiemSuffixOfInteger(25); // "1pm" -``` +getMeridiemSuffixOfInteger(0); // "12am" +getMeridiemSuffixOfInteger(11); // "11am" +getMeridiemSuffixOfInteger(13); // "1pm" +getMeridiemSuffixOfInteger(25); // "1pm" +```

    [⬆ Back to top](#contents) -### isAfterDate - -Check if a date is after another date. - -Use the greater than operator (`>`) to check if the first date comes after the second one. - +### isAfterDate + +Check if a date is after another date. + +Use the greater than operator (`>`) to check if the first date comes after the second one. + ```js -const isAfterDate = (dateA, dateB) => dateA > dateB; +const isAfterDate = (dateA, dateB) => dateA > dateB; ```
    Examples ```js -isAfterDate(new Date(2010, 10, 21), new Date(2010, 10, 20)); // true -``` +isAfterDate(new Date(2010, 10, 21), new Date(2010, 10, 20)); // true +```

    [⬆ Back to top](#contents) -### isBeforeDate - -Check if a date is before another date. - -Use the less than operator (`<`) to check if the first date comes before the second one. - +### isBeforeDate + +Check if a date is before another date. + +Use the less than operator (`<`) to check if the first date comes before the second one. + ```js -const isBeforeDate = (dateA, dateB) => dateA < dateB; +const isBeforeDate = (dateA, dateB) => dateA < dateB; ```
    Examples ```js -isBeforeDate(new Date(2010, 10, 20), new Date(2010, 10, 21)); // true -``` +isBeforeDate(new Date(2010, 10, 20), new Date(2010, 10, 21)); // true +```

    [⬆ Back to top](#contents) -### isSameDate - -Check if a date is the same as another date. - -Use `Date.prototype.toISOString()` and strict equality checking (`===`) to check if the first date is the same as the second one. - +### isSameDate + +Check if a date is the same as another date. + +Use `Date.prototype.toISOString()` and strict equality checking (`===`) to check if the first date is the same as the second one. + ```js -const isSameDate = (dateA, dateB) => dateA.toISOString() === dateB.toISOString(); +const isSameDate = (dateA, dateB) => dateA.toISOString() === dateB.toISOString(); ```
    Examples ```js -isSameDate(new Date(2010, 10, 20), new Date(2010, 10, 20)); // true -``` +isSameDate(new Date(2010, 10, 20), new Date(2010, 10, 20)); // true +```

    [⬆ Back to top](#contents) -### maxDate - -Returns the maximum of the given dates. - -Use `Math.max.apply()` to find the maximum date value, `new Date()` to convert it to a `Date` object. - +### maxDate + +Returns the maximum of the given dates. + +Use `Math.max.apply()` to find the maximum date value, `new Date()` to convert it to a `Date` object. + ```js -const maxDate = (...dates) => new Date(Math.max.apply(null, ...dates)); +const maxDate = (...dates) => new Date(Math.max.apply(null, ...dates)); ```
    Examples ```js -const array = [ - new Date(2017, 4, 13), - new Date(2018, 2, 12), - new Date(2016, 0, 10), - new Date(2016, 0, 9) -]; -maxDate(array); // 2018-03-11T22:00:00.000Z -``` +const array = [ + new Date(2017, 4, 13), + new Date(2018, 2, 12), + new Date(2016, 0, 10), + new Date(2016, 0, 9) +]; +maxDate(array); // 2018-03-11T22:00:00.000Z +```

    [⬆ Back to top](#contents) -### minDate - -Returns the minimum of the given dates. - -Use `Math.min.apply()` to find the minimum date value, `new Date()` to convert it to a `Date` object. - +### minDate + +Returns the minimum of the given dates. + +Use `Math.min.apply()` to find the minimum date value, `new Date()` to convert it to a `Date` object. + ```js -const minDate = (...dates) => new Date(Math.min.apply(null, ...dates)); +const minDate = (...dates) => new Date(Math.min.apply(null, ...dates)); ```
    Examples ```js -const array = [ - new Date(2017, 4, 13), - new Date(2018, 2, 12), - new Date(2016, 0, 10), - new Date(2016, 0, 9) -]; -minDate(array); // 2016-01-08T22:00:00.000Z -``` +const array = [ + new Date(2017, 4, 13), + new Date(2018, 2, 12), + new Date(2016, 0, 10), + new Date(2016, 0, 9) +]; +minDate(array); // 2016-01-08T22:00:00.000Z +```

    [⬆ Back to top](#contents) -### tomorrow - -Results in a string representation of tomorrow's date. - -Use `new Date()` to get the current date, increment by one using `Date.getDate()` and set the value to the result using `Date.setDate()`. -Use `Date.prototype.toISOString()` to return a string in `yyyy-mm-dd` format. - +### tomorrow + +Results in a string representation of tomorrow's date. + +Use `new Date()` to get the current date, increment by one using `Date.getDate()` and set the value to the result using `Date.setDate()`. +Use `Date.prototype.toISOString()` to return a string in `yyyy-mm-dd` format. + ```js -const tomorrow = () => { - let t = new Date(); - t.setDate(t.getDate() + 1); - return t.toISOString().split('T')[0]; -}; +const tomorrow = () => { + let t = new Date(); + t.setDate(t.getDate() + 1); + return t.toISOString().split('T')[0]; +}; ```
    Examples ```js -tomorrow(); // 2018-10-18 (if current date is 2018-10-18) -``` +tomorrow(); // 2018-10-18 (if current date is 2018-10-18) +```
    @@ -4520,12 +4519,12 @@ tomorrow(); // 2018-10-18 (if current date is 2018-10-18) ## 🎛️ Function -### attempt - -Attempts to invoke a function with the provided arguments, returning either the result or the caught error object. - -Use a `try... catch` block to return either the result of the function or an appropriate error. - +### attempt + +Attempts to invoke a function with the provided arguments, returning either the result or the caught error object. + +Use a `try... catch` block to return either the result of the function or an appropriate error. + ```js const attempt = (fn, ...args) => { try { @@ -4544,19 +4543,19 @@ var elements = attempt(function(selector) { return document.querySelectorAll(selector); }, '>_>'); if (elements instanceof Error) elements = []; // elements = [] -``` +```
    [⬆ Back to top](#contents) -### bind - -Creates a function that invokes `fn` with a given context, optionally adding any additional supplied parameters to the beginning of the arguments. - -Return a `function` that uses `Function.prototype.apply()` to apply the given `context` to `fn`. -Use `Array.prototype.concat()` to prepend any additional supplied parameters to the arguments. - +### bind + +Creates a function that invokes `fn` with a given context, optionally adding any additional supplied parameters to the beginning of the arguments. + +Return a `function` that uses `Function.prototype.apply()` to apply the given `context` to `fn`. +Use `Array.prototype.concat()` to prepend any additional supplied parameters to the arguments. + ```js const bind = (fn, context, ...boundArgs) => (...args) => fn.apply(context, [...boundArgs, ...args]); ``` @@ -4571,19 +4570,19 @@ function greet(greeting, punctuation) { const freddy = { user: 'fred' }; const freddyBound = bind(greet, freddy); console.log(freddyBound('hi', '!')); // 'hi fred!' -``` +```
    [⬆ Back to top](#contents) -### bindKey - -Creates a function that invokes the method at a given key of an object, optionally adding any additional supplied parameters to the beginning of the arguments. - -Return a `function` that uses `Function.prototype.apply()` to bind `context[fn]` to `context`. -Use the spread operator (`...`) to prepend any additional supplied parameters to the arguments. - +### bindKey + +Creates a function that invokes the method at a given key of an object, optionally adding any additional supplied parameters to the beginning of the arguments. + +Return a `function` that uses `Function.prototype.apply()` to bind `context[fn]` to `context`. +Use the spread operator (`...`) to prepend any additional supplied parameters to the arguments. + ```js const bindKey = (context, fn, ...boundArgs) => (...args) => context[fn].apply(context, [...boundArgs, ...args]); @@ -4601,88 +4600,88 @@ const freddy = { }; const freddyBound = bindKey(freddy, 'greet'); console.log(freddyBound('hi', '!')); // 'hi fred!' -``` +```
    [⬆ Back to top](#contents) -### chainAsync - -Chains asynchronous functions. - -Loop through an array of functions containing asynchronous events, calling `next` when each asynchronous event has completed. - +### chainAsync + +Chains asynchronous functions. + +Loop through an array of functions containing asynchronous events, calling `next` when each asynchronous event has completed. + ```js -const chainAsync = fns => { - let curr = 0; - const last = fns[fns.length - 1]; - const next = () => { - const fn = fns[curr++]; - fn === last ? fn() : fn(next); - }; - next(); -}; +const chainAsync = fns => { + let curr = 0; + const last = fns[fns.length - 1]; + const next = () => { + const fn = fns[curr++]; + fn === last ? fn() : fn(next); + }; + next(); +}; ```
    Examples ```js -chainAsync([ - next => { - console.log('0 seconds'); - setTimeout(next, 1000); - }, - next => { - console.log('1 second'); - setTimeout(next, 1000); - }, - () => { - console.log('2 second'); - } -]); -``` +chainAsync([ + next => { + console.log('0 seconds'); + setTimeout(next, 1000); + }, + next => { + console.log('1 second'); + setTimeout(next, 1000); + }, + () => { + console.log('2 second'); + } +]); +```

    [⬆ Back to top](#contents) -### compose - -Performs right-to-left function composition. - -Use `Array.prototype.reduce()` to perform right-to-left function composition. -The last (rightmost) function can accept one or more arguments; the remaining functions must be unary. - +### compose + +Performs right-to-left function composition. + +Use `Array.prototype.reduce()` to perform right-to-left function composition. +The last (rightmost) function can accept one or more arguments; the remaining functions must be unary. + ```js -const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args))); +const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args))); ```
    Examples ```js -const add5 = x => x + 5; -const multiply = (x, y) => x * y; -const multiplyAndAdd5 = compose( - add5, - multiply -); -multiplyAndAdd5(5, 2); // 15 -``` +const add5 = x => x + 5; +const multiply = (x, y) => x * y; +const multiplyAndAdd5 = compose( + add5, + multiply +); +multiplyAndAdd5(5, 2); // 15 +```

    [⬆ Back to top](#contents) -### composeRight - -Performs left-to-right function composition. - -Use `Array.prototype.reduce()` to perform left-to-right function composition. -The first (leftmost) function can accept one or more arguments; the remaining functions must be unary. - +### composeRight + +Performs left-to-right function composition. + +Use `Array.prototype.reduce()` to perform left-to-right function composition. +The first (leftmost) function can accept one or more arguments; the remaining functions must be unary. + ```js const composeRight = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args))); ``` @@ -4695,19 +4694,19 @@ const add = (x, y) => x + y; const square = x => x * x; const addAndSquare = composeRight(add, square); addAndSquare(1, 2); // 9 -``` +```
    [⬆ Back to top](#contents) -### converge - -Accepts a converging function and a list of branching functions and returns a function that applies each branching function to the arguments and the results of the branching functions are passed as arguments to the converging function. - -Use `Array.prototype.map()` and `Function.prototype.apply()` to apply each function to the given arguments. -Use the spread operator (`...`) to call `coverger` with the results of all other functions. - +### converge + +Accepts a converging function and a list of branching functions and returns a function that applies each branching function to the arguments and the results of the branching functions are passed as arguments to the converging function. + +Use `Array.prototype.map()` and `Function.prototype.apply()` to apply each function to the given arguments. +Use the spread operator (`...`) to call `coverger` with the results of all other functions. + ```js const converge = (converger, fns) => (...args) => converger(...fns.map(fn => fn.apply(null, args))); ``` @@ -4721,21 +4720,21 @@ const average = converge((a, b) => a / b, [ arr => arr.length ]); average([1, 2, 3, 4, 5, 6, 7]); // 4 -``` +```
    [⬆ Back to top](#contents) -### curry - -Curries a function. - -Use recursion. -If the number of provided arguments (`args`) is sufficient, call the passed function `fn`. -Otherwise, return a curried function `fn` that expects the rest of the arguments. -If you want to curry a function that accepts a variable number of arguments (a variadic function, e.g. `Math.min()`), you can optionally pass the number of arguments to the second parameter `arity`. - +### curry + +Curries a function. + +Use recursion. +If the number of provided arguments (`args`) is sufficient, call the passed function `fn`. +Otherwise, return a curried function `fn` that expects the rest of the arguments. +If you want to curry a function that accepts a variable number of arguments (a variadic function, e.g. `Math.min()`), you can optionally pass the number of arguments to the second parameter `arity`. + ```js const curry = (fn, arity = fn.length, ...args) => arity <= args.length ? fn(...args) : curry.bind(null, fn, arity, ...args); @@ -4747,19 +4746,19 @@ const curry = (fn, arity = fn.length, ...args) => ```js curry(Math.pow)(2)(10); // 1024 curry(Math.min, 3)(10)(50)(2); // 2 -``` +```
    [⬆ Back to top](#contents) -### debounce - -Creates a debounced function that delays invoking the provided function until at least `ms` milliseconds have elapsed since the last time it was invoked. - -Each time the debounced function is invoked, clear the current pending timeout with `clearTimeout()` and use `setTimeout()` to create a new timeout that delays invoking the function until at least `ms` milliseconds has elapsed. Use `Function.prototype.apply()` to apply the `this` context to the function and provide the necessary arguments. -Omit the second argument, `ms`, to set the timeout at a default of 0 ms. - +### debounce + +Creates a debounced function that delays invoking the provided function until at least `ms` milliseconds have elapsed since the last time it was invoked. + +Each time the debounced function is invoked, clear the current pending timeout with `clearTimeout()` and use `setTimeout()` to create a new timeout that delays invoking the function until at least `ms` milliseconds has elapsed. Use `Function.prototype.apply()` to apply the `this` context to the function and provide the necessary arguments. +Omit the second argument, `ms`, to set the timeout at a default of 0 ms. + ```js const debounce = (fn, ms = 0) => { let timeoutId; @@ -4781,46 +4780,46 @@ window.addEventListener( console.log(window.innerHeight); }, 250) ); // Will log the window dimensions at most every 250ms -``` +```
    [⬆ Back to top](#contents) -### defer - -Defers invoking a function until the current call stack has cleared. - -Use `setTimeout()` with a timeout of 1ms to add a new event to the browser event queue and allow the rendering engine to complete its work. Use the spread (`...`) operator to supply the function with an arbitrary number of arguments. - +### defer + +Defers invoking a function until the current call stack has cleared. + +Use `setTimeout()` with a timeout of 1ms to add a new event to the browser event queue and allow the rendering engine to complete its work. Use the spread (`...`) operator to supply the function with an arbitrary number of arguments. + ```js -const defer = (fn, ...args) => setTimeout(fn, 1, ...args); +const defer = (fn, ...args) => setTimeout(fn, 1, ...args); ```
    Examples ```js -// Example A: -defer(console.log, 'a'), console.log('b'); // logs 'b' then 'a' - -// Example B: -document.querySelector('#someElement').innerHTML = 'Hello'; -longRunningFunction(); // Browser will not update the HTML until this has finished -defer(longRunningFunction); // Browser will update the HTML then run the function -``` +// Example A: +defer(console.log, 'a'), console.log('b'); // logs 'b' then 'a' + +// Example B: +document.querySelector('#someElement').innerHTML = 'Hello'; +longRunningFunction(); // Browser will not update the HTML until this has finished +defer(longRunningFunction); // Browser will update the HTML then run the function +```

    [⬆ Back to top](#contents) -### delay - -Invokes the provided function after `wait` milliseconds. - -Use `setTimeout()` to delay execution of `fn`. -Use the spread (`...`) operator to supply the function with an arbitrary number of arguments. - +### delay + +Invokes the provided function after `wait` milliseconds. + +Use `setTimeout()` to delay execution of `fn`. +Use the spread (`...`) operator to supply the function with an arbitrary number of arguments. + ```js const delay = (fn, wait, ...args) => setTimeout(fn, wait, ...args); ``` @@ -4836,18 +4835,18 @@ delay( 1000, 'later' ); // Logs 'later' after one second. -``` +```
    [⬆ Back to top](#contents) -### functionName - -Logs the name of a function. - -Use `console.debug()` and the `name` property of the passed method to log the method's name to the `debug` channel of the console. - +### functionName + +Logs the name of a function. + +Use `console.debug()` and the `name` property of the passed method to log the method's name to the `debug` channel of the console. + ```js const functionName = fn => (console.debug(fn.name), fn); ``` @@ -4857,50 +4856,50 @@ const functionName = fn => (console.debug(fn.name), fn); ```js functionName(Math.max); // max (logged in debug channel of console) -``` +```
    [⬆ Back to top](#contents) -### hz - -Returns the number of times a function executed per second. -`hz` is the unit for `hertz`, the unit of frequency defined as one cycle per second. - -Use `performance.now()` to get the difference in milliseconds before and after the iteration loop to calculate the time elapsed executing the function `iterations` times. -Return the number of cycles per second by converting milliseconds to seconds and dividing it by the time elapsed. -Omit the second argument, `iterations`, to use the default of 100 iterations. - +### hz + +Returns the number of times a function executed per second. +`hz` is the unit for `hertz`, the unit of frequency defined as one cycle per second. + +Use `performance.now()` to get the difference in milliseconds before and after the iteration loop to calculate the time elapsed executing the function `iterations` times. +Return the number of cycles per second by converting milliseconds to seconds and dividing it by the time elapsed. +Omit the second argument, `iterations`, to use the default of 100 iterations. + ```js -const hz = (fn, iterations = 100) => { - const before = performance.now(); - for (let i = 0; i < iterations; i++) fn(); - return (1000 * iterations) / (performance.now() - before); -}; +const hz = (fn, iterations = 100) => { + const before = performance.now(); + for (let i = 0; i < iterations; i++) fn(); + return (1000 * iterations) / (performance.now() - before); +}; ```
    Examples ```js -// 10,000 element array -const numbers = Array(10000) - .fill() - .map((_, i) => i); - -// Test functions with the same goal: sum up the elements in the array -const sumReduce = () => numbers.reduce((acc, n) => acc + n, 0); -const sumForLoop = () => { - let sum = 0; - for (let i = 0; i < numbers.length; i++) sum += numbers[i]; - return sum; -}; - -// `sumForLoop` is nearly 10 times faster -Math.round(hz(sumReduce)); // 572 -Math.round(hz(sumForLoop)); // 4784 -``` +// 10,000 element array +const numbers = Array(10000) + .fill() + .map((_, i) => i); + +// Test functions with the same goal: sum up the elements in the array +const sumReduce = () => numbers.reduce((acc, n) => acc + n, 0); +const sumForLoop = () => { + let sum = 0; + for (let i = 0; i < numbers.length; i++) sum += numbers[i]; + return sum; +}; + +// `sumForLoop` is nearly 10 times faster +Math.round(hz(sumReduce)); // 572 +Math.round(hz(sumForLoop)); // 4784 +```
    @@ -4940,12 +4939,12 @@ console.log(anagramsCached.cache); // The cached anagrams map
    [⬆ Back to top](#contents) -### negate - -Negates a predicate function. - -Take a predicate function and apply the not operator (`!`) to it with its arguments. - +### negate + +Negates a predicate function. + +Take a predicate function and apply the not operator (`!`) to it with its arguments. + ```js const negate = func => (...args) => !func(...args); ``` @@ -4955,19 +4954,19 @@ const negate = func => (...args) => !func(...args); ```js [1, 2, 3, 4, 5, 6].filter(negate(n => n % 2 === 0)); // [ 1, 3, 5 ] -``` +```
    [⬆ Back to top](#contents) -### once - -Ensures a function is called only once. - -Utilizing a closure, use a flag, `called`, and set it to `true` once the function is called for the first time, preventing it from being called again. In order to allow the function to have its `this` context changed (such as in an event listener), the `function` keyword must be used, and the supplied function must have the context applied. -Allow the function to be supplied with an arbitrary number of arguments using the rest/spread (`...`) operator. - +### once + +Ensures a function is called only once. + +Utilizing a closure, use a flag, `called`, and set it to `true` once the function is called for the first time, preventing it from being called again. In order to allow the function to have its `this` context changed (such as in an event listener), the `function` keyword must be used, and the supplied function must have the context applied. +Allow the function to be supplied with an arbitrary number of arguments using the rest/spread (`...`) operator. + ```js const once = fn => { let called = false; @@ -4987,18 +4986,18 @@ const startApp = function(event) { console.log(this, event); // document.body, MouseEvent }; document.body.addEventListener('click', once(startApp)); // only runs `startApp` once upon click -``` +```
    [⬆ Back to top](#contents) -### partial - -Creates a function that invokes `fn` with `partials` prepended to the arguments it receives. - -Use the spread operator (`...`) to prepend `partials` to the list of arguments of `fn`. - +### partial + +Creates a function that invokes `fn` with `partials` prepended to the arguments it receives. + +Use the spread operator (`...`) to prepend `partials` to the list of arguments of `fn`. + ```js const partial = (fn, ...partials) => (...args) => fn(...partials, ...args); ``` @@ -5010,18 +5009,18 @@ const partial = (fn, ...partials) => (...args) => fn(...partials, ...args); const greet = (greeting, name) => greeting + ' ' + name + '!'; const greetHello = partial(greet, 'Hello'); greetHello('John'); // 'Hello John!' -``` +```
    [⬆ Back to top](#contents) -### partialRight - -Creates a function that invokes `fn` with `partials` appended to the arguments it receives. - -Use the spread operator (`...`) to append `partials` to the list of arguments of `fn`. - +### partialRight + +Creates a function that invokes `fn` with `partials` appended to the arguments it receives. + +Use the spread operator (`...`) to append `partials` to the list of arguments of `fn`. + ```js const partialRight = (fn, ...partials) => (...args) => fn(...args, ...partials); ``` @@ -5033,18 +5032,18 @@ const partialRight = (fn, ...partials) => (...args) => fn(...args, ...partials); const greet = (greeting, name) => greeting + ' ' + name + '!'; const greetJohn = partialRight(greet, 'John'); greetJohn('Hello'); // 'Hello John!' -``` +```
    [⬆ Back to top](#contents) -### runPromisesInSeries - -Runs an array of promises in series. - -Use `Array.prototype.reduce()` to create a promise chain, where each promise returns the next promise when resolved. - +### runPromisesInSeries + +Runs an array of promises in series. + +Use `Array.prototype.reduce()` to create a promise chain, where each promise returns the next promise when resolved. + ```js const runPromisesInSeries = ps => ps.reduce((p, next) => p.then(next), Promise.resolve()); ``` @@ -5055,18 +5054,18 @@ const runPromisesInSeries = ps => ps.reduce((p, next) => p.then(next), Promise.r ```js const delay = d => new Promise(r => setTimeout(r, d)); runPromisesInSeries([() => delay(1000), () => delay(2000)]); // Executes each promise sequentially, taking a total of 3 seconds to complete -``` +```
    [⬆ Back to top](#contents) -### sleep - -Delays the execution of an asynchronous function. - -Delay executing part of an `async` function, by putting it to sleep, returning a `Promise`. - +### sleep + +Delays the execution of an asynchronous function. + +Delay executing part of an `async` function, by putting it to sleep, returning a `Promise`. + ```js const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); ``` @@ -5080,7 +5079,7 @@ async function sleepyWork() { await sleep(1000); console.log('I woke up after 1 second.'); } -``` +``` @@ -5135,13 +5134,13 @@ window.addEventListener(
    [⬆ Back to top](#contents) -### times - -Iterates over a callback `n` times - -Use `Function.call()` to call `fn` `n` times or until it returns `false`. -Omit the last argument, `context`, to use an `undefined` object (or the global object in non-strict mode). - +### times + +Iterates over a callback `n` times + +Use `Function.call()` to call `fn` `n` times or until it returns `false`. +Omit the last argument, `context`, to use an `undefined` object (or the global object in non-strict mode). + ```js const times = (n, fn, context = undefined) => { let i = 0; @@ -5156,22 +5155,22 @@ const times = (n, fn, context = undefined) => { var output = ''; times(5, i => (output += i)); console.log(output); // 01234 -``` +```
    [⬆ Back to top](#contents) -### uncurry - -Uncurries a function up to depth `n`. - -Return a variadic function. -Use `Array.prototype.reduce()` on the provided arguments to call each subsequent curry level of the function. -If the `length` of the provided arguments is less than `n` throw an error. -Otherwise, call `fn` with the proper amount of arguments, using `Array.prototype.slice(0, n)`. -Omit the second argument, `n`, to uncurry up to depth `1`. - +### uncurry + +Uncurries a function up to depth `n`. + +Return a variadic function. +Use `Array.prototype.reduce()` on the provided arguments to call each subsequent curry level of the function. +If the `length` of the provided arguments is less than `n` throw an error. +Otherwise, call `fn` with the proper amount of arguments, using `Array.prototype.slice(0, n)`. +Omit the second argument, `n`, to uncurry up to depth `1`. + ```js const uncurry = (fn, n = 1) => (...args) => { const next = acc => args => args.reduce((x, y) => x(y), acc); @@ -5187,19 +5186,19 @@ const uncurry = (fn, n = 1) => (...args) => { const add = x => y => z => x + y + z; const uncurriedAdd = uncurry(add, 3); uncurriedAdd(1, 2, 3); // 6 -``` +```
    [⬆ Back to top](#contents) -### unfold - -Builds an array, using an iterator function and an initial seed value. - -Use a `while` loop and `Array.prototype.push()` to call the function repeatedly until it returns `false`. -The iterator function accepts one argument (`seed`) and must always return an array with two elements ([`value`, `nextSeed`]) or `false` to terminate. - +### unfold + +Builds an array, using an iterator function and an initial seed value. + +Use a `while` loop and `Array.prototype.push()` to call the function repeatedly until it returns `false`. +The iterator function accepts one argument (`seed`) and must always return an array with two elements ([`value`, `nextSeed`]) or `false` to terminate. + ```js const unfold = (fn, seed) => { let result = [], @@ -5215,18 +5214,18 @@ const unfold = (fn, seed) => { ```js var f = n => (n > 50 ? false : [-n, n + 10]); unfold(f, 10); // [-10, -20, -30, -40, -50] -``` +```
    [⬆ Back to top](#contents) -### when - -Tests a value, `x`, against a predicate function. If `true`, return `fn(x)`. Else, return `x`. - -Return a function expecting a single value, `x`, that returns the appropriate value based on `pred`. - +### when + +Tests a value, `x`, against a predicate function. If `true`, return `fn(x)`. Else, return `x`. + +Return a function expecting a single value, `x`, that returns the appropriate value based on `pred`. + ```js const when = (pred, whenTrue) => x => (pred(x) ? whenTrue(x) : x); ``` @@ -5238,7 +5237,7 @@ const when = (pred, whenTrue) => x => (pred(x) ? whenTrue(x) : x); const doubleEvenNumbers = when(x => x % 2 === 0, x => x * 2); doubleEvenNumbers(2); // 4 doubleEvenNumbers(1); // 1 -``` +``` @@ -5249,13 +5248,13 @@ doubleEvenNumbers(1); // 1 ## ➗ Math -### approximatelyEqual - -Checks if two numbers are approximately equal to each other. - -Use `Math.abs()` to compare the absolute difference of the two values to `epsilon`. -Omit the third parameter, `epsilon`, to use a default value of `0.001`. - +### approximatelyEqual + +Checks if two numbers are approximately equal to each other. + +Use `Math.abs()` to compare the absolute difference of the two values to `epsilon`. +Omit the third parameter, `epsilon`, to use a default value of `0.001`. + ```js const approximatelyEqual = (v1, v2, epsilon = 0.001) => Math.abs(v1 - v2) < epsilon; ``` @@ -5265,18 +5264,18 @@ const approximatelyEqual = (v1, v2, epsilon = 0.001) => Math.abs(v1 - v2) < epsi ```js approximatelyEqual(Math.PI / 2.0, 1.5708); // true -``` +```
    [⬆ Back to top](#contents) -### average - -Returns the average of two or more numbers. - -Use `Array.prototype.reduce()` to add each value to an accumulator, initialized with a value of `0`, divide by the `length` of the array. - +### average + +Returns the average of two or more numbers. + +Use `Array.prototype.reduce()` to add each value to an accumulator, initialized with a value of `0`, divide by the `length` of the array. + ```js const average = (...nums) => nums.reduce((acc, val) => acc + val, 0) / nums.length; ``` @@ -5287,18 +5286,18 @@ const average = (...nums) => nums.reduce((acc, val) => acc + val, 0) / nums.leng ```js average(...[1, 2, 3]); // 2 average(1, 2, 3); // 2 -``` +```
    [⬆ Back to top](#contents) -### averageBy - -Returns the average of an array, after mapping each element to a value using the provided function. - -Use `Array.prototype.map()` to map each element to the value returned by `fn`, `Array.prototype.reduce()` to add each value to an accumulator, initialized with a value of `0`, divide by the `length` of the array. - +### averageBy + +Returns the average of an array, after mapping each element to a value using the provided function. + +Use `Array.prototype.map()` to map each element to the value returned by `fn`, `Array.prototype.reduce()` to add each value to an accumulator, initialized with a value of `0`, divide by the `length` of the array. + ```js const averageBy = (arr, fn) => arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0) / @@ -5311,22 +5310,22 @@ const averageBy = (arr, fn) => ```js averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n); // 5 averageBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n'); // 5 -``` +```
    [⬆ Back to top](#contents) -### binomialCoefficient - -Evaluates the binomial coefficient of two integers `n` and `k`. - -Use `Number.isNaN()` to check if any of the two values is `NaN`. -Check if `k` is less than `0`, greater than or equal to `n`, equal to `1` or `n - 1` and return the appropriate result. -Check if `n - k` is less than `k` and switch their values accordingly. -Loop from `2` through `k` and calculate the binomial coefficient. -Use `Math.round()` to account for rounding errors in the calculation. - +### binomialCoefficient + +Evaluates the binomial coefficient of two integers `n` and `k`. + +Use `Number.isNaN()` to check if any of the two values is `NaN`. +Check if `k` is less than `0`, greater than or equal to `n`, equal to `1` or `n - 1` and return the appropriate result. +Check if `n - k` is less than `k` and switch their values accordingly. +Loop from `2` through `k` and calculate the binomial coefficient. +Use `Math.round()` to account for rounding errors in the calculation. + ```js const binomialCoefficient = (n, k) => { if (Number.isNaN(n) || Number.isNaN(k)) return NaN; @@ -5345,19 +5344,19 @@ const binomialCoefficient = (n, k) => { ```js binomialCoefficient(8, 2); // 28 -``` +```
    [⬆ Back to top](#contents) -### clampNumber - -Clamps `num` within the inclusive range specified by the boundary values `a` and `b`. - -If `num` falls within the range, return `num`. -Otherwise, return the nearest number in the range. - +### clampNumber + +Clamps `num` within the inclusive range specified by the boundary values `a` and `b`. + +If `num` falls within the range, return `num`. +Otherwise, return the nearest number in the range. + ```js const clampNumber = (num, a, b) => Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b)); ``` @@ -5368,40 +5367,40 @@ const clampNumber = (num, a, b) => Math.max(Math.min(num, Math.max(a, b)), Math. ```js clampNumber(2, 3, 5); // 3 clampNumber(1, -1, -5); // -1 -``` +```
    [⬆ Back to top](#contents) -### degreesToRads - -Converts an angle from degrees to radians. - -Use `Math.PI` and the degree to radian formula to convert the angle from degrees to radians. - +### degreesToRads + +Converts an angle from degrees to radians. + +Use `Math.PI` and the degree to radian formula to convert the angle from degrees to radians. + ```js -const degreesToRads = deg => (deg * Math.PI) / 180.0; +const degreesToRads = deg => (deg * Math.PI) / 180.0; ```
    Examples ```js -degreesToRads(90.0); // ~1.5708 -``` +degreesToRads(90.0); // ~1.5708 +```

    [⬆ Back to top](#contents) -### digitize - -Converts a number to an array of digits. - -Convert the number to a string, using the spread operator (`...`) to build an array. -Use `Array.prototype.map()` and `parseInt()` to transform each value to an integer. - +### digitize + +Converts a number to an array of digits. + +Convert the number to a string, using the spread operator (`...`) to build an array. +Use `Array.prototype.map()` and `parseInt()` to transform each value to an integer. + ```js const digitize = n => [...`${n}`].map(i => parseInt(i)); ``` @@ -5411,18 +5410,18 @@ const digitize = n => [...`${n}`].map(i => parseInt(i)); ```js digitize(123); // [1, 2, 3] -``` +```
    [⬆ Back to top](#contents) -### distance - -Returns the distance between two points. - -Use `Math.hypot()` to calculate the Euclidean distance between two points. - +### distance + +Returns the distance between two points. + +Use `Math.hypot()` to calculate the Euclidean distance between two points. + ```js const distance = (x0, y0, x1, y1) => Math.hypot(x1 - x0, y1 - y0); ``` @@ -5432,7 +5431,7 @@ const distance = (x0, y0, x1, y1) => Math.hypot(x1 - x0, y1 - y0); ```js distance(1, 1, 2, 3); // 2.23606797749979 -``` +``` @@ -5488,44 +5487,44 @@ own individual rating by supplying it as the third argument.
    [⬆ Back to top](#contents) -### factorial - -Calculates the factorial of a number. - -Use recursion. -If `n` is less than or equal to `1`, return `1`. -Otherwise, return the product of `n` and the factorial of `n - 1`. -Throws an exception if `n` is a negative number. - +### factorial + +Calculates the factorial of a number. + +Use recursion. +If `n` is less than or equal to `1`, return `1`. +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 - ? (() => { - throw new TypeError('Negative numbers are not allowed!'); - })() - : n <= 1 - ? 1 - : n * factorial(n - 1); +const factorial = n => + n < 0 + ? (() => { + throw new TypeError('Negative numbers are not allowed!'); + })() + : n <= 1 + ? 1 + : n * factorial(n - 1); ```
    Examples ```js -factorial(6); // 720 -``` +factorial(6); // 720 +```

    [⬆ Back to top](#contents) -### fibonacci - -Generates an array, containing the Fibonacci sequence, up until the nth term. - -Create an empty array of the specific length, initializing the first two values (`0` and `1`). -Use `Array.prototype.reduce()` to add values into the array, using the sum of the last two values, except for the first two. - +### fibonacci + +Generates an array, containing the Fibonacci sequence, up until the nth term. + +Create an empty array of the specific length, initializing the first two values (`0` and `1`). +Use `Array.prototype.reduce()` to add values into the array, using the sum of the last two values, except for the first two. + ```js const fibonacci = n => Array.from({ length: n }).reduce( @@ -5539,20 +5538,20 @@ const fibonacci = n => ```js fibonacci(6); // [0, 1, 1, 2, 3, 5] -``` +```
    [⬆ Back to top](#contents) -### gcd - -Calculates the greatest common divisor between two or more numbers/arrays. - -The inner `_gcd` function uses recursion. -Base case is when `y` equals `0`. In this case, return `x`. -Otherwise, return the GCD of `y` and the remainder of the division `x/y`. - +### gcd + +Calculates the greatest common divisor between two or more numbers/arrays. + +The inner `_gcd` function uses recursion. +Base case is when `y` equals `0`. In this case, return `x`. +Otherwise, return the GCD of `y` and the remainder of the division `x/y`. + ```js const gcd = (...arr) => { const _gcd = (x, y) => (!y ? x : gcd(y, x % y)); @@ -5566,21 +5565,21 @@ const gcd = (...arr) => { ```js gcd(8, 36); // 4 gcd(...[12, 8, 32]); // 4 -``` +```
    [⬆ Back to top](#contents) -### geometricProgression - -Initializes an array containing the numbers in the specified range where `start` and `end` are inclusive and the ratio between two terms is `step`. -Returns an error if `step` equals `1`. - -Use `Array.from()`, `Math.log()` and `Math.floor()` to create an array of the desired length, `Array.prototype.map()` to fill with the desired values in a range. -Omit the second argument, `start`, to use a default value of `1`. -Omit the third argument, `step`, to use a default value of `2`. - +### geometricProgression + +Initializes an array containing the numbers in the specified range where `start` and `end` are inclusive and the ratio between two terms is `step`. +Returns an error if `step` equals `1`. + +Use `Array.from()`, `Math.log()` and `Math.floor()` to create an array of the desired length, `Array.prototype.map()` to fill with the desired values in a range. +Omit the second argument, `start`, to use a default value of `1`. +Omit the third argument, `step`, to use a default value of `2`. + ```js const geometricProgression = (end, start = 1, step = 2) => Array.from({ length: Math.floor(Math.log(end / start) / Math.log(step)) + 1 }).map( @@ -5595,19 +5594,19 @@ const geometricProgression = (end, start = 1, step = 2) => geometricProgression(256); // [1, 2, 4, 8, 16, 32, 64, 128, 256] geometricProgression(256, 3); // [3, 6, 12, 24, 48, 96, 192] geometricProgression(256, 1, 4); // [1, 4, 16, 64, 256] -``` +```
    [⬆ Back to top](#contents) -### hammingDistance - -Calculates the Hamming distance between two values. - -Use XOR operator (`^`) to find the bit difference between the two numbers, convert to a binary string using `toString(2)`. -Count and return the number of `1`s in the string, using `match(/1/g)`. - +### hammingDistance + +Calculates the Hamming distance between two values. + +Use XOR operator (`^`) to find the bit difference between the two numbers, convert to a binary string using `toString(2)`. +Count and return the number of `1`s in the string, using `match(/1/g)`. + ```js const hammingDistance = (num1, num2) => ((num1 ^ num2).toString(2).match(/1/g) || '').length; ``` @@ -5617,19 +5616,19 @@ const hammingDistance = (num1, num2) => ((num1 ^ num2).toString(2).match(/1/g) | ```js hammingDistance(2, 3); // 1 -``` +```
    [⬆ Back to top](#contents) -### inRange - -Checks if the given number falls within the given range. - -Use arithmetic comparison to check if the given number is in the specified range. -If the second parameter, `end`, is not specified, the range is considered to be from `0` to `start`. - +### inRange + +Checks if the given number falls within the given range. + +Use arithmetic comparison to check if the given number is in the specified range. +If the second parameter, `end`, is not specified, the range is considered to be from `0` to `start`. + ```js const inRange = (n, start, end = null) => { if (end && start > end) [end, start] = [start, end]; @@ -5645,18 +5644,18 @@ inRange(3, 2, 5); // true inRange(3, 4); // true inRange(2, 3, 5); // false inRange(3, 2); // false -``` +```
    [⬆ Back to top](#contents) -### isDivisible - -Checks if the first numeric argument is divisible by the second one. - -Use the modulo operator (`%`) to check if the remainder is equal to `0`. - +### isDivisible + +Checks if the first numeric argument is divisible by the second one. + +Use the modulo operator (`%`) to check if the remainder is equal to `0`. + ```js const isDivisible = (dividend, divisor) => dividend % divisor === 0; ``` @@ -5666,19 +5665,19 @@ const isDivisible = (dividend, divisor) => dividend % divisor === 0; ```js isDivisible(6, 3); // true -``` +```
    [⬆ Back to top](#contents) -### isEven - -Returns `true` if the given number is even, `false` otherwise. - -Checks whether a number is odd or even using the modulo (`%`) operator. -Returns `true` if the number is even, `false` if the number is odd. - +### isEven + +Returns `true` if the given number is even, `false` otherwise. + +Checks whether a number is odd or even using the modulo (`%`) operator. +Returns `true` if the number is even, `false` if the number is odd. + ```js const isEven = num => num % 2 === 0; ``` @@ -5688,41 +5687,41 @@ const isEven = num => num % 2 === 0; ```js isEven(3); // false -``` +```
    [⬆ Back to top](#contents) -### isNegativeZero - -Checks if the given value is equal to negative zero (`-0`). - -Checks whether a passed value is equal to `0` and if `1` divided by the value equals `-Infinity`. - +### isNegativeZero + +Checks if the given value is equal to negative zero (`-0`). + +Checks whether a passed value is equal to `0` and if `1` divided by the value equals `-Infinity`. + ```js -const isNegativeZero = val => val === 0 && 1 / val === -Infinity; +const isNegativeZero = val => val === 0 && 1 / val === -Infinity; ```
    Examples ```js -isNegativeZero(-0); // true -isNegativeZero(0); // false -``` +isNegativeZero(-0); // true +isNegativeZero(0); // false +```

    [⬆ Back to top](#contents) -### isPrime - -Checks if the provided integer is a prime number. - -Check numbers from `2` to the square root of the given number. -Return `false` if any of them divides the given number, else return `true`, unless the number is less than `2`. - +### isPrime + +Checks if the provided integer is a prime number. + +Check numbers from `2` to the square root of the given number. +Return `false` if any of them divides the given number, else return `true`, unless the number is less than `2`. + ```js const isPrime = num => { const boundary = Math.floor(Math.sqrt(num)); @@ -5736,34 +5735,34 @@ const isPrime = num => { ```js isPrime(11); // true -``` +```
    [⬆ Back to top](#contents) -### lcm - -Returns the least common multiple of two or more numbers. - -Use the greatest common divisor (GCD) formula and the fact that `lcm(x,y) = x * y / gcd(x,y)` to determine the least common multiple. -The GCD formula uses recursion. - +### lcm + +Returns the least common multiple of two or more numbers. + +Use the greatest common divisor (GCD) formula and the fact that `lcm(x,y) = x * y / gcd(x,y)` to determine the least common multiple. +The GCD formula uses recursion. + ```js -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 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)); +}; ```
    Examples ```js -lcm(12, 7); // 84 -lcm(...[1, 3, 4, 5]); // 60 -``` +lcm(12, 7); // 84 +lcm(...[1, 3, 4, 5]); // 60 +```
    @@ -5805,12 +5804,12 @@ luhnCheck(123456789); // false
    [⬆ Back to top](#contents) -### maxBy - -Returns the maximum value of an array, after mapping each element to a value using the provided function. - -Use `Array.prototype.map()` to map each element to the value returned by `fn`, `Math.max()` to get the maximum value. - +### maxBy + +Returns the maximum value of an array, after mapping each element to a value using the provided function. + +Use `Array.prototype.map()` to map each element to the value returned by `fn`, `Math.max()` to get the maximum value. + ```js const maxBy = (arr, fn) => Math.max(...arr.map(typeof fn === 'function' ? fn : val => val[fn])); ``` @@ -5821,19 +5820,19 @@ const maxBy = (arr, fn) => Math.max(...arr.map(typeof fn === 'function' ? fn : v ```js maxBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n); // 8 maxBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n'); // 8 -``` +```
    [⬆ Back to top](#contents) -### median - -Returns the median of an array of numbers. - -Find the middle of the array, use `Array.prototype.sort()` to sort the values. -Return the number at the midpoint if `length` is odd, otherwise the average of the two middle numbers. - +### median + +Returns the median of an array of numbers. + +Find the middle of the array, use `Array.prototype.sort()` to sort the values. +Return the number at the midpoint if `length` is odd, otherwise the average of the two middle numbers. + ```js const median = arr => { const mid = Math.floor(arr.length / 2), @@ -5847,42 +5846,42 @@ const median = arr => { ```js median([5, 6, 50, 1, -5]); // 5 -``` +```
    [⬆ Back to top](#contents) -### midpoint - -Calculates the midpoint between two pairs of (x,y) points. - -Destructure the array to get `x1`, `y1`, `x2` and `y2`, calculate the midpoint for each dimension by dividing the sum of the two endpoints by `2`. - +### midpoint + +Calculates the midpoint between two pairs of (x,y) points. + +Destructure the array to get `x1`, `y1`, `x2` and `y2`, calculate the midpoint for each dimension by dividing the sum of the two endpoints by `2`. + ```js -const midpoint = ([x1, y1], [x2, y2]) => [(x1 + x2) / 2, (y1 + y2) / 2]; +const midpoint = ([x1, y1], [x2, y2]) => [(x1 + x2) / 2, (y1 + y2) / 2]; ```
    Examples ```js -midpoint([2, 2], [4, 4]); // [3, 3] -midpoint([4, 4], [6, 6]); // [5, 5] -midpoint([1, 3], [2, 4]); // [1.5, 3.5] -``` - +midpoint([2, 2], [4, 4]); // [3, 3] +midpoint([4, 4], [6, 6]); // [5, 5] +midpoint([1, 3], [2, 4]); // [1.5, 3.5] +``` +

    [⬆ Back to top](#contents) -### minBy - -Returns the minimum value of an array, after mapping each element to a value using the provided function. - -Use `Array.prototype.map()` to map each element to the value returned by `fn`, `Math.min()` to get the maximum value. - +### minBy + +Returns the minimum value of an array, after mapping each element to a value using the provided function. + +Use `Array.prototype.map()` to map each element to the value returned by `fn`, `Math.min()` to get the maximum value. + ```js const minBy = (arr, fn) => Math.min(...arr.map(typeof fn === 'function' ? fn : val => val[fn])); ``` @@ -5893,40 +5892,40 @@ const minBy = (arr, fn) => Math.min(...arr.map(typeof fn === 'function' ? fn : v ```js minBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n); // 2 minBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n'); // 2 -``` +```
    [⬆ Back to top](#contents) -### percentile - -Uses the percentile formula to calculate how many numbers in the given array are less or equal to the given value. - -Use `Array.prototype.reduce()` to calculate how many numbers are below the value and how many are the same value and apply the percentile formula. - +### percentile + +Uses the percentile formula to calculate how many numbers in the given array are less or equal to the given value. + +Use `Array.prototype.reduce()` to calculate how many numbers are below the value and how many are the same value and apply the percentile formula. + ```js -const percentile = (arr, val) => - (100 * arr.reduce((acc, v) => acc + (v < val ? 1 : 0) + (v === val ? 0.5 : 0), 0)) / arr.length; +const percentile = (arr, val) => + (100 * arr.reduce((acc, v) => acc + (v < val ? 1 : 0) + (v === val ? 0.5 : 0), 0)) / arr.length; ```
    Examples ```js -percentile([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 6); // 55 -``` +percentile([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 6); // 55 +```

    [⬆ Back to top](#contents) -### powerset - -Returns the powerset of a given array of numbers. - -Use `Array.prototype.reduce()` combined with `Array.prototype.map()` to iterate over elements and combine into an array containing all combinations. - +### powerset + +Returns the powerset of a given array of numbers. + +Use `Array.prototype.reduce()` combined with `Array.prototype.map()` to iterate over elements and combine into an array containing all combinations. + ```js const powerset = arr => arr.reduce((a, v) => a.concat(a.map(r => [v].concat(r))), [[]]); ``` @@ -5936,18 +5935,18 @@ const powerset = arr => arr.reduce((a, v) => a.concat(a.map(r => [v].concat(r))) ```js powerset([1, 2]); // [[], [1], [2], [2, 1]] -``` +```
    [⬆ Back to top](#contents) -### primes - -Generates primes up to a given number, using the Sieve of Eratosthenes. - -Generate an array from `2` to the given number. Use `Array.prototype.filter()` to filter out the values divisible by any number from `2` to the square root of the provided number. - +### primes + +Generates primes up to a given number, using the Sieve of Eratosthenes. + +Generate an array from `2` to the given number. Use `Array.prototype.filter()` to filter out the values divisible by any number from `2` to the square root of the provided number. + ```js const primes = num => { let arr = Array.from({ length: num - 1 }).map((x, i) => i + 2), @@ -5963,39 +5962,39 @@ const primes = num => { ```js primes(10); // [2,3,5,7] -``` +```
    [⬆ Back to top](#contents) -### radsToDegrees - -Converts an angle from radians to degrees. - -Use `Math.PI` and the radian to degree formula to convert the angle from radians to degrees. - +### radsToDegrees + +Converts an angle from radians to degrees. + +Use `Math.PI` and the radian to degree formula to convert the angle from radians to degrees. + ```js -const radsToDegrees = rad => (rad * 180.0) / Math.PI; +const radsToDegrees = rad => (rad * 180.0) / Math.PI; ```
    Examples ```js -radsToDegrees(Math.PI / 2); // 90 -``` +radsToDegrees(Math.PI / 2); // 90 +```

    [⬆ Back to top](#contents) -### randomIntArrayInRange - -Returns an array of n random integers in the specified range. - -Use `Array.from()` to create an empty array of the specific length, `Math.random()` to generate a random number and map it to the desired range, using `Math.floor()` to make it an integer. - +### randomIntArrayInRange + +Returns an array of n random integers in the specified range. + +Use `Array.from()` to create an empty array of the specific length, `Math.random()` to generate a random number and map it to the desired range, using `Math.floor()` to make it an integer. + ```js const randomIntArrayInRange = (min, max, n = 1) => Array.from({ length: n }, () => Math.floor(Math.random() * (max - min + 1)) + min); @@ -6006,18 +6005,18 @@ const randomIntArrayInRange = (min, max, n = 1) => ```js randomIntArrayInRange(12, 35, 10); // [ 34, 14, 27, 17, 30, 27, 20, 26, 21, 14 ] -``` +```
    [⬆ Back to top](#contents) -### randomIntegerInRange - -Returns a random integer in the specified range. - -Use `Math.random()` to generate a random number and map it to the desired range, using `Math.floor()` to make it an integer. - +### randomIntegerInRange + +Returns a random integer in the specified range. + +Use `Math.random()` to generate a random number and map it to the desired range, using `Math.floor()` to make it an integer. + ```js const randomIntegerInRange = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min; ``` @@ -6027,18 +6026,18 @@ const randomIntegerInRange = (min, max) => Math.floor(Math.random() * (max - min ```js randomIntegerInRange(0, 5); // 2 -``` +```
    [⬆ Back to top](#contents) -### randomNumberInRange - -Returns a random number in the specified range. - -Use `Math.random()` to generate a random value, map it to the desired range using multiplication. - +### randomNumberInRange + +Returns a random number in the specified range. + +Use `Math.random()` to generate a random value, map it to the desired range using multiplication. + ```js const randomNumberInRange = (min, max) => Math.random() * (max - min) + min; ``` @@ -6048,19 +6047,19 @@ const randomNumberInRange = (min, max) => Math.random() * (max - min) + min; ```js randomNumberInRange(2, 10); // 6.0211363285087005 -``` +```
    [⬆ Back to top](#contents) -### round - -Rounds a number to a specified amount of digits. - -Use `Math.round()` and template literals to round the number to the specified number of digits. -Omit the second argument, `decimals` to round to an integer. - +### round + +Rounds a number to a specified amount of digits. + +Use `Math.round()` and template literals to round the number to the specified number of digits. +Omit the second argument, `decimals` to round to an integer. + ```js const round = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${decimals}`); ``` @@ -6070,18 +6069,18 @@ const round = (n, decimals = 0) => Number(`${Math.round(`${n}e${decimals}`)}e-${ ```js round(1.005, 2); // 1.01 -``` +```
    [⬆ Back to top](#contents) -### sdbm - -Hashes the input string into a whole number. - -Use `String.prototype.split('')` and `Array.prototype.reduce()` to create a hash of the input string, utilizing bit shifting. - +### sdbm + +Hashes the input string into a whole number. + +Use `String.prototype.split('')` and `Array.prototype.reduce()` to create a hash of the input string, utilizing bit shifting. + ```js const sdbm = str => { let arr = str.split(''); @@ -6098,20 +6097,20 @@ const sdbm = str => { ```js sdbm('name'); // -3521204949 -``` +```
    [⬆ Back to top](#contents) -### standardDeviation - -Returns the standard deviation of an array of numbers. - -Use `Array.prototype.reduce()` to calculate the mean, variance and the sum of the variance of the values, the variance of the values, then -determine the standard deviation. -You can omit the second argument to get the sample standard deviation or set it to `true` to get the population standard deviation. - +### standardDeviation + +Returns the standard deviation of an array of numbers. + +Use `Array.prototype.reduce()` to calculate the mean, variance and the sum of the variance of the values, the variance of the values, then +determine the standard deviation. +You can omit the second argument to get the sample standard deviation or set it to `true` to get the population standard deviation. + ```js const standardDeviation = (arr, usePopulation = false) => { const mean = arr.reduce((acc, val) => acc + val, 0) / arr.length; @@ -6128,40 +6127,40 @@ const standardDeviation = (arr, usePopulation = false) => { ```js standardDeviation([10, 2, 38, 23, 38, 23, 21]); // 13.284434142114991 (sample) standardDeviation([10, 2, 38, 23, 38, 23, 21], true); // 12.29899614287479 (population) -``` +```
    [⬆ Back to top](#contents) -### sum - -Returns the sum of two or more numbers/arrays. - -Use `Array.prototype.reduce()` to add each value to an accumulator, initialized with a value of `0`. - +### sum + +Returns the sum of two or more numbers/arrays. + +Use `Array.prototype.reduce()` to add each value to an accumulator, initialized with a value of `0`. + ```js -const sum = (...arr) => [...arr].reduce((acc, val) => acc + val, 0); +const sum = (...arr) => [...arr].reduce((acc, val) => acc + val, 0); ```
    Examples ```js -sum(1, 2, 3, 4); // 10 -sum(...[1, 2, 3, 4]); // 10 -``` +sum(1, 2, 3, 4); // 10 +sum(...[1, 2, 3, 4]); // 10 +```

    [⬆ Back to top](#contents) -### sumBy - -Returns the sum of an array, after mapping each element to a value using the provided function. - -Use `Array.prototype.map()` to map each element to the value returned by `fn`, `Array.prototype.reduce()` to add each value to an accumulator, initialized with a value of `0`. - +### sumBy + +Returns the sum of an array, after mapping each element to a value using the provided function. + +Use `Array.prototype.map()` to map each element to the value returned by `fn`, `Array.prototype.reduce()` to add each value to an accumulator, initialized with a value of `0`. + ```js const sumBy = (arr, fn) => arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0); @@ -6173,48 +6172,48 @@ const sumBy = (arr, fn) => ```js sumBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], o => o.n); // 20 sumBy([{ n: 4 }, { n: 2 }, { n: 8 }, { n: 6 }], 'n'); // 20 -``` +```
    [⬆ Back to top](#contents) -### sumPower - -Returns the sum of the powers of all the numbers from `start` to `end` (both inclusive). - -Use `Array.prototype.fill()` to create an array of all the numbers in the target range, `Array.prototype.map()` and the exponent operator (`**`) to raise them to `power` and `Array.prototype.reduce()` to add them together. -Omit the second argument, `power`, to use a default power of `2`. -Omit the third argument, `start`, to use a default starting value of `1`. - +### sumPower + +Returns the sum of the powers of all the numbers from `start` to `end` (both inclusive). + +Use `Array.prototype.fill()` to create an array of all the numbers in the target range, `Array.prototype.map()` and the exponent operator (`**`) to raise them to `power` and `Array.prototype.reduce()` to add them together. +Omit the second argument, `power`, to use a default power of `2`. +Omit the third argument, `start`, to use a default starting value of `1`. + ```js -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 sumPower = (end, power = 2, start = 1) => + Array(end + 1 - start) + .fill(0) + .map((x, i) => (i + start) ** power) + .reduce((a, b) => a + b, 0); ```
    Examples ```js -sumPower(10); // 385 -sumPower(10, 3); // 3025 -sumPower(10, 3, 5); // 2925 -``` +sumPower(10); // 385 +sumPower(10, 3); // 3025 +sumPower(10, 3, 5); // 2925 +```

    [⬆ Back to top](#contents) -### toSafeInteger - -Converts a value to a safe integer. - -Use `Math.max()` and `Math.min()` to find the closest safe value. -Use `Math.round()` to convert to an integer. - +### toSafeInteger + +Converts a value to a safe integer. + +Use `Math.max()` and `Math.min()` to find the closest safe value. +Use `Math.round()` to convert to an integer. + ```js const toSafeInteger = num => Math.round(Math.max(Math.min(num, Number.MAX_SAFE_INTEGER), Number.MIN_SAFE_INTEGER)); @@ -6226,7 +6225,7 @@ const toSafeInteger = num => ```js toSafeInteger('3.2'); // 3 toSafeInteger(Infinity); // 9007199254740991 -``` +``` @@ -6237,55 +6236,55 @@ toSafeInteger(Infinity); // 9007199254740991 ## 📦 Node -### atob - -Decodes a string of data which has been encoded using base-64 encoding. - -Create a `Buffer` for the given string with base-64 encoding and use `Buffer.toString('binary')` to return the decoded string. - +### atob + +Decodes a string of data which has been encoded using base-64 encoding. + +Create a `Buffer` for the given string with base-64 encoding and use `Buffer.toString('binary')` to return the decoded string. + ```js -const atob = str => Buffer.from(str, 'base64').toString('binary'); +const atob = str => Buffer.from(str, 'base64').toString('binary'); ```
    Examples ```js -atob('Zm9vYmFy'); // 'foobar' -``` +atob('Zm9vYmFy'); // 'foobar' +```

    [⬆ Back to top](#contents) -### btoa - -Creates a base-64 encoded ASCII string from a String object in which each character in the string is treated as a byte of binary data. - -Create a `Buffer` for the given string with binary encoding and use `Buffer.toString('base64')` to return the encoded string. - +### btoa + +Creates a base-64 encoded ASCII string from a String object in which each character in the string is treated as a byte of binary data. + +Create a `Buffer` for the given string with binary encoding and use `Buffer.toString('base64')` to return the encoded string. + ```js -const btoa = str => Buffer.from(str, 'binary').toString('base64'); +const btoa = str => Buffer.from(str, 'binary').toString('base64'); ```
    Examples ```js -btoa('foobar'); // 'Zm9vYmFy' -``` +btoa('foobar'); // 'Zm9vYmFy' +```

    [⬆ Back to top](#contents) -### colorize - -Add special characters to text to print in color in the console (combined with `console.log()`). - -Use template literals and special characters to add the appropriate color code to the string output. -For background colors, add a special character that resets the background color at the end of the string. - +### colorize + +Add special characters to text to print in color in the console (combined with `console.log()`). + +Use template literals and special characters to add the appropriate color code to the string output. +For background colors, add a special character that resets the background color at the end of the string. + ```js const colorize = (...args) => ({ black: `\x1b[30m${args.join(' ')}`, @@ -6314,41 +6313,41 @@ const colorize = (...args) => ({ console.log(colorize('foo').red); // 'foo' (red letters) console.log(colorize('foo', 'bar').bgBlue); // 'foo bar' (blue background) console.log(colorize(colorize('foo').yellow, colorize('foo').green).bgWhite); // 'foo bar' (first word in yellow letters, second word in green letters, white background for both) -``` +```
    [⬆ Back to top](#contents) -### createDirIfNotExists - -Creates a directory, if it does not exist. - -Use `fs.existsSync()` to check if the directory exists, `fs.mkdirSync()` to create it. - +### createDirIfNotExists + +Creates a directory, if it does not exist. + +Use `fs.existsSync()` to check if the directory exists, `fs.mkdirSync()` to create it. + ```js -const fs = require('fs'); -const createDirIfNotExists = dir => (!fs.existsSync(dir) ? fs.mkdirSync(dir) : undefined); +const fs = require('fs'); +const createDirIfNotExists = dir => (!fs.existsSync(dir) ? fs.mkdirSync(dir) : undefined); ```
    Examples ```js -createDirIfNotExists('test'); // creates the directory 'test', if it doesn't exist -``` +createDirIfNotExists('test'); // creates the directory 'test', if it doesn't exist +```

    [⬆ Back to top](#contents) -### hasFlags - -Check if the current process's arguments contain the specified flags. - -Use `Array.prototype.every()` and `Array.prototype.includes()` to check if `process.argv` contains all the specified flags. -Use a regular expression to test if the specified flags are prefixed with `-` or `--` and prefix them accordingly. - +### hasFlags + +Check if the current process's arguments contain the specified flags. + +Use `Array.prototype.every()` and `Array.prototype.includes()` to check if `process.argv` contains all the specified flags. +Use a regular expression to test if the specified flags are prefixed with `-` or `--` and prefix them accordingly. + ```js const hasFlags = (...flags) => flags.every(flag => process.argv.includes(/^-{1,2}/.test(flag) ? flag : '--' + flag)); @@ -6362,18 +6361,18 @@ const hasFlags = (...flags) => hasFlags('-s'); // true hasFlags('--test', 'cool=true', '-s'); // true hasFlags('special'); // false -``` +```
    [⬆ Back to top](#contents) -### hashNode - -Creates a hash for a value using the [SHA-256](https://en.wikipedia.org/wiki/SHA-2) algorithm. Returns a promise. - -Use `crypto` API to create a hash for the given value. - +### hashNode + +Creates a hash for a value using the [SHA-256](https://en.wikipedia.org/wiki/SHA-2) algorithm. Returns a promise. + +Use `crypto` API to create a hash for the given value. + ```js const crypto = require('crypto'); const hashNode = val => @@ -6396,98 +6395,98 @@ const hashNode = val => ```js hashNode(JSON.stringify({ a: 'a', b: [1, 2, 3, 4], foo: { c: 'bar' } })).then(console.log); // '04aa106279f5977f59f9067fa9712afc4aedc6f5862a8defc34552d8c7206393' -``` +```
    [⬆ Back to top](#contents) -### isDuplexStream - -Checks if the given argument is a duplex (readable and writable) stream. - -Check if the value is different from `null`, use `typeof` to check if a value is of type `object` and the `pipe` property is of type `function`. -Additionally check if the `typeof` the `_read`, `_write` and `_readableState`, `_writableState` properties are `function` and `object` respectively. - +### isDuplexStream + +Checks if the given argument is a duplex (readable and writable) stream. + +Check if the value is different from `null`, use `typeof` to check if a value is of type `object` and the `pipe` property is of type `function`. +Additionally check if the `typeof` the `_read`, `_write` and `_readableState`, `_writableState` properties are `function` and `object` respectively. + ```js -const isDuplexStream = val => - val !== null && - typeof val === 'object' && - typeof val.pipe === 'function' && - typeof val._read === 'function' && - typeof val._readableState === 'object' && - typeof val._write === 'function' && - typeof val._writableState === 'object'; +const isDuplexStream = val => + val !== null && + typeof val === 'object' && + typeof val.pipe === 'function' && + typeof val._read === 'function' && + typeof val._readableState === 'object' && + typeof val._write === 'function' && + typeof val._writableState === 'object'; ```
    Examples ```js -const Stream = require('stream'); -isDuplexStream(new Stream.Duplex()); // true -``` +const Stream = require('stream'); +isDuplexStream(new Stream.Duplex()); // true +```

    [⬆ Back to top](#contents) -### isReadableStream - -Checks if the given argument is a readable stream. - -Check if the value is different from `null`, use `typeof` to check if the value is of type `object` and the `pipe` property is of type `function`. -Additionally check if the `typeof` the `_read` and `_readableState` properties are `function` and `object` respectively. - +### isReadableStream + +Checks if the given argument is a readable stream. + +Check if the value is different from `null`, use `typeof` to check if the value is of type `object` and the `pipe` property is of type `function`. +Additionally check if the `typeof` the `_read` and `_readableState` properties are `function` and `object` respectively. + ```js -const isReadableStream = val => - val !== null && - typeof val === 'object' && - typeof val.pipe === 'function' && - typeof val._read === 'function' && - typeof val._readableState === 'object'; +const isReadableStream = val => + val !== null && + typeof val === 'object' && + typeof val.pipe === 'function' && + typeof val._read === 'function' && + typeof val._readableState === 'object'; ```
    Examples ```js -const fs = require('fs'); -isReadableStream(fs.createReadStream('test.txt')); // true -``` +const fs = require('fs'); +isReadableStream(fs.createReadStream('test.txt')); // true +```

    [⬆ Back to top](#contents) -### isStream - -Checks if the given argument is a stream. - -Check if the value is different from `null`, use `typeof` to check if the value is of type `object` and the `pipe` property is of type `function`. - +### isStream + +Checks if the given argument is a stream. + +Check if the value is different from `null`, use `typeof` to check if the value is of type `object` and the `pipe` property is of type `function`. + ```js -const isStream = val => val !== null && typeof val === 'object' && typeof val.pipe === 'function'; +const isStream = val => val !== null && typeof val === 'object' && typeof val.pipe === 'function'; ```
    Examples ```js -const fs = require('fs'); -isStream(fs.createReadStream('test.txt')); // true -``` +const fs = require('fs'); +isStream(fs.createReadStream('test.txt')); // true +```

    [⬆ Back to top](#contents) -### isTravisCI - -Checks if the current environment is [Travis CI](https://travis-ci.org/). - -Checks if the current environment has the `TRAVIS` and `CI` environment variables ([reference](https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables)). - +### isTravisCI + +Checks if the current environment is [Travis CI](https://travis-ci.org/). + +Checks if the current environment has the `TRAVIS` and `CI` environment variables ([reference](https://docs.travis-ci.com/user/environment-variables/#Default-Environment-Variables)). + ```js const isTravisCI = () => 'TRAVIS' in process.env && 'CI' in process.env; ``` @@ -6497,46 +6496,46 @@ const isTravisCI = () => 'TRAVIS' in process.env && 'CI' in process.env; ```js isTravisCI(); // true (if code is running on Travis CI) -``` +```
    [⬆ Back to top](#contents) -### isWritableStream - -Checks if the given argument is a writable stream. - -Check if the value is different from `null`, use `typeof` to check if the value is of type `object` and the `pipe` property is of type `function`. -Additionally check if the `typeof` the `_write` and `_writableState` properties are `function` and `object` respectively. - +### isWritableStream + +Checks if the given argument is a writable stream. + +Check if the value is different from `null`, use `typeof` to check if the value is of type `object` and the `pipe` property is of type `function`. +Additionally check if the `typeof` the `_write` and `_writableState` properties are `function` and `object` respectively. + ```js -const isWritableStream = val => - val !== null && - typeof val === 'object' && - typeof val.pipe === 'function' && - typeof val._write === 'function' && - typeof val._writableState === 'object'; +const isWritableStream = val => + val !== null && + typeof val === 'object' && + typeof val.pipe === 'function' && + typeof val._write === 'function' && + typeof val._writableState === 'object'; ```
    Examples ```js -const fs = require('fs'); -isWritableStream(fs.createWriteStream('test.txt')); // true -``` +const fs = require('fs'); +isWritableStream(fs.createWriteStream('test.txt')); // true +```

    [⬆ Back to top](#contents) -### JSONToFile - -Writes a JSON object to a file. - -Use `fs.writeFile()`, template literals and `JSON.stringify()` to write a `json` object to a `.json` file. - +### JSONToFile + +Writes a JSON object to a file. + +Use `fs.writeFile()`, template literals and `JSON.stringify()` to write a `json` object to a `.json` file. + ```js const fs = require('fs'); const JSONToFile = (obj, filename) => @@ -6548,20 +6547,20 @@ const JSONToFile = (obj, filename) => ```js JSONToFile({ test: 'is passed' }, 'testJsonFile'); // writes the object to 'testJsonFile.json' -``` +```
    [⬆ Back to top](#contents) -### readFileLines - -Returns an array of lines from the specified file. - -Use `readFileSync` function in `fs` node package to create a `Buffer` from a file. -convert buffer to string using `toString(encoding)` function. -creating an array from contents of file by `split`ing file content line by line (each `\n`). - +### readFileLines + +Returns an array of lines from the specified file. + +Use `readFileSync` function in `fs` node package to create a `Buffer` from a file. +convert buffer to string using `toString(encoding)` function. +creating an array from contents of file by `split`ing file content line by line (each `\n`). + ```js const fs = require('fs'); const readFileLines = filename => @@ -6575,28 +6574,28 @@ const readFileLines = filename => Examples ```js -/* -contents of test.txt : - line1 - line2 - line3 - ___________________________ +/* +contents of test.txt : + line1 + line2 + line3 + ___________________________ */ let arr = readFileLines('test.txt'); console.log(arr); // ['line1', 'line2', 'line3'] -``` - +``` +
    [⬆ Back to top](#contents) -### untildify - -Converts a tilde path to an absolute path. - -Use `String.prototype.replace()` with a regular expression and `OS.homedir()` to replace the `~` in the start of the path with the home directory. - +### untildify + +Converts a tilde path to an absolute path. + +Use `String.prototype.replace()` with a regular expression and `OS.homedir()` to replace the `~` in the start of the path with the home directory. + ```js const untildify = str => str.replace(/^~($|\/|\\)/, `${require('os').homedir()}$1`); ``` @@ -6606,18 +6605,18 @@ const untildify = str => str.replace(/^~($|\/|\\)/, `${require('os').homedir()}$ ```js untildify('~/node'); // '/Users/aUser/node' -``` +```
    [⬆ Back to top](#contents) -### UUIDGeneratorNode - -Generates a UUID in Node.JS. - -Use `crypto` API to generate a UUID, compliant with [RFC4122](https://www.ietf.org/rfc/rfc4122.txt) version 4. - +### UUIDGeneratorNode + +Generates a UUID in Node.JS. + +Use `crypto` API to generate a UUID, compliant with [RFC4122](https://www.ietf.org/rfc/rfc4122.txt) version 4. + ```js const crypto = require('crypto'); const UUIDGeneratorNode = () => @@ -6631,7 +6630,7 @@ const UUIDGeneratorNode = () => ```js UUIDGeneratorNode(); // '79c7c136-60ee-40a2-beb2-856f1feabefc' -``` +``` @@ -6642,12 +6641,12 @@ UUIDGeneratorNode(); // '79c7c136-60ee-40a2-beb2-856f1feabefc' ## 🗃️ Object -### bindAll - -Binds methods of an object to the object itself, overwriting the existing method. - -Use `Array.prototype.forEach()` to return a `function` that uses `Function.prototype.apply()` to apply the given context (`obj`) to `fn` for each function specified. - +### bindAll + +Binds methods of an object to the object itself, overwriting the existing method. + +Use `Array.prototype.forEach()` to return a `function` that uses `Function.prototype.apply()` to apply the given context (`obj`) to `fn` for each function specified. + ```js const bindAll = (obj, ...fns) => fns.forEach( @@ -6672,67 +6671,71 @@ var view = { }; bindAll(view, 'click'); jQuery(element).on('click', view.click); // Logs 'clicked docs' when clicked. -``` +```
    [⬆ Back to top](#contents) -### deepClone - -Creates a deep clone of an object. - -Use recursion. -Use `Object.assign()` and an empty object (`{}`) to create a shallow clone of the original. -Use `Object.keys()` and `Array.prototype.forEach()` to determine which key-value pairs need to be deep cloned. - +### deepClone + +Creates a deep clone of an object. + +Use recursion. +Use `Object.assign()` and an empty object (`{}`) to create a shallow clone of the original. +Use `Object.keys()` and `Array.prototype.forEach()` to determine which key-value pairs need to be deep cloned. + ```js -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 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) && obj.length + ? (clone.length = obj.length) && Array.from(clone) + : Array.isArray(obj) + ? Array.from(obj) + : clone; +}; ```
    Examples ```js -const a = { foo: 'bar', obj: { a: 1, b: 2 } }; -const b = deepClone(a); // a !== b, a.obj !== b.obj -``` +const a = { foo: 'bar', obj: { a: 1, b: 2 } }; +const b = deepClone(a); // a !== b, a.obj !== b.obj +```

    [⬆ Back to top](#contents) -### deepFreeze - -Deep freezes an object. - -Calls `Object.freeze(obj)` recursively on all unfrozen properties of passed object that are `instanceof` object. - +### deepFreeze + +Deep freezes an object. + +Calls `Object.freeze(obj)` recursively on all unfrozen properties of passed object that are `instanceof` object. + ```js -const deepFreeze = obj => - Object.keys(obj).forEach( - prop => - !(obj[prop] instanceof Object) || Object.isFrozen(obj[prop]) ? null : deepFreeze(obj[prop]) - ) || Object.freeze(obj); +const deepFreeze = obj => + Object.keys(obj).forEach( + prop => + !(obj[prop] instanceof Object) || Object.isFrozen(obj[prop]) ? null : deepFreeze(obj[prop]) + ) || Object.freeze(obj); ```
    Examples ```js -'use strict'; - -const o = deepFreeze([1, [2, 3]]); - -o[0] = 3; // not allowed -o[1][0] = 4; // not allowed as well -``` +'use strict'; + +const o = deepFreeze([1, [2, 3]]); + +o[0] = 3; // not allowed +o[1][0] = 4; // not allowed as well +```
    @@ -6798,12 +6801,12 @@ const upperKeysObj = deepMapKeys(obj, key => key.toUpperCase());
    [⬆ Back to top](#contents) -### defaults - -Assigns default values for all properties in an object that are `undefined`. - -Use `Object.assign()` to create a new empty object and copy the original one to maintain key order, use `Array.prototype.reverse()` and the spread operator `...` to combine the default values from left to right, finally use `obj` again to overwrite properties that originally had a value. - +### defaults + +Assigns default values for all properties in an object that are `undefined`. + +Use `Object.assign()` to create a new empty object and copy the original one to maintain key order, use `Array.prototype.reverse()` and the spread operator `...` to combine the default values from left to right, finally use `obj` again to overwrite properties that originally had a value. + ```js const defaults = (obj, ...defs) => Object.assign({}, obj, ...defs.reverse(), obj); ``` @@ -6813,43 +6816,43 @@ const defaults = (obj, ...defs) => Object.assign({}, obj, ...defs.reverse(), obj ```js defaults({ a: 1 }, { b: 2 }, { b: 6 }, { a: 3 }); // { a: 1, b: 2 } -``` +```
    [⬆ Back to top](#contents) -### 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. - +### 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. + ```js -const dig = (obj, target) => - target in obj - ? obj[target] - : Object.values(obj).reduce((acc, val) => { - if (acc !== undefined) return acc; - if (typeof val === 'object') return dig(val, target); - }, undefined); +const dig = (obj, target) => + target in obj + ? obj[target] + : Object.values(obj).reduce((acc, val) => { + if (acc !== undefined) return acc; + if (typeof val === 'object') return dig(val, target); + }, undefined); ```
    Examples ```js -const data = { - level1: { - level2: { - level3: 'some data' - } - } -}; -dig(data, 'level3'); // 'some data' -dig(data, 'level4'); // undefined -``` +const data = { + level1: { + level2: { + level3: 'some data' + } + } +}; +dig(data, 'level3'); // 'some data' +dig(data, 'level4'); // undefined +```
    @@ -6887,12 +6890,12 @@ equals({ a: [2, { e: 3 }], b: [4], c: 'foo' }, { a: [2, { e: 3 }], b: [4], c: 'f
    [⬆ Back to top](#contents) -### findKey - -Returns the first key that satisfies the provided testing function. Otherwise `undefined` is returned. - -Use `Object.keys(obj)` to get all the properties of the object, `Array.prototype.find()` to test the provided function for each key-value pair. The callback receives three arguments - the value, the key and the object. - +### findKey + +Returns the first key that satisfies the provided testing function. Otherwise `undefined` is returned. + +Use `Object.keys(obj)` to get all the properties of the object, `Array.prototype.find()` to test the provided function for each key-value pair. The callback receives three arguments - the value, the key and the object. + ```js const findKey = (obj, fn) => Object.keys(obj).find(key => fn(obj[key], key, obj)); ``` @@ -6909,20 +6912,20 @@ findKey( }, o => o['active'] ); // 'barney' -``` +```
    [⬆ Back to top](#contents) -### findLastKey - -Returns the last key that satisfies the provided testing function. -Otherwise `undefined` is returned. - -Use `Object.keys(obj)` to get all the properties of the object, `Array.prototype.reverse()` to reverse their order and `Array.prototype.find()` to test the provided function for each key-value pair. -The callback receives three arguments - the value, the key and the object. - +### findLastKey + +Returns the last key that satisfies the provided testing function. +Otherwise `undefined` is returned. + +Use `Object.keys(obj)` to get all the properties of the object, `Array.prototype.reverse()` to reverse their order and `Array.prototype.find()` to test the provided function for each key-value pair. +The callback receives three arguments - the value, the key and the object. + ```js const findLastKey = (obj, fn) => Object.keys(obj) @@ -6942,22 +6945,22 @@ findLastKey( }, o => o['active'] ); // 'pebbles' -``` +```
    [⬆ Back to top](#contents) -### flattenObject - -Flatten an object with the paths for keys. - -Use recursion. -Use `Object.keys(obj)` combined with `Array.prototype.reduce()` to convert every leaf node to a flattened path node. -If the value of a key is an object, the function calls itself with the appropriate `prefix` to create the path using `Object.assign()`. -Otherwise, it adds the appropriate prefixed key-value pair to the accumulator object. -You should always omit the second argument, `prefix`, unless you want every key to have a prefix. - +### flattenObject + +Flatten an object with the paths for keys. + +Use recursion. +Use `Object.keys(obj)` combined with `Array.prototype.reduce()` to convert every leaf node to a flattened path node. +If the value of a key is an object, the function calls itself with the appropriate `prefix` to create the path using `Object.assign()`. +Otherwise, it adds the appropriate prefixed key-value pair to the accumulator object. +You should always omit the second argument, `prefix`, unless you want every key to have a prefix. + ```js const flattenObject = (obj, prefix = '') => Object.keys(obj).reduce((acc, k) => { @@ -6973,18 +6976,18 @@ const flattenObject = (obj, prefix = '') => ```js flattenObject({ a: { b: { c: 1 } }, d: 1 }); // { 'a.b.c': 1, d: 1 } -``` +```
    [⬆ Back to top](#contents) -### forOwn - -Iterates over all own properties of an object, running a callback for each one. - -Use `Object.keys(obj)` to get all the properties of the object, `Array.prototype.forEach()` to run the provided function for each key-value pair. The callback receives three arguments - the value, the key and the object. - +### forOwn + +Iterates over all own properties of an object, running a callback for each one. + +Use `Object.keys(obj)` to get all the properties of the object, `Array.prototype.forEach()` to run the provided function for each key-value pair. The callback receives three arguments - the value, the key and the object. + ```js const forOwn = (obj, fn) => Object.keys(obj).forEach(key => fn(obj[key], key, obj)); ``` @@ -6994,18 +6997,18 @@ const forOwn = (obj, fn) => Object.keys(obj).forEach(key => fn(obj[key], key, ob ```js forOwn({ foo: 'bar', a: 1 }, v => console.log(v)); // 'bar', 1 -``` +```
    [⬆ Back to top](#contents) -### forOwnRight - -Iterates over all own properties of an object in reverse, running a callback for each one. - -Use `Object.keys(obj)` to get all the properties of the object, `Array.prototype.reverse()` to reverse their order and `Array.prototype.forEach()` to run the provided function for each key-value pair. The callback receives three arguments - the value, the key and the object. - +### forOwnRight + +Iterates over all own properties of an object in reverse, running a callback for each one. + +Use `Object.keys(obj)` to get all the properties of the object, `Array.prototype.reverse()` to reverse their order and `Array.prototype.forEach()` to run the provided function for each key-value pair. The callback receives three arguments - the value, the key and the object. + ```js const forOwnRight = (obj, fn) => Object.keys(obj) @@ -7018,21 +7021,21 @@ const forOwnRight = (obj, fn) => ```js forOwnRight({ foo: 'bar', a: 1 }, v => console.log(v)); // 1, 'bar' -``` +```
    [⬆ Back to top](#contents) -### functions - -Returns an array of function property names from own (and optionally inherited) enumerable properties of an object. - -Use `Object.keys(obj)` to iterate over the object's own properties. -If `inherited` is `true`, use `Object.get.PrototypeOf(obj)` to also get the object's inherited properties. -Use `Array.prototype.filter()` to keep only those properties that are functions. -Omit the second argument, `inherited`, to not include inherited properties by default. - +### functions + +Returns an array of function property names from own (and optionally inherited) enumerable properties of an object. + +Use `Object.keys(obj)` to iterate over the object's own properties. +If `inherited` is `true`, use `Object.get.PrototypeOf(obj)` to also get the object's inherited properties. +Use `Array.prototype.filter()` to keep only those properties that are functions. +Omit the second argument, `inherited`, to not include inherited properties by default. + ```js const functions = (obj, inherited = false) => (inherited @@ -7052,18 +7055,18 @@ function Foo() { Foo.prototype.c = () => 3; functions(new Foo()); // ['a', 'b'] functions(new Foo(), true); // ['a', 'b', 'c'] -``` +```
    [⬆ Back to top](#contents) -### get - -Retrieve a set of properties indicated by the given selectors from an object. - -Use `Array.prototype.map()` for each selector, `String.prototype.replace()` to replace square brackets with dots, `String.prototype.split('.')` to split each selector, `Array.prototype.filter()` to remove empty values and `Array.prototype.reduce()` to get the value indicated by it. - +### get + +Retrieve a set of properties indicated by the given selectors from an object. + +Use `Array.prototype.map()` for each selector, `String.prototype.replace()` to replace square brackets with dots, `String.prototype.split('.')` to split each selector, `Array.prototype.filter()` to remove empty values and `Array.prototype.reduce()` to get the value indicated by it. + ```js const get = (from, ...selectors) => [...selectors].map(s => @@ -7081,19 +7084,19 @@ const get = (from, ...selectors) => ```js const obj = { selector: { to: { val: 'val to select' } }, target: [1, 2, { a: 'test' }] }; get(obj, 'selector.to.val', 'target[0]', 'target[2].a'); // ['val to select', 1, 'test'] -``` +```
    [⬆ Back to top](#contents) -### invertKeyValues - -Inverts the key-value pairs of an object, without mutating it. The corresponding inverted value of each inverted key is an array of keys responsible for generating the inverted value. If a function is supplied, it is applied to each inverted key. - -Use `Object.keys()` and `Array.prototype.reduce()` to invert the key-value pairs of an object and apply the function provided (if any). -Omit the second argument, `fn`, to get the inverted keys without applying a function to them. - +### invertKeyValues + +Inverts the key-value pairs of an object, without mutating it. The corresponding inverted value of each inverted key is an array of keys responsible for generating the inverted value. If a function is supplied, it is applied to each inverted key. + +Use `Object.keys()` and `Array.prototype.reduce()` to invert the key-value pairs of an object and apply the function provided (if any). +Omit the second argument, `fn`, to get the inverted keys without applying a function to them. + ```js const invertKeyValues = (obj, fn) => Object.keys(obj).reduce((acc, key) => { @@ -7110,19 +7113,19 @@ const invertKeyValues = (obj, fn) => ```js invertKeyValues({ a: 1, b: 2, c: 1 }); // { 1: [ 'a', 'c' ], 2: [ 'b' ] } invertKeyValues({ a: 1, b: 2, c: 1 }, value => 'group' + value); // { group1: [ 'a', 'c' ], group2: [ 'b' ] } -``` +```
    [⬆ Back to top](#contents) -### lowercaseKeys - -Creates a new object from the specified object, where all the keys are in lowercase. - -Use `Object.keys()` and `Array.prototype.reduce()` to create a new object from the specified object. -Convert each key in the original object to lowercase, using `String.toLowerCase()`. - +### lowercaseKeys + +Creates a new object from the specified object, where all the keys are in lowercase. + +Use `Object.keys()` and `Array.prototype.reduce()` to create a new object from the specified object. +Convert each key in the original object to lowercase, using `String.toLowerCase()`. + ```js const lowercaseKeys = obj => Object.keys(obj).reduce((acc, key) => { @@ -7137,19 +7140,19 @@ const lowercaseKeys = obj => ```js const myObj = { Name: 'Adam', sUrnAME: 'Smith' }; const myObjLower = lowercaseKeys(myObj); // {name: 'Adam', surname: 'Smith'}; -``` +```
    [⬆ Back to top](#contents) -### mapKeys - -Creates an object with keys generated by running the provided function for each key and the same values as the provided object. - -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`. - +### mapKeys + +Creates an object with keys generated by running the provided function for each key and the same values as the provided object. + +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 mapKeys = (obj, fn) => Object.keys(obj).reduce((acc, k) => { @@ -7163,19 +7166,19 @@ const mapKeys = (obj, fn) => ```js mapKeys({ a: 1, b: 2 }, (val, key) => key + val); // { a1: 1, b2: 2 } -``` +```
    [⬆ Back to top](#contents) -### mapValues - -Creates an object with the same keys as the provided object and values generated by running the provided function for each value. - -Use `Object.keys(obj)` to iterate over the object's keys. -Use `Array.prototype.reduce()` to create a new object with the same keys and mapped values using `fn`. - +### mapValues + +Creates an object with the same keys as the provided object and values generated by running the provided function for each value. + +Use `Object.keys(obj)` to iterate over the object's keys. +Use `Array.prototype.reduce()` to create a new object with the same keys and mapped values using `fn`. + ```js const mapValues = (obj, fn) => Object.keys(obj).reduce((acc, k) => { @@ -7193,18 +7196,18 @@ const users = { pebbles: { user: 'pebbles', age: 1 } }; mapValues(users, u => u.age); // { fred: 40, pebbles: 1 } -``` +```
    [⬆ Back to top](#contents) -### matches - -Compares two objects to determine if the first one contains equivalent property values to the second one. - -Use `Object.keys(source)` to get all the keys of the second object, then `Array.prototype.every()`, `Object.hasOwnProperty()` and strict comparison to determine if all keys exist in the first object and have the same values. - +### matches + +Compares two objects to determine if the first one contains equivalent property values to the second one. + +Use `Object.keys(source)` to get all the keys of the second object, then `Array.prototype.every()`, `Object.hasOwnProperty()` and strict comparison to determine if all keys exist in the first object and have the same values. + ```js const matches = (obj, source) => Object.keys(source).every(key => obj.hasOwnProperty(key) && obj[key] === source[key]); @@ -7216,19 +7219,19 @@ const matches = (obj, source) => ```js matches({ age: 25, hair: 'long', beard: true }, { hair: 'long', beard: true }); // true matches({ hair: 'long', beard: true }, { age: 25, hair: 'long', beard: true }); // false -``` +```
    [⬆ Back to top](#contents) -### matchesWith - -Compares two objects to determine if the first one contains equivalent property values to the second one, based on a provided function. - -Use `Object.keys(source)` to get all the keys of the second object, then `Array.prototype.every()`, `Object.hasOwnProperty()` and the provided function to determine if all keys exist in the first object and have equivalent values. -If no function is provided, the values will be compared using the equality operator. - +### matchesWith + +Compares two objects to determine if the first one contains equivalent property values to the second one, based on a provided function. + +Use `Object.keys(source)` to get all the keys of the second object, then `Array.prototype.every()`, `Object.hasOwnProperty()` and the provided function to determine if all keys exist in the first object and have equivalent values. +If no function is provided, the values will be compared using the equality operator. + ```js const matchesWith = (obj, source, fn) => Object.keys(source).every( @@ -7249,19 +7252,19 @@ matchesWith( { greeting: 'hi' }, (oV, sV) => isGreeting(oV) && isGreeting(sV) ); // true -``` +```
    [⬆ Back to top](#contents) -### merge - -Creates a new object from the combination of two or more objects. - -Use `Array.prototype.reduce()` combined with `Object.keys(obj)` to iterate over all objects and keys. -Use `hasOwnProperty()` and `Array.prototype.concat()` to append values for keys existing in multiple objects. - +### merge + +Creates a new object from the combination of two or more objects. + +Use `Array.prototype.reduce()` combined with `Object.keys(obj)` to iterate over all objects and keys. +Use `hasOwnProperty()` and `Array.prototype.concat()` to append values for keys existing in multiple objects. + ```js const merge = (...objs) => [...objs].reduce( @@ -7288,22 +7291,22 @@ const other = { c: 'foo' }; merge(object, other); // { a: [ { x: 2 }, { y: 4 }, { z: 3 } ], b: [ 1, 2, 3 ], c: 'foo' } -``` +```
    [⬆ Back to top](#contents) -### nest - -Given a flat array of objects linked to one another, it will nest them recursively. -Useful for nesting comments, such as the ones on reddit.com. - -Use recursion. -Use `Array.prototype.filter()` to filter the items where the `id` matches the `link`, then `Array.prototype.map()` to map each one to a new object that has a `children` property which recursively nests the items based on which ones are children of the current item. -Omit the second argument, `id`, to default to `null` which indicates the object is not linked to another one (i.e. it is a top level object). -Omit the third argument, `link`, to use `'parent_id'` as the default property which links the object to another one by its `id`. - +### nest + +Given a flat array of objects linked to one another, it will nest them recursively. +Useful for nesting comments, such as the ones on reddit.com. + +Use recursion. +Use `Array.prototype.filter()` to filter the items where the `id` matches the `link`, then `Array.prototype.map()` to map each one to a new object that has a `children` property which recursively nests the items based on which ones are children of the current item. +Omit the second argument, `id`, to default to `null` which indicates the object is not linked to another one (i.e. it is a top level object). +Omit the third argument, `link`, to use `'parent_id'` as the default property which links the object to another one by its `id`. + ```js const nest = (items, id = null, link = 'parent_id') => items @@ -7324,19 +7327,19 @@ const comments = [ { id: 5, parent_id: 4 } ]; const nestedComments = nest(comments); // [{ id: 1, parent_id: null, children: [...] }] -``` - +``` +
    [⬆ Back to top](#contents) -### objectFromPairs - -Creates an object from the given key-value pairs. - -Use `Array.prototype.reduce()` to create and combine key-value pairs. - +### objectFromPairs + +Creates an object from the given key-value pairs. + +Use `Array.prototype.reduce()` to create and combine key-value pairs. + ```js const objectFromPairs = arr => arr.reduce((a, [key, val]) => ((a[key] = val), a), {}); ``` @@ -7346,18 +7349,18 @@ const objectFromPairs = arr => arr.reduce((a, [key, val]) => ((a[key] = val), a) ```js objectFromPairs([['a', 1], ['b', 2]]); // {a: 1, b: 2} -``` +```
    [⬆ Back to top](#contents) -### objectToPairs - -Creates an array of key-value pair arrays from an object. - -Use `Object.keys()` and `Array.prototype.map()` to iterate over the object's keys and produce an array with key-value pairs. - +### objectToPairs + +Creates an array of key-value pair arrays from an object. + +Use `Object.keys()` and `Array.prototype.map()` to iterate over the object's keys and produce an array with key-value pairs. + ```js const objectToPairs = obj => Object.keys(obj).map(k => [k, obj[k]]); ``` @@ -7367,19 +7370,19 @@ const objectToPairs = obj => Object.keys(obj).map(k => [k, obj[k]]); ```js objectToPairs({ a: 1, b: 2 }); // [ ['a', 1], ['b', 2] ] -``` +```
    [⬆ Back to top](#contents) -### omit - -Omits the key-value pairs corresponding to the given keys from an object. - -Use `Object.keys(obj)`, `Array.prototype.filter()` and `Array.prototype.includes()` to remove the provided keys. -Use `Array.prototype.reduce()` to convert the filtered keys back to an object with the corresponding key-value pairs. - +### omit + +Omits the key-value pairs corresponding to the given keys from an object. + +Use `Object.keys(obj)`, `Array.prototype.filter()` and `Array.prototype.includes()` to remove the provided keys. +Use `Array.prototype.reduce()` to convert the filtered keys back to an object with the corresponding key-value pairs. + ```js const omit = (obj, arr) => Object.keys(obj) @@ -7392,19 +7395,19 @@ const omit = (obj, arr) => ```js omit({ a: 1, b: '2', c: 3 }, ['b']); // { 'a': 1, 'c': 3 } -``` +```
    [⬆ Back to top](#contents) -### omitBy - -Creates an object composed of the properties the given function returns falsey for. The function is invoked with two arguments: (value, key). - -Use `Object.keys(obj)` and `Array.prototype.filter()`to remove the keys for which `fn` returns a truthy value. -Use `Array.prototype.reduce()` to convert the filtered keys back to an object with the corresponding key-value pairs. - +### omitBy + +Creates an object composed of the properties the given function returns falsey for. The function is invoked with two arguments: (value, key). + +Use `Object.keys(obj)` and `Array.prototype.filter()`to remove the keys for which `fn` returns a truthy value. +Use `Array.prototype.reduce()` to convert the filtered keys back to an object with the corresponding key-value pairs. + ```js const omitBy = (obj, fn) => Object.keys(obj) @@ -7417,19 +7420,19 @@ const omitBy = (obj, fn) => ```js omitBy({ a: 1, b: '2', c: 3 }, x => typeof x === 'number'); // { b: '2' } -``` +```
    [⬆ Back to top](#contents) -### orderBy - -Returns a sorted array of objects ordered by properties and orders. - -Uses `Array.prototype.sort()`, `Array.prototype.reduce()` on the `props` array with a default value of `0`, use array destructuring to swap the properties position depending on the order passed. -If no `orders` array is passed it sort by `'asc'` by default. - +### orderBy + +Returns a sorted array of objects ordered by properties and orders. + +Uses `Array.prototype.sort()`, `Array.prototype.reduce()` on the `props` array with a default value of `0`, use array destructuring to swap the properties position depending on the order passed. +If no `orders` array is passed it sort by `'asc'` by default. + ```js const orderBy = (arr, props, orders) => [...arr].sort((a, b) => @@ -7450,18 +7453,18 @@ const orderBy = (arr, props, orders) => const users = [{ name: 'fred', age: 48 }, { name: 'barney', age: 36 }, { name: 'fred', age: 40 }]; orderBy(users, ['name', 'age'], ['asc', 'desc']); // [{name: 'barney', age: 36}, {name: 'fred', age: 48}, {name: 'fred', age: 40}] orderBy(users, ['name', 'age']); // [{name: 'barney', age: 36}, {name: 'fred', age: 40}, {name: 'fred', age: 48}] -``` +```
    [⬆ Back to top](#contents) -### pick - -Picks the key-value pairs corresponding to the given keys from an object. - -Use `Array.prototype.reduce()` to convert the filtered/picked keys back to an object with the corresponding key-value pairs if the key exists in the object. - +### pick + +Picks the key-value pairs corresponding to the given keys from an object. + +Use `Array.prototype.reduce()` to convert the filtered/picked keys back to an object with the corresponding key-value pairs if the key exists in the object. + ```js const pick = (obj, arr) => arr.reduce((acc, curr) => (curr in obj && (acc[curr] = obj[curr]), acc), {}); @@ -7472,19 +7475,19 @@ const pick = (obj, arr) => ```js pick({ a: 1, b: '2', c: 3 }, ['a', 'c']); // { 'a': 1, 'c': 3 } -``` +```
    [⬆ Back to top](#contents) -### pickBy - -Creates an object composed of the properties the given function returns truthy for. The function is invoked with two arguments: (value, key). - -Use `Object.keys(obj)` and `Array.prototype.filter()`to remove the keys for which `fn` returns a falsey value. -Use `Array.prototype.reduce()` to convert the filtered keys back to an object with the corresponding key-value pairs. - +### pickBy + +Creates an object composed of the properties the given function returns truthy for. The function is invoked with two arguments: (value, key). + +Use `Object.keys(obj)` and `Array.prototype.filter()`to remove the keys for which `fn` returns a falsey value. +Use `Array.prototype.reduce()` to convert the filtered keys back to an object with the corresponding key-value pairs. + ```js const pickBy = (obj, fn) => Object.keys(obj) @@ -7497,18 +7500,18 @@ const pickBy = (obj, fn) => ```js pickBy({ a: 1, b: '2', c: 3 }, x => typeof x === 'number'); // { 'a': 1, 'c': 3 } -``` +```
    [⬆ Back to top](#contents) -### renameKeys - -Replaces the names of multiple object keys with the values provided. - -Use `Object.keys()` in combination with `Array.prototype.reduce()` and the spread operator (`...`) to get the object's keys and rename them according to `keysMap`. - +### renameKeys + +Replaces the names of multiple object keys with the values provided. + +Use `Object.keys()` in combination with `Array.prototype.reduce()` and the spread operator (`...`) to get the object's keys and rename them according to `keysMap`. + ```js const renameKeys = (keysMap, obj) => Object.keys(obj).reduce( @@ -7526,18 +7529,18 @@ const renameKeys = (keysMap, obj) => ```js const obj = { name: 'Bobo', job: 'Front-End Master', shoeSize: 100 }; renameKeys({ name: 'firstName', job: 'passion' }, obj); // { firstName: 'Bobo', passion: 'Front-End Master', shoeSize: 100 } -``` +```
    [⬆ Back to top](#contents) -### shallowClone - -Creates a shallow clone of an object. - -Use `Object.assign()` and an empty object (`{}`) to create a shallow clone of the original. - +### shallowClone + +Creates a shallow clone of an object. + +Use `Object.assign()` and an empty object (`{}`) to create a shallow clone of the original. + ```js const shallowClone = obj => Object.assign({}, obj); ``` @@ -7548,23 +7551,23 @@ const shallowClone = obj => Object.assign({}, obj); ```js const a = { x: true, y: 1 }; const b = shallowClone(a); // a !== b -``` +```
    [⬆ Back to top](#contents) -### size - -Get size of arrays, objects or strings. - -Get type of `val` (`array`, `object` or `string`). -Use `length` property for arrays. -Use `length` or `size` value if available or number of keys for objects. -Use `size` of a [`Blob` object](https://developer.mozilla.org/en-US/docs/Web/API/Blob) created from `val` for strings. - -Split strings into array of characters with `split('')` and return its length. - +### size + +Get size of arrays, objects or strings. + +Get type of `val` (`array`, `object` or `string`). +Use `length` property for arrays. +Use `length` or `size` value if available or number of keys for objects. +Use `size` of a [`Blob` object](https://developer.mozilla.org/en-US/docs/Web/API/Blob) created from `val` for strings. + +Split strings into array of characters with `split('')` and return its length. + ```js const size = val => Array.isArray(val) @@ -7583,18 +7586,18 @@ const size = val => size([1, 2, 3, 4, 5]); // 5 size('size'); // 4 size({ one: 1, two: 2, three: 3 }); // 3 -``` +```
    [⬆ Back to top](#contents) -### transform - -Applies a function against an accumulator and each key in the object (from left to right). - -Use `Object.keys(obj)` to iterate over each key in the object, `Array.prototype.reduce()` to call the apply the specified function against the given accumulator. - +### transform + +Applies a function against an accumulator and each key in the object (from left to right). + +Use `Object.keys(obj)` to iterate over each key in the object, `Array.prototype.reduce()` to call the apply the specified function against the given accumulator. + ```js const transform = (obj, fn, acc) => Object.keys(obj).reduce((a, k) => fn(a, obj[k], k, obj), acc); ``` @@ -7611,18 +7614,18 @@ transform( }, {} ); // { '1': ['a', 'c'], '2': ['b'] } -``` +```
    [⬆ Back to top](#contents) -### truthCheckCollection - -Checks if the predicate (second argument) is truthy on all elements of a collection (first argument). - -Use `Array.prototype.every()` to check if each passed object has the specified property and if it returns a truthy value. - +### truthCheckCollection + +Checks if the predicate (second argument) is truthy on all elements of a collection (first argument). + +Use `Array.prototype.every()` to check if each passed object has the specified property and if it returns a truthy value. + ```js const truthCheckCollection = (collection, pre) => collection.every(obj => obj[pre]); ``` @@ -7632,7 +7635,7 @@ const truthCheckCollection = (collection, pre) => collection.every(obj => obj[pr ```js truthCheckCollection([{ user: 'Tinky-Winky', sex: 'male' }, { user: 'Dipsy', sex: 'male' }], 'sex'); // true -``` +``` @@ -7681,12 +7684,12 @@ unflattenObject({ 'a.b.c': 1, d: 1 }); // { a: { b: { c: 1 } }, d: 1 } ## 📜 String -### byteSize - -Returns the length of a string in bytes. - -Convert a given string to a [`Blob` Object](https://developer.mozilla.org/en-US/docs/Web/API/Blob) and find its `size`. - +### byteSize + +Returns the length of a string in bytes. + +Convert a given string to a [`Blob` Object](https://developer.mozilla.org/en-US/docs/Web/API/Blob) and find its `size`. + ```js const byteSize = str => new Blob([str]).size; ``` @@ -7697,19 +7700,19 @@ const byteSize = str => new Blob([str]).size; ```js byteSize('😀'); // 4 byteSize('Hello World'); // 11 -``` +```
    [⬆ Back to top](#contents) -### capitalize - -Capitalizes the first letter of a string. - -Use array destructuring and `String.prototype.toUpperCase()` to capitalize first letter, `...rest` to get array of characters after first letter and then `Array.prototype.join('')` to make it a string again. -Omit the `lowerRest` parameter to keep the rest of the string intact, or set it to `true` to convert to lowercase. - +### capitalize + +Capitalizes the first letter of a string. + +Use array destructuring and `String.prototype.toUpperCase()` to capitalize first letter, `...rest` to get array of characters after first letter and then `Array.prototype.join('')` to make it a string again. +Omit the `lowerRest` parameter to keep the rest of the string intact, or set it to `true` to convert to lowercase. + ```js const capitalize = ([first, ...rest], lowerRest = false) => first.toUpperCase() + (lowerRest ? rest.join('').toLowerCase() : rest.join('')); @@ -7721,18 +7724,18 @@ const capitalize = ([first, ...rest], lowerRest = false) => ```js capitalize('fooBar'); // 'FooBar' capitalize('fooBar', true); // 'Foobar' -``` +```
    [⬆ Back to top](#contents) -### capitalizeEveryWord - -Capitalizes the first letter of every word in a string. - -Use `String.prototype.replace()` to match the first character of each word and `String.prototype.toUpperCase()` to capitalize it. - +### capitalizeEveryWord + +Capitalizes the first letter of every word in a string. + +Use `String.prototype.replace()` to match the first character of each word and `String.prototype.toUpperCase()` to capitalize it. + ```js const capitalizeEveryWord = str => str.replace(/\b[a-z]/g, char => char.toUpperCase()); ``` @@ -7742,43 +7745,43 @@ const capitalizeEveryWord = str => str.replace(/\b[a-z]/g, char => char.toUpperC ```js capitalizeEveryWord('hello world!'); // 'Hello World!' -``` +```
    [⬆ Back to top](#contents) -### compactWhitespace - -Returns a string with whitespaces compacted. - -Use `String.prototype.replace()` with a regular expression to replace all occurences of 2 or more whitespace characters with a single space. - +### compactWhitespace + +Returns a string with whitespaces compacted. + +Use `String.prototype.replace()` with a regular expression to replace all occurences of 2 or more whitespace characters with a single space. + ```js -const compactWhitespace = str => str.replace(/\s{2,}/g, ' '); +const compactWhitespace = str => str.replace(/\s{2,}/g, ' '); ```
    Examples ```js -compactWhitespace('Lorem Ipsum'); // 'Lorem Ipsum' -compactWhitespace('Lorem \n Ipsum'); // 'Lorem Ipsum' -``` +compactWhitespace('Lorem Ipsum'); // 'Lorem Ipsum' +compactWhitespace('Lorem \n Ipsum'); // 'Lorem Ipsum' +```

    [⬆ Back to top](#contents) -### CSVToArray - -Converts a comma-separated values (CSV) string to a 2D array. - -Use `Array.prototype.slice()` and `Array.prototype.indexOf('\n')` to remove the first row (title row) if `omitFirstRow` is `true`. -Use `String.prototype.split('\n')` to create a string for each row, then `String.prototype.split(delimiter)` to separate the values in each row. -Omit the second argument, `delimiter`, to use a default delimiter of `,`. -Omit the third argument, `omitFirstRow`, to include the first row (title row) of the CSV string. - +### CSVToArray + +Converts a comma-separated values (CSV) string to a 2D array. + +Use `Array.prototype.slice()` and `Array.prototype.indexOf('\n')` to remove the first row (title row) if `omitFirstRow` is `true`. +Use `String.prototype.split('\n')` to create a string for each row, then `String.prototype.split(delimiter)` to separate the values in each row. +Omit the second argument, `delimiter`, to use a default delimiter of `,`. +Omit the third argument, `omitFirstRow`, to include the first row (title row) of the CSV string. + ```js const CSVToArray = (data, delimiter = ',', omitFirstRow = false) => data @@ -7794,7 +7797,7 @@ const CSVToArray = (data, delimiter = ',', omitFirstRow = false) => CSVToArray('a,b\nc,d'); // [['a','b'],['c','d']]; CSVToArray('a;b\nc;d', ';'); // [['a','b'],['c','d']]; CSVToArray('col1,col2\na,b\nc,d', ',', true); // [['a','b'],['c','d']]; -``` +``` @@ -7835,13 +7838,13 @@ CSVToJSON('col1;col2\na;b\nc;d', ';'); // [{'col1': 'a', 'col2': 'b'}, {'col1':
    [⬆ Back to top](#contents) -### decapitalize - -Decapitalizes the first letter of a string. - -Use array destructuring and `String.toLowerCase()` to decapitalize first letter, `...rest` to get array of characters after first letter and then `Array.prototype.join('')` to make it a string again. -Omit the `upperRest` parameter to keep the rest of the string intact, or set it to `true` to convert to uppercase. - +### decapitalize + +Decapitalizes the first letter of a string. + +Use array destructuring and `String.toLowerCase()` to decapitalize first letter, `...rest` to get array of characters after first letter and then `Array.prototype.join('')` to make it a string again. +Omit the `upperRest` parameter to keep the rest of the string intact, or set it to `true` to convert to uppercase. + ```js const decapitalize = ([first, ...rest], upperRest = false) => first.toLowerCase() + (upperRest ? rest.join('').toUpperCase() : rest.join('')); @@ -7853,18 +7856,18 @@ const decapitalize = ([first, ...rest], upperRest = false) => ```js decapitalize('FooBar'); // 'fooBar' decapitalize('FooBar', true); // 'fOOBAR' -``` +```
    [⬆ Back to top](#contents) -### escapeHTML - -Escapes a string for use in HTML. - -Use `String.prototype.replace()` with a regexp that matches the characters that need to be escaped, using a callback function to replace each character instance with its associated escaped character using a dictionary (object). - +### escapeHTML + +Escapes a string for use in HTML. + +Use `String.prototype.replace()` with a regexp that matches the characters that need to be escaped, using a callback function to replace each character instance with its associated escaped character using a dictionary (object). + ```js const escapeHTML = str => str.replace( @@ -7885,18 +7888,18 @@ const escapeHTML = str => ```js escapeHTML('Me & you'); // '<a href="#">Me & you</a>' -``` +```
    [⬆ Back to top](#contents) -### escapeRegExp - -Escapes a string to use in a regular expression. - -Use `String.prototype.replace()` to escape special characters. - +### escapeRegExp + +Escapes a string to use in a regular expression. + +Use `String.prototype.replace()` to escape special characters. + ```js const escapeRegExp = str => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); ``` @@ -7906,19 +7909,19 @@ const escapeRegExp = str => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); ```js escapeRegExp('(test)'); // \\(test\\) -``` +```
    [⬆ Back to top](#contents) -### fromCamelCase - -Converts a string from camelcase. - -Use `String.prototype.replace()` to remove underscores, hyphens, and spaces and convert words to camelcase. -Omit the second argument to use a default `separator` of `_`. - +### fromCamelCase + +Converts a string from camelcase. + +Use `String.prototype.replace()` to remove underscores, hyphens, and spaces and convert words to camelcase. +Omit the second argument to use a default `separator` of `_`. + ```js const fromCamelCase = (str, separator = '_') => str @@ -7934,19 +7937,19 @@ const fromCamelCase = (str, separator = '_') => fromCamelCase('someDatabaseFieldName', ' '); // 'some database field name' fromCamelCase('someLabelThatNeedsToBeCamelized', '-'); // 'some-label-that-needs-to-be-camelized' fromCamelCase('someJavascriptProperty', '_'); // 'some_javascript_property' -``` +```
    [⬆ Back to top](#contents) -### indentString - -Indents each line in the provided string. - -Use `String.replace` and a regular expression to add the character specified by `indent` `count` times at the start of each line. -Omit the third parameter, `indent`, to use a default indentation character of `' '`. - +### indentString + +Indents each line in the provided string. + +Use `String.replace` and a regular expression to add the character specified by `indent` `count` times at the start of each line. +Omit the third parameter, `indent`, to use a default indentation character of `' '`. + ```js const indentString = (str, count, indent = ' ') => str.replace(/^/gm, indent.repeat(count)); ``` @@ -7957,18 +7960,18 @@ const indentString = (str, count, indent = ' ') => str.replace(/^/gm, indent.rep ```js indentString('Lorem\nIpsum', 2); // ' Lorem\n Ipsum' indentString('Lorem\nIpsum', 2, '_'); // '__Lorem\n__Ipsum' -``` +```
    [⬆ Back to top](#contents) -### isAbsoluteURL - -Returns `true` if the given string is an absolute URL, `false` otherwise. - -Use a regular expression to test if the string is an absolute URL. - +### isAbsoluteURL + +Returns `true` if the given string is an absolute URL, `false` otherwise. + +Use a regular expression to test if the string is an absolute URL. + ```js const isAbsoluteURL = str => /^[a-z][a-z0-9+.-]*:/.test(str); ``` @@ -7980,18 +7983,18 @@ const isAbsoluteURL = str => /^[a-z][a-z0-9+.-]*:/.test(str); isAbsoluteURL('https://google.com'); // true isAbsoluteURL('ftp://www.myserver.net'); // true isAbsoluteURL('/foo/bar'); // false -``` +```
    [⬆ Back to top](#contents) -### isAnagram - -Checks if a string is an anagram of another string (case-insensitive, ignores spaces, punctuation and special characters). - -Use `String.toLowerCase()`, `String.prototype.replace()` with an appropriate regular expression to remove unnecessary characters, `String.prototype.split('')`, `Array.prototype.sort()` and `Array.prototype.join('')` on both strings to normalize them, then check if their normalized forms are equal. - +### isAnagram + +Checks if a string is an anagram of another string (case-insensitive, ignores spaces, punctuation and special characters). + +Use `String.toLowerCase()`, `String.prototype.replace()` with an appropriate regular expression to remove unnecessary characters, `String.prototype.split('')`, `Array.prototype.sort()` and `Array.prototype.join('')` on both strings to normalize them, then check if their normalized forms are equal. + ```js const isAnagram = (str1, str2) => { const normalize = str => @@ -8010,18 +8013,18 @@ const isAnagram = (str1, str2) => { ```js isAnagram('iceman', 'cinema'); // true -``` +```
    [⬆ Back to top](#contents) -### isLowerCase - -Checks if a string is lower case. - -Convert the given string to lower case, using `String.toLowerCase()` and compare it to the original. - +### isLowerCase + +Checks if a string is lower case. + +Convert the given string to lower case, using `String.toLowerCase()` and compare it to the original. + ```js const isLowerCase = str => str === str.toLowerCase(); ``` @@ -8033,19 +8036,19 @@ const isLowerCase = str => str === str.toLowerCase(); isLowerCase('abc'); // true isLowerCase('a3@$'); // true isLowerCase('Ab4'); // false -``` +```
    [⬆ Back to top](#contents) -### isUpperCase - -Checks if a string is upper case. - -Convert the given string to upper case, using `String.prototype.toUpperCase()` and compare it to the original. - - +### isUpperCase + +Checks if a string is upper case. + +Convert the given string to upper case, using `String.prototype.toUpperCase()` and compare it to the original. + + ```js const isUpperCase = str => str === str.toUpperCase(); ``` @@ -8057,20 +8060,20 @@ const isUpperCase = str => str === str.toUpperCase(); isUpperCase('ABC'); // true isLowerCase('A3@$'); // true isLowerCase('aB4'); // false -``` +```
    [⬆ Back to top](#contents) -### mapString - -Creates a new string with the results of calling a provided function on every character in the calling string. - -Use `String.prototype.split('')` and `Array.prototype.map()` to call the provided function, `fn`, for each character in `str`. -Use `Array.prototype.join('')` to recombine the array of characters into a string. -The callback function, `fn`, takes three arguments (the current character, the index of the current character and the string `mapString` was called upon). - +### mapString + +Creates a new string with the results of calling a provided function on every character in the calling string. + +Use `String.prototype.split('')` and `Array.prototype.map()` to call the provided function, `fn`, for each character in `str`. +Use `Array.prototype.join('')` to recombine the array of characters into a string. +The callback function, `fn`, takes three arguments (the current character, the index of the current character and the string `mapString` was called upon). + ```js const mapString = (str, fn) => str @@ -8084,20 +8087,20 @@ const mapString = (str, fn) => ```js mapString('lorem ipsum', c => c.toUpperCase()); // 'LOREM IPSUM' -``` +```
    [⬆ Back to top](#contents) -### mask - -Replaces all but the last `num` of characters with the specified mask character. - -Use `String.prototype.slice()` to grab the portion of the characters that will remain unmasked and use `String.padStart()` to fill the beginning of the string with the mask character up to the original length. -Omit the second argument, `num`, to keep a default of `4` characters unmasked. If `num` is negative, the unmasked characters will be at the start of the string. -Omit the third argument, `mask`, to use a default character of `'*'` for the mask. - +### mask + +Replaces all but the last `num` of characters with the specified mask character. + +Use `String.prototype.slice()` to grab the portion of the characters that will remain unmasked and use `String.padStart()` to fill the beginning of the string with the mask character up to the original length. +Omit the second argument, `num`, to keep a default of `4` characters unmasked. If `num` is negative, the unmasked characters will be at the start of the string. +Omit the third argument, `mask`, to use a default character of `'*'` for the mask. + ```js const mask = (cc, num = 4, mask = '*') => `${cc}`.slice(-num).padStart(`${cc}`.length, mask); ``` @@ -8109,19 +8112,19 @@ const mask = (cc, num = 4, mask = '*') => `${cc}`.slice(-num).padStart(`${cc}`.l mask(1234567890); // '******7890' mask(1234567890, 3); // '*******890' mask(1234567890, -4, '$'); // '$$$$567890' -``` +```
    [⬆ Back to top](#contents) -### pad - -Pads a string on both sides with the specified character, if it's shorter than the specified length. - -Use `String.padStart()` and `String.padEnd()` to pad both sides of the given string. -Omit the third argument, `char`, to use the whitespace character as the default padding character. - +### pad + +Pads a string on both sides with the specified character, if it's shorter than the specified length. + +Use `String.padStart()` and `String.padEnd()` to pad both sides of the given string. +Omit the third argument, `char`, to use the whitespace character as the default padding character. + ```js const pad = (str, length, char = ' ') => str.padStart((str.length + length) / 2, char).padEnd(length, char); @@ -8134,43 +8137,43 @@ const pad = (str, length, char = ' ') => pad('cat', 8); // ' cat ' pad(String(42), 6, '0'); // '004200' pad('foobar', 3); // 'foobar' -``` +```
    [⬆ Back to top](#contents) -### palindrome - -Returns `true` if the given string is a palindrome, `false` otherwise. - -Convert the string to `String.prototype.toLowerCase()` and use `String.prototype.replace()` to remove non-alphanumeric characters from it. -Then, use the spread operator (`...`) to split the string into individual characters, `Array.prototype.reverse()`, `String.prototype.join('')` and compare it to the original, unreversed string, after converting it to `String.prototype.toLowerCase()`. - +### palindrome + +Returns `true` if the given string is a palindrome, `false` otherwise. + +Convert the string to `String.prototype.toLowerCase()` and use `String.prototype.replace()` to remove non-alphanumeric characters from it. +Then, use the spread operator (`...`) to split the string into individual characters, `Array.prototype.reverse()`, `String.prototype.join('')` and compare it to the original, unreversed string, after converting it to `String.prototype.toLowerCase()`. + ```js -const palindrome = str => { - const s = str.toLowerCase().replace(/[\W_]/g, ''); - return s === [...s].reverse().join(''); -}; +const palindrome = str => { + const s = str.toLowerCase().replace(/[\W_]/g, ''); + return s === [...s].reverse().join(''); +}; ```
    Examples ```js -palindrome('taco cat'); // true -``` +palindrome('taco cat'); // true +```

    [⬆ Back to top](#contents) -### pluralize - -Returns the singular or plural form of the word based on the input number. If the first argument is an `object`, it will use a closure by returning a function that can auto-pluralize words that don't simply end in `s` if the supplied dictionary contains the word. - -If `num` is either `-1` or `1`, return the singular form of the word. If `num` is any other number, return the plural form. Omit the third argument to use the default of the singular word + `s`, or supply a custom pluralized word when necessary. If the first argument is an `object`, utilize a closure by returning a function which can use the supplied dictionary to resolve the correct plural form of the word. - +### pluralize + +Returns the singular or plural form of the word based on the input number. If the first argument is an `object`, it will use a closure by returning a function that can auto-pluralize words that don't simply end in `s` if the supplied dictionary contains the word. + +If `num` is either `-1` or `1`, return the singular form of the word. If `num` is any other number, return the plural form. Omit the third argument to use the default of the singular word + `s`, or supply a custom pluralized word when necessary. If the first argument is an `object`, utilize a closure by returning a function which can use the supplied dictionary to resolve the correct plural form of the word. + ```js const pluralize = (val, word, plural = word + 's') => { const _pluralize = (num, word, plural = word + 's') => @@ -8195,18 +8198,18 @@ const PLURALS = { }; const autoPluralize = pluralize(PLURALS); autoPluralize(2, 'person'); // 'people' -``` +```
    [⬆ Back to top](#contents) -### removeNonASCII - -Removes non-printable ASCII characters. - -Use a regular expression to remove non-printable ASCII characters. - +### removeNonASCII + +Removes non-printable ASCII characters. + +Use a regular expression to remove non-printable ASCII characters. + ```js const removeNonASCII = str => str.replace(/[^\x20-\x7E]/g, ''); ``` @@ -8216,19 +8219,19 @@ const removeNonASCII = str => str.replace(/[^\x20-\x7E]/g, ''); ```js removeNonASCII('äÄçÇéÉêlorem-ipsumöÖÐþúÚ'); // 'lorem-ipsum' -``` +```
    [⬆ Back to top](#contents) -### reverseString - -Reverses a string. - -Use the spread operator (`...`) and `Array.prototype.reverse()` to reverse the order of the characters in the string. -Combine characters to get a string using `String.prototype.join('')`. - +### reverseString + +Reverses a string. + +Use the spread operator (`...`) and `Array.prototype.reverse()` to reverse the order of the characters in the string. +Combine characters to get a string using `String.prototype.join('')`. + ```js const reverseString = str => [...str].reverse().join(''); ``` @@ -8238,18 +8241,18 @@ const reverseString = str => [...str].reverse().join(''); ```js reverseString('foobar'); // 'raboof' -``` +```
    [⬆ Back to top](#contents) -### sortCharactersInString - -Alphabetically sorts the characters in a string. - -Use the spread operator (`...`), `Array.prototype.sort()` and `String.localeCompare()` to sort the characters in `str`, recombine using `String.prototype.join('')`. - +### sortCharactersInString + +Alphabetically sorts the characters in a string. + +Use the spread operator (`...`), `Array.prototype.sort()` and `String.localeCompare()` to sort the characters in `str`, recombine using `String.prototype.join('')`. + ```js const sortCharactersInString = str => [...str].sort((a, b) => a.localeCompare(b)).join(''); ``` @@ -8259,18 +8262,18 @@ const sortCharactersInString = str => [...str].sort((a, b) => a.localeCompare(b) ```js sortCharactersInString('cabbage'); // 'aabbceg' -``` +```
    [⬆ Back to top](#contents) -### splitLines - -Splits a multiline string into an array of lines. - -Use `String.prototype.split()` and a regular expression to match line breaks and create an array. - +### splitLines + +Splits a multiline string into an array of lines. + +Use `String.prototype.split()` and a regular expression to match line breaks and create an array. + ```js const splitLines = str => str.split(/\r?\n/); ``` @@ -8280,7 +8283,7 @@ const splitLines = str => str.split(/\r?\n/); ```js splitLines('This\nis a\nmultiline\nstring.\n'); // ['This', 'is a', 'multiline', 'string.' , ''] -``` +``` @@ -8321,12 +8324,12 @@ stringPermutations('abc'); // ['abc','acb','bac','bca','cab','cba']
    [⬆ Back to top](#contents) -### stripHTMLTags - -Removes HTML/XML tags from string. - -Use a regular expression to remove HTML/XML tags from a string. - +### stripHTMLTags + +Removes HTML/XML tags from string. + +Use a regular expression to remove HTML/XML tags from a string. + ```js const stripHTMLTags = str => str.replace(/<[^>]*>/g, ''); ``` @@ -8336,18 +8339,18 @@ const stripHTMLTags = str => str.replace(/<[^>]*>/g, ''); ```js stripHTMLTags('

    lorem ipsum

    '); // 'lorem ipsum' -``` +```
    [⬆ Back to top](#contents) -### toCamelCase - -Converts a string to camelcase. - -Break the string into words and combine them capitalizing the first letter of each word, using a regexp. - +### toCamelCase + +Converts a string to camelcase. + +Break the string into words and combine them capitalizing the first letter of each word, using a regexp. + ```js const toCamelCase = str => { let s = @@ -8368,18 +8371,18 @@ toCamelCase('some_database_field_name'); // 'someDatabaseFieldName' toCamelCase('Some label that needs to be camelized'); // 'someLabelThatNeedsToBeCamelized' toCamelCase('some-javascript-property'); // 'someJavascriptProperty' toCamelCase('some-mixed_string with spaces_underscores-and-hyphens'); // 'someMixedStringWithSpacesUnderscoresAndHyphens' -``` +```
    [⬆ Back to top](#contents) -### toKebabCase - -Converts a string to kebab case. - -Break the string into words and combine them adding `-` as a separator, using a regexp. - +### toKebabCase + +Converts a string to kebab case. + +Break the string into words and combine them adding `-` as a separator, using a regexp. + ```js const toKebabCase = str => str && @@ -8398,18 +8401,18 @@ toKebabCase('some text'); // 'some-text' toKebabCase('some-mixed_string With spaces_underscores-and-hyphens'); // 'some-mixed-string-with-spaces-underscores-and-hyphens' toKebabCase('AllThe-small Things'); // "all-the-small-things" toKebabCase('IAmListeningToFMWhileLoadingDifferentURLOnMyBrowserAndAlsoEditingSomeXMLAndHTML'); // "i-am-listening-to-fm-while-loading-different-url-on-my-browser-and-also-editing-xml-and-html" -``` +```
    [⬆ Back to top](#contents) -### toSnakeCase - -Converts a string to snake case. - -Break the string into words and combine them adding `_` as a separator, using a regexp. - +### toSnakeCase + +Converts a string to snake case. + +Break the string into words and combine them adding `_` as a separator, using a regexp. + ```js const toSnakeCase = str => str && @@ -8428,47 +8431,47 @@ toSnakeCase('some text'); // 'some_text' toSnakeCase('some-mixed_string With spaces_underscores-and-hyphens'); // 'some_mixed_string_with_spaces_underscores_and_hyphens' toSnakeCase('AllThe-small Things'); // "all_the_smal_things" toSnakeCase('IAmListeningToFMWhileLoadingDifferentURLOnMyBrowserAndAlsoEditingSomeXMLAndHTML'); // "i_am_listening_to_fm_while_loading_different_url_on_my_browser_and_also_editing_some_xml_and_html" -``` +```
    [⬆ Back to top](#contents) -### toTitleCase - -Converts a string to title case. - -Break the string into words, using a regexp, and combine them capitalizing the first letter of each word and adding a whitespace between them. - +### toTitleCase + +Converts a string to title case. + +Break the string into words, using a regexp, and combine them capitalizing the first letter of each word and adding a whitespace between them. + ```js -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 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(' '); ```
    Examples ```js -toTitleCase('some_database_field_name'); // 'Some Database Field Name' -toTitleCase('Some label that needs to be title-cased'); // 'Some Label That Needs To Be Title Cased' -toTitleCase('some-package-name'); // 'Some Package Name' -toTitleCase('some-mixed_string with spaces_underscores-and-hyphens'); // 'Some Mixed String With Spaces Underscores And Hyphens' -``` +toTitleCase('some_database_field_name'); // 'Some Database Field Name' +toTitleCase('Some label that needs to be title-cased'); // 'Some Label That Needs To Be Title Cased' +toTitleCase('some-package-name'); // 'Some Package Name' +toTitleCase('some-mixed_string with spaces_underscores-and-hyphens'); // 'Some Mixed String With Spaces Underscores And Hyphens' +```

    [⬆ Back to top](#contents) -### truncateString - -Truncates a string up to a specified length. - -Determine if the string's `length` is greater than `num`. -Return the string truncated to the desired length, with `'...'` appended to the end or the original string. - +### truncateString + +Truncates a string up to a specified length. + +Determine if the string's `length` is greater than `num`. +Return the string truncated to the desired length, with `'...'` appended to the end or the original string. + ```js const truncateString = (str, num) => str.length > num ? str.slice(0, num > 3 ? num - 3 : num) + '...' : str; @@ -8479,18 +8482,18 @@ const truncateString = (str, num) => ```js truncateString('boomerang', 7); // 'boom...' -``` +```
    [⬆ Back to top](#contents) -### unescapeHTML - -Unescapes escaped HTML characters. - -Use `String.prototype.replace()` with a regex that matches the characters that need to be unescaped, using a callback function to replace each escaped character instance with its associated unescaped character using a dictionary (object). - +### unescapeHTML + +Unescapes escaped HTML characters. + +Use `String.prototype.replace()` with a regex that matches the characters that need to be unescaped, using a callback function to replace each escaped character instance with its associated unescaped character using a dictionary (object). + ```js const unescapeHTML = str => str.replace( @@ -8511,7 +8514,7 @@ const unescapeHTML = str => ```js unescapeHTML('<a href="#">Me & you</a>'); // 'Me & you' -``` +``` @@ -8546,13 +8549,13 @@ URLJoin('http://www.google.com', 'a', '/b/cd', '?foo=123', '?bar=foo'); // 'http
    [⬆ Back to top](#contents) -### words - -Converts a given string into an array of words. - -Use `String.prototype.split()` with a supplied pattern (defaults to non-alpha as a regexp) to convert to an array of strings. Use `Array.prototype.filter()` to remove any empty strings. -Omit the second argument to use the default regexp. - +### words + +Converts a given string into an array of words. + +Use `String.prototype.split()` with a supplied pattern (defaults to non-alpha as a regexp) to convert to an array of strings. Use `Array.prototype.filter()` to remove any empty strings. +Omit the second argument to use the default regexp. + ```js const words = (str, pattern = /[^a-zA-Z-]+/) => str.split(pattern).filter(Boolean); ``` @@ -8563,7 +8566,7 @@ const words = (str, pattern = /[^a-zA-Z-]+/) => str.split(pattern).filter(Boolea ```js words('I love javaScript!!'); // ["I", "love", "javaScript"] words('python, javaScript & coffee'); // ["python", "javaScript", "coffee"] -``` +``` @@ -8574,12 +8577,12 @@ words('python, javaScript & coffee'); // ["python", "javaScript", "coffee"] ## 📃 Type -### getType - -Returns the native type of a value. - -Returns lowercased constructor name of value, `"undefined"` or `"null"` if value is `undefined` or `null`. - +### getType + +Returns the native type of a value. + +Returns lowercased constructor name of value, `"undefined"` or `"null"` if value is `undefined` or `null`. + ```js const getType = v => v === undefined ? 'undefined' : v === null ? 'null' : v.constructor.name.toLowerCase(); @@ -8590,18 +8593,18 @@ const getType = v => ```js getType(new Set([1, 2, 3])); // 'set' -``` +```
    [⬆ Back to top](#contents) -### is - -Checks if the provided value is of the specified type. - -Ensure the value is not `undefined` or `null` using `Array.prototype.includes()`, and compare the `constructor` property on the value with `type` to check if the provided value is of the specified `type`. - +### is + +Checks if the provided value is of the specified type. + +Ensure the value is not `undefined` or `null` using `Array.prototype.includes()`, and compare the `constructor` property on the value with `type` to check if the provided value is of the specified `type`. + ```js const is = (type, val) => ![, null].includes(val) && val.constructor === type; ``` @@ -8623,18 +8626,18 @@ is(Number, 1); // true is(Number, new Number(1)); // true is(Boolean, true); // true is(Boolean, new Boolean(true)); // true -``` +```
    [⬆ Back to top](#contents) -### isArrayLike - -Checks if the provided argument is array-like (i.e. is iterable). - -Check if the provided argument is not `null` and that its `Symbol.iterator` property is a function. - +### isArrayLike + +Checks if the provided argument is array-like (i.e. is iterable). + +Check if the provided argument is not `null` and that its `Symbol.iterator` property is a function. + ```js const isArrayLike = obj => obj != null && typeof obj[Symbol.iterator] === 'function'; ``` @@ -8646,18 +8649,18 @@ const isArrayLike = obj => obj != null && typeof obj[Symbol.iterator] === 'funct isArrayLike(document.querySelectorAll('.className')); // true isArrayLike('abc'); // true isArrayLike(null); // false -``` +```
    [⬆ Back to top](#contents) -### isBoolean - -Checks if the given argument is a native boolean element. - -Use `typeof` to check if a value is classified as a boolean primitive. - +### isBoolean + +Checks if the given argument is a native boolean element. + +Use `typeof` to check if a value is classified as a boolean primitive. + ```js const isBoolean = val => typeof val === 'boolean'; ``` @@ -8668,18 +8671,18 @@ const isBoolean = val => typeof val === 'boolean'; ```js isBoolean(null); // false isBoolean(false); // true -``` +```
    [⬆ Back to top](#contents) -### isEmpty - -Returns true if the a value is an empty object, collection, map or set, has no enumerable properties or is any type that is not considered a collection. - -Check if the provided value is `null` or if its `length` is equal to `0`. - +### isEmpty + +Returns true if the a value is an empty object, collection, map or set, has no enumerable properties or is any type that is not considered a collection. + +Check if the provided value is `null` or if its `length` is equal to `0`. + ```js const isEmpty = val => val == null || !(Object.keys(val) || val).length; ``` @@ -8698,18 +8701,18 @@ isEmpty({ a: 1, b: 2 }); // false isEmpty('text'); // false isEmpty(123); // true - type is not considered a collection isEmpty(true); // true - type is not considered a collection -``` +```
    [⬆ Back to top](#contents) -### isFunction - -Checks if the given argument is a function. - -Use `typeof` to check if a value is classified as a function primitive. - +### isFunction + +Checks if the given argument is a function. + +Use `typeof` to check if a value is classified as a function primitive. + ```js const isFunction = val => typeof val === 'function'; ``` @@ -8720,18 +8723,18 @@ const isFunction = val => typeof val === 'function'; ```js isFunction('x'); // false isFunction(x => x); // true -``` +```
    [⬆ Back to top](#contents) -### isNil - -Returns `true` if the specified value is `null` or `undefined`, `false` otherwise. - -Use the strict equality operator to check if the value and of `val` are equal to `null` or `undefined`. - +### isNil + +Returns `true` if the specified value is `null` or `undefined`, `false` otherwise. + +Use the strict equality operator to check if the value and of `val` are equal to `null` or `undefined`. + ```js const isNil = val => val === undefined || val === null; ``` @@ -8742,18 +8745,18 @@ const isNil = val => val === undefined || val === null; ```js isNil(null); // true isNil(undefined); // true -``` +```
    [⬆ Back to top](#contents) -### isNull - -Returns `true` if the specified value is `null`, `false` otherwise. - -Use the strict equality operator to check if the value and of `val` are equal to `null`. - +### isNull + +Returns `true` if the specified value is `null`, `false` otherwise. + +Use the strict equality operator to check if the value and of `val` are equal to `null`. + ```js const isNull = val => val === null; ``` @@ -8763,18 +8766,18 @@ const isNull = val => val === null; ```js isNull(null); // true -``` +```
    [⬆ Back to top](#contents) -### isNumber - -Checks if the given argument is a number. - -Use `typeof` to check if a value is classified as a number primitive. - +### isNumber + +Checks if the given argument is a number. + +Use `typeof` to check if a value is classified as a number primitive. + ```js const isNumber = val => typeof val === 'number'; ``` @@ -8785,19 +8788,19 @@ const isNumber = val => typeof val === 'number'; ```js isNumber('1'); // false isNumber(1); // true -``` +```
    [⬆ Back to top](#contents) -### isObject - -Returns a boolean determining if the passed value is an object or not. - -Uses the `Object` constructor to create an object wrapper for the given value. -If the value is `null` or `undefined`, create and return an empty object. Οtherwise, return an object of a type that corresponds to the given value. - +### isObject + +Returns a boolean determining if the passed value is an object or not. + +Uses the `Object` constructor to create an object wrapper for the given value. +If the value is `null` or `undefined`, create and return an empty object. Οtherwise, return an object of a type that corresponds to the given value. + ```js const isObject = obj => obj === Object(obj); ``` @@ -8812,18 +8815,18 @@ isObject(['Hello!']); // true isObject({ a: 1 }); // true isObject({}); // true isObject(true); // false -``` +```
    [⬆ Back to top](#contents) -### isObjectLike - -Checks if a value is object-like. - -Check if the provided value is not `null` and its `typeof` is equal to `'object'`. - +### isObjectLike + +Checks if a value is object-like. + +Check if the provided value is not `null` and its `typeof` is equal to `'object'`. + ```js const isObjectLike = val => val !== null && typeof val === 'object'; ``` @@ -8836,18 +8839,18 @@ isObjectLike({}); // true isObjectLike([1, 2, 3]); // true isObjectLike(x => x); // false isObjectLike(null); // false -``` +```
    [⬆ Back to top](#contents) -### isPlainObject - -Checks if the provided value is an object created by the Object constructor. - -Check if the provided value is truthy, use `typeof` to check if it is an object and `Object.constructor` to make sure the constructor is equal to `Object`. - +### isPlainObject + +Checks if the provided value is an object created by the Object constructor. + +Check if the provided value is truthy, use `typeof` to check if it is an object and `Object.constructor` to make sure the constructor is equal to `Object`. + ```js const isPlainObject = val => !!val && typeof val === 'object' && val.constructor === Object; ``` @@ -8858,44 +8861,44 @@ const isPlainObject = val => !!val && typeof val === 'object' && val.constructor ```js isPlainObject({ a: 1 }); // true isPlainObject(new Map()); // false -``` +```
    [⬆ Back to top](#contents) -### isPrimitive - -Returns a boolean determining if the passed value is primitive or not. - -Create an object from `val` and compare it with `val` to determine if the passed value is primitive (i.e. not equal to the created object). - +### isPrimitive + +Returns a boolean determining if the passed value is primitive or not. + +Create an object from `val` and compare it with `val` to determine if the passed value is primitive (i.e. not equal to the created object). + ```js -const isPrimitive = val => Object(val) !== val; +const isPrimitive = val => Object(val) !== val; ```
    Examples ```js -isPrimitive(null); // true -isPrimitive(50); // true -isPrimitive('Hello!'); // true -isPrimitive(false); // true -isPrimitive(Symbol()); // true -isPrimitive([]); // false -``` +isPrimitive(null); // true +isPrimitive(50); // true +isPrimitive('Hello!'); // true +isPrimitive(false); // true +isPrimitive(Symbol()); // true +isPrimitive([]); // false +```

    [⬆ Back to top](#contents) -### isPromiseLike - -Returns `true` if an object looks like a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise), `false` otherwise. - -Check if the object is not `null`, its `typeof` matches either `object` or `function` and if it has a `.then` property, which is also a `function`. - +### isPromiseLike + +Returns `true` if an object looks like a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise), `false` otherwise. + +Check if the object is not `null`, its `typeof` matches either `object` or `function` and if it has a `.then` property, which is also a `function`. + ```js const isPromiseLike = obj => obj !== null && @@ -8914,39 +8917,39 @@ isPromiseLike({ }); // true isPromiseLike(null); // false isPromiseLike({}); // false -``` +```
    [⬆ Back to top](#contents) -### isString - -Checks if the given argument is a string. Only works for string primitives. - -Use `typeof` to check if a value is classified as a string primitive. - +### isString + +Checks if the given argument is a string. Only works for string primitives. + +Use `typeof` to check if a value is classified as a string primitive. + ```js -const isString = val => typeof val === 'string'; +const isString = val => typeof val === 'string'; ```
    Examples ```js -isString('10'); // true -``` +isString('10'); // true +```

    [⬆ Back to top](#contents) -### isSymbol - -Checks if the given argument is a symbol. - -Use `typeof` to check if a value is classified as a symbol primitive. - +### isSymbol + +Checks if the given argument is a symbol. + +Use `typeof` to check if a value is classified as a symbol primitive. + ```js const isSymbol = val => typeof val === 'symbol'; ``` @@ -8956,18 +8959,18 @@ const isSymbol = val => typeof val === 'symbol'; ```js isSymbol(Symbol('x')); // true -``` +```
    [⬆ Back to top](#contents) -### isUndefined - -Returns `true` if the specified value is `undefined`, `false` otherwise. - -Use the strict equality operator to check if the value and of `val` are equal to `undefined`. - +### isUndefined + +Returns `true` if the specified value is `undefined`, `false` otherwise. + +Use the strict equality operator to check if the value and of `val` are equal to `undefined`. + ```js const isUndefined = val => val === undefined; ``` @@ -8977,37 +8980,37 @@ const isUndefined = val => val === undefined; ```js isUndefined(undefined); // true -``` +```
    [⬆ Back to top](#contents) -### isValidJSON - -Checks if the provided string is a valid JSON. - -Use `JSON.parse()` and a `try... catch` block to check if the provided string is a valid JSON. - +### isValidJSON + +Checks if the provided string is a valid JSON. + +Use `JSON.parse()` and a `try... catch` block to check if the provided string is a valid JSON. + ```js -const isValidJSON = str => { - try { - JSON.parse(str); - return true; - } catch (e) { - return false; - } -}; +const isValidJSON = str => { + try { + JSON.parse(str); + return true; + } catch (e) { + return false; + } +}; ```
    Examples ```js -isValidJSON('{"name":"Adam","age":20}'); // true -isValidJSON('{"name":"Adam",age:"20"}'); // false -isValidJSON(null); // true -``` +isValidJSON('{"name":"Adam","age":20}'); // true +isValidJSON('{"name":"Adam",age:"20"}'); // false +isValidJSON(null); // true +```
    @@ -9018,12 +9021,12 @@ isValidJSON(null); // true ## 🔧 Utility -### castArray - -Casts the provided value as an array if it's not one. - -Use `Array.prototype.isArray()` to determine if `val` is an array and return it as-is or encapsulated in an array accordingly. - +### castArray + +Casts the provided value as an array if it's not one. + +Use `Array.prototype.isArray()` to determine if `val` is an array and return it as-is or encapsulated in an array accordingly. + ```js const castArray = val => (Array.isArray(val) ? val : [val]); ``` @@ -9034,18 +9037,18 @@ const castArray = val => (Array.isArray(val) ? val : [val]); ```js castArray('foo'); // ['foo'] castArray([1]); // [1] -``` +```
    [⬆ Back to top](#contents) -### cloneRegExp - -Clones a regular expression. - -Use `new RegExp()`, `RegExp.source` and `RegExp.flags` to clone the given regular expression. - +### cloneRegExp + +Clones a regular expression. + +Use `new RegExp()`, `RegExp.source` and `RegExp.flags` to clone the given regular expression. + ```js const cloneRegExp = regExp => new RegExp(regExp.source, regExp.flags); ``` @@ -9056,18 +9059,18 @@ const cloneRegExp = regExp => new RegExp(regExp.source, regExp.flags); ```js const regExp = /lorem ipsum/gi; const regExp2 = cloneRegExp(regExp); // /lorem ipsum/gi -``` +```
    [⬆ Back to top](#contents) -### coalesce - -Returns the first non-null/undefined argument. - -Use `Array.prototype.find()` to return the first non `null`/`undefined` argument. - +### coalesce + +Returns the first non-null/undefined argument. + +Use `Array.prototype.find()` to return the first non `null`/`undefined` argument. + ```js const coalesce = (...args) => args.find(_ => ![undefined, null].includes(_)); ``` @@ -9077,18 +9080,18 @@ const coalesce = (...args) => args.find(_ => ![undefined, null].includes(_)); ```js coalesce(null, undefined, '', NaN, 'Waldo'); // "" -``` +```
    [⬆ Back to top](#contents) -### coalesceFactory - -Returns a customized coalesce function that returns the first argument that returns `true` from the provided argument validation function. - -Use `Array.prototype.find()` to return the first argument that returns `true` from the provided argument validation function. - +### coalesceFactory + +Returns a customized coalesce function that returns the first argument that returns `true` from the provided argument validation function. + +Use `Array.prototype.find()` to return the first argument that returns `true` from the provided argument validation function. + ```js const coalesceFactory = valid => (...args) => args.find(valid); ``` @@ -9099,19 +9102,19 @@ const coalesceFactory = valid => (...args) => args.find(valid); ```js const customCoalesce = coalesceFactory(_ => ![null, undefined, '', NaN].includes(_)); customCoalesce(undefined, null, NaN, '', 'Waldo'); // "Waldo" -``` +```
    [⬆ Back to top](#contents) -### extendHex - -Extends a 3-digit color code to a 6-digit color code. - -Use `Array.prototype.map()`, `String.prototype.split()` and `Array.prototype.join()` to join the mapped array for converting a 3-digit RGB notated hexadecimal color-code to the 6-digit form. -`Array.prototype.slice()` is used to remove `#` from string start since it's added once. - +### extendHex + +Extends a 3-digit color code to a 6-digit color code. + +Use `Array.prototype.map()`, `String.prototype.split()` and `Array.prototype.join()` to join the mapped array for converting a 3-digit RGB notated hexadecimal color-code to the 6-digit form. +`Array.prototype.slice()` is used to remove `#` from string start since it's added once. + ```js const extendHex = shortHex => '#' + @@ -9128,19 +9131,19 @@ const extendHex = shortHex => ```js extendHex('#03f'); // '#0033ff' extendHex('05a'); // '#0055aa' -``` +```
    [⬆ Back to top](#contents) -### getURLParameters - -Returns an object containing the parameters of the current URL. - -Use `String.match()` with an appropriate regular expression to get all key-value pairs, `Array.prototype.reduce()` to map and combine them into a single object. -Pass `location.search` as the argument to apply to the current `url`. - +### getURLParameters + +Returns an object containing the parameters of the current URL. + +Use `String.match()` with an appropriate regular expression to get all key-value pairs, `Array.prototype.reduce()` to map and combine them into a single object. +Pass `location.search` as the argument to apply to the current `url`. + ```js const getURLParameters = url => (url.match(/([^?=&]+)(=([^&]*))/g) || []).reduce( @@ -9155,7 +9158,7 @@ const getURLParameters = url => ```js getURLParameters('http://url.com/page?name=Adam&surname=Smith'); // {name: 'Adam', surname: 'Smith'} getURLParameters('google.com'); // {} -``` +``` @@ -9202,114 +9205,114 @@ hexToRGB('#fff'); // 'rgb(255, 255, 255)'
    [⬆ Back to top](#contents) -### httpGet - -Makes a `GET` request to the passed URL. - -Use [`XMLHttpRequest`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest) web api to make a `get` request to the given `url`. -Handle the `onload` event, by calling the given `callback` the `responseText`. -Handle the `onerror` event, by running the provided `err` function. -Omit the third argument, `err`, to log errors to the console's `error` stream by default. - +### httpGet + +Makes a `GET` request to the passed URL. + +Use [`XMLHttpRequest`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest) web api to make a `get` request to the given `url`. +Handle the `onload` event, by calling the given `callback` the `responseText`. +Handle the `onerror` event, by running the provided `err` function. +Omit the third argument, `err`, to log errors to the console's `error` stream by default. + ```js -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 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(); +}; ```
    Examples ```js -httpGet( - 'https://jsonplaceholder.typicode.com/posts/1', - console.log -); /* -Logs: { - "userId": 1, - "id": 1, - "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", - "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" -} -*/ -``` +httpGet( + 'https://jsonplaceholder.typicode.com/posts/1', + console.log +); /* +Logs: { + "userId": 1, + "id": 1, + "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", + "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita et cum\nreprehenderit molestiae ut ut quas totam\nnostrum rerum est autem sunt rem eveniet architecto" +} +*/ +```

    [⬆ Back to top](#contents) -### httpPost - -Makes a `POST` request to the passed URL. - -Use [`XMLHttpRequest`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest) web api to make a `post` request to the given `url`. -Set the value of an `HTTP` request header with `setRequestHeader` method. -Handle the `onload` event, by calling the given `callback` the `responseText`. -Handle the `onerror` event, by running the provided `err` function. -Omit the third argument, `data`, to send no data to the provided `url`. -Omit the fourth argument, `err`, to log errors to the console's `error` stream by default. - +### httpPost + +Makes a `POST` request to the passed URL. + +Use [`XMLHttpRequest`](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest) web api to make a `post` request to the given `url`. +Set the value of an `HTTP` request header with `setRequestHeader` method. +Handle the `onload` event, by calling the given `callback` the `responseText`. +Handle the `onerror` event, by running the provided `err` function. +Omit the third argument, `data`, to send no data to the provided `url`. +Omit the fourth argument, `err`, to log errors to the console's `error` stream by default. + ```js -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'); - request.onload = () => callback(request.responseText); - request.onerror = () => err(request); - request.send(data); -}; +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'); + request.onload = () => callback(request.responseText); + request.onerror = () => err(request); + request.send(data); +}; ```
    Examples ```js -const newPost = { - userId: 1, - id: 1337, - title: 'Foo', - body: 'bar bar bar' -}; -const data = JSON.stringify(newPost); -httpPost( - 'https://jsonplaceholder.typicode.com/posts', - data, - console.log -); /* -Logs: { - "userId": 1, - "id": 1337, - "title": "Foo", - "body": "bar bar bar" -} -*/ -httpPost( - 'https://jsonplaceholder.typicode.com/posts', - null, // does not send a body - console.log -); /* -Logs: { - "id": 101 -} -*/ -``` +const newPost = { + userId: 1, + id: 1337, + title: 'Foo', + body: 'bar bar bar' +}; +const data = JSON.stringify(newPost); +httpPost( + 'https://jsonplaceholder.typicode.com/posts', + data, + console.log +); /* +Logs: { + "userId": 1, + "id": 1337, + "title": "Foo", + "body": "bar bar bar" +} +*/ +httpPost( + 'https://jsonplaceholder.typicode.com/posts', + null, // does not send a body + console.log +); /* +Logs: { + "id": 101 +} +*/ +```

    [⬆ Back to top](#contents) -### isBrowser - -Determines if the current runtime environment is a browser so that front-end modules can run on the server (Node) without throwing errors. - -Use `Array.prototype.includes()` on the `typeof` values of both `window` and `document` (globals usually only available in a browser environment unless they were explicitly defined), which will return `true` if one of them is `undefined`. -`typeof` allows globals to be checked for existence without throwing a `ReferenceError`. -If both of them are not `undefined`, then the current environment is assumed to be a browser. - +### isBrowser + +Determines if the current runtime environment is a browser so that front-end modules can run on the server (Node) without throwing errors. + +Use `Array.prototype.includes()` on the `typeof` values of both `window` and `document` (globals usually only available in a browser environment unless they were explicitly defined), which will return `true` if one of them is `undefined`. +`typeof` allows globals to be checked for existence without throwing a `ReferenceError`. +If both of them are not `undefined`, then the current environment is assumed to be a browser. + ```js const isBrowser = () => ![typeof window, typeof document].includes('undefined'); ``` @@ -9320,20 +9323,20 @@ const isBrowser = () => ![typeof window, typeof document].includes('undefined'); ```js isBrowser(); // true (browser) isBrowser(); // false (Node) -``` +```
    [⬆ Back to top](#contents) -### mostPerformant - -Returns the index of the function in an array of functions which executed the fastest. - -Use `Array.prototype.map()` to generate an array where each value is the total time taken to execute the function after `iterations` times. Use the difference in `performance.now()` values before and after to get the total time in milliseconds to a high degree of accuracy. -Use `Math.min()` to find the minimum execution time, and return the index of that shortest time which corresponds to the index of the most performant function. -Omit the second argument, `iterations`, to use a default of 10,000 iterations. The more iterations, the more reliable the result but the longer it will take. - +### mostPerformant + +Returns the index of the function in an array of functions which executed the fastest. + +Use `Array.prototype.map()` to generate an array where each value is the total time taken to execute the function after `iterations` times. Use the difference in `performance.now()` values before and after to get the total time in milliseconds to a high degree of accuracy. +Use `Math.min()` to find the minimum execution time, and return the index of that shortest time which corresponds to the index of the most performant function. +Omit the second argument, `iterations`, to use a default of 10,000 iterations. The more iterations, the more reliable the result but the longer it will take. + ```js const mostPerformant = (fns, iterations = 10000) => { const times = fns.map(fn => { @@ -9359,18 +9362,18 @@ mostPerformant([ [1, '2', 3, 4, 5, 6, 7, 8, 9, 10].every(el => typeof el === 'number'); } ]); // 1 -``` +```
    [⬆ Back to top](#contents) -### nthArg - -Creates a function that gets the argument at index `n`. If `n` is negative, the nth argument from the end is returned. - -Use `Array.prototype.slice()` to get the desired argument at index `n`. - +### nthArg + +Creates a function that gets the argument at index `n`. If `n` is negative, the nth argument from the end is returned. + +Use `Array.prototype.slice()` to get the desired argument at index `n`. + ```js const nthArg = n => (...args) => args.slice(n)[0]; ``` @@ -9384,20 +9387,20 @@ third(1, 2, 3); // 3 third(1, 2); // undefined const last = nthArg(-1); last(1, 2, 3, 4, 5); // 5 -``` +```
    [⬆ Back to top](#contents) -### parseCookie - -Parse an HTTP Cookie header string and return an object of all cookie name-value pairs. - -Use `String.prototype.split(';')` to separate key-value pairs from each other. -Use `Array.prototype.map()` and `String.prototype.split('=')` to separate keys from values in each pair. -Use `Array.prototype.reduce()` and `decodeURIComponent()` to create an object with all key-value pairs. - +### parseCookie + +Parse an HTTP Cookie header string and return an object of all cookie name-value pairs. + +Use `String.prototype.split(';')` to separate key-value pairs from each other. +Use `Array.prototype.map()` and `String.prototype.split('=')` to separate keys from values in each pair. +Use `Array.prototype.reduce()` and `decodeURIComponent()` to create an object with all key-value pairs. + ```js const parseCookie = str => str @@ -9414,7 +9417,7 @@ const parseCookie = str => ```js parseCookie('foo=bar; equation=E%3Dmc%5E2'); // { foo: 'bar', equation: 'E=mc^2' } -``` +``` @@ -9453,12 +9456,12 @@ prettyBytes(123456789, 3, false); // "123MB"
    [⬆ Back to top](#contents) -### randomHexColorCode - -Generates a random hexadecimal color code. - -Use `Math.random` to generate a random 24-bit(6x4bits) hexadecimal number. Use bit shifting and then convert it to an hexadecimal String using `toString(16)`. - +### randomHexColorCode + +Generates a random hexadecimal color code. + +Use `Math.random` to generate a random 24-bit(6x4bits) hexadecimal number. Use bit shifting and then convert it to an hexadecimal String using `toString(16)`. + ```js const randomHexColorCode = () => { let n = (Math.random() * 0xfffff * 1000000).toString(16); @@ -9471,18 +9474,18 @@ const randomHexColorCode = () => { ```js randomHexColorCode(); // "#e34155" -``` +```
    [⬆ Back to top](#contents) -### RGBToHex - -Converts the values of RGB components to a color code. - -Convert given RGB parameters to hexadecimal string using bitwise left-shift operator (`<<`) and `toString(16)`, then `String.padStart(6,'0')` to get a 6-digit hexadecimal value. - +### RGBToHex + +Converts the values of RGB components to a color code. + +Convert given RGB parameters to hexadecimal string using bitwise left-shift operator (`<<`) and `toString(16)`, then `String.padStart(6,'0')` to get a 6-digit hexadecimal value. + ```js const RGBToHex = (r, g, b) => ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0'); ``` @@ -9492,18 +9495,18 @@ const RGBToHex = (r, g, b) => ((r << 16) + (g << 8) + b).toString(16).padStart(6 ```js RGBToHex(255, 165, 1); // 'ffa501' -``` +```
    [⬆ Back to top](#contents) -### serializeCookie - -Serialize a cookie name-value pair into a Set-Cookie header string. - -Use template literals and `encodeURIComponent()` to create the appropriate string. - +### serializeCookie + +Serialize a cookie name-value pair into a Set-Cookie header string. + +Use template literals and `encodeURIComponent()` to create the appropriate string. + ```js const serializeCookie = (name, val) => `${encodeURIComponent(name)}=${encodeURIComponent(val)}`; ``` @@ -9513,18 +9516,18 @@ const serializeCookie = (name, val) => `${encodeURIComponent(name)}=${encodeURIC ```js serializeCookie('foo', 'bar'); // 'foo=bar' -``` +```
    [⬆ Back to top](#contents) -### timeTaken - -Measures the time taken by a function to execute. - -Use `console.time()` and `console.timeEnd()` to measure the difference between the start and end times to determine how long the callback took to execute. - +### timeTaken + +Measures the time taken by a function to execute. + +Use `console.time()` and `console.timeEnd()` to measure the difference between the start and end times to determine how long the callback took to execute. + ```js const timeTaken = callback => { console.time('timeTaken'); @@ -9539,18 +9542,18 @@ const timeTaken = callback => { ```js timeTaken(() => Math.pow(2, 10)); // 1024, (logged): timeTaken: 0.02099609375ms -``` +```
    [⬆ Back to top](#contents) -### toCurrency - -Take a number and return specified currency formatting. - -Use `Intl.NumberFormat` to enable country / currency sensitive formatting. - +### toCurrency + +Take a number and return specified currency formatting. + +Use `Intl.NumberFormat` to enable country / currency sensitive formatting. + ```js const toCurrency = (n, curr, LanguageFormat = undefined) => Intl.NumberFormat(LanguageFormat, { style: 'currency', currency: curr }).format(n); @@ -9565,16 +9568,16 @@ toCurrency(123456.789, 'USD', 'en-us'); // $123,456.79 | currency: US Dollar | toCurrency(123456.789, 'USD', 'fa'); // ۱۲۳٬۴۵۶٫۷۹ ؜$ | currency: US Dollar | currencyLangFormat: Farsi toCurrency(322342436423.2435, 'JPY'); // ¥322,342,436,423 | currency: Japanese Yen | currencyLangFormat: Local toCurrency(322342436423.2435, 'JPY', 'fi'); // 322 342 436 423 ¥ | currency: Japanese Yen | currencyLangFormat: Finnish -``` +```
    [⬆ Back to top](#contents) -### toDecimalMark - -Use `toLocaleString()` to convert a float-point arithmetic to the [Decimal mark](https://en.wikipedia.org/wiki/Decimal_mark) form. It makes a comma separated string from a number. - +### toDecimalMark + +Use `toLocaleString()` to convert a float-point arithmetic to the [Decimal mark](https://en.wikipedia.org/wiki/Decimal_mark) form. It makes a comma separated string from a number. + ```js const toDecimalMark = num => num.toLocaleString('en-US'); ``` @@ -9584,20 +9587,20 @@ const toDecimalMark = num => num.toLocaleString('en-US'); ```js toDecimalMark(12305030388.9087); // "12,305,030,388.909" -``` +```
    [⬆ Back to top](#contents) -### toOrdinalSuffix - -Adds an ordinal suffix to a number. - -Use the modulo operator (`%`) to find values of single and tens digits. -Find which ordinal pattern digits match. -If digit is found in teens pattern, use teens ordinal. - +### toOrdinalSuffix + +Adds an ordinal suffix to a number. + +Use the modulo operator (`%`) to find values of single and tens digits. +Find which ordinal pattern digits match. +If digit is found in teens pattern, use teens ordinal. + ```js const toOrdinalSuffix = num => { const int = parseInt(num), @@ -9616,20 +9619,20 @@ const toOrdinalSuffix = num => { ```js toOrdinalSuffix('123'); // "123rd" -``` +```
    [⬆ Back to top](#contents) -### validateNumber - -Returns `true` if the given value is a number, `false` otherwise. - -Use `!isNaN()` in combination with `parseFloat()` to check if the argument is a number. -Use `isFinite()` to check if the number is finite. -Use `Number()` to check if the coercion holds. - +### validateNumber + +Returns `true` if the given value is a number, `false` otherwise. + +Use `!isNaN()` in combination with `parseFloat()` to check if the argument is a number. +Use `isFinite()` to check if the number is finite. +Use `Number()` to check if the coercion holds. + ```js const validateNumber = n => !isNaN(parseFloat(n)) && isFinite(n) && Number(n) == n; ``` @@ -9639,19 +9642,19 @@ const validateNumber = n => !isNaN(parseFloat(n)) && isFinite(n) && Number(n) == ```js validateNumber('10'); // true -``` +```
    [⬆ Back to top](#contents) -### yesNo - -Returns `true` if the string is `y`/`yes` or `false` if the string is `n`/`no`. - -Use `RegExp.test()` to check if the string evaluates to `y/yes` or `n/no`. -Omit the second argument, `def` to set the default answer as `no`. - +### yesNo + +Returns `true` if the string is `y`/`yes` or `false` if the string is `n`/`no`. + +Use `RegExp.test()` to check if the string evaluates to `y/yes` or `n/no`. +Omit the second argument, `def` to set the default answer as `no`. + ```js const yesNo = (val, def = false) => /^(y|yes)$/i.test(val) ? true : /^(n|no)$/i.test(val) ? false : def; @@ -9665,22 +9668,22 @@ yesNo('Y'); // true yesNo('yes'); // true yesNo('No'); // false yesNo('Foo', true); // true -``` +```
    [⬆ Back to top](#contents) -## Collaborators - -| [](https://github.com/Chalarangelo)
    [Angelos Chalaris](https://github.com/Chalarangelo) | [](https://github.com/flxwu)
    [Felix Wu](https://github.com/Pl4gue) | [](https://github.com/fejes713)
    [Stefan Feješ](https://github.com/fejes713) | [](https://github.com/kingdavidmartins)
    [King David Martins](https://github.com/iamsoorena) | [](https://github.com/iamsoorena)
    [Soorena Soleimani](https://github.com/iamsoorena) | -| --- | --- | --- | --- | --- | -| [](https://github.com/elderhsouza)
    [Elder Henrique Souza](https://github.com/elderhsouza) | [](https://github.com/skatcat31)
    [Robert Mennell](https://github.com/skatcat31) | [](https://github.com/atomiks)
    [atomiks](https://github.com/atomiks) | - - -## Credits - -*Logos made by [Angelos Chalaris](https://github.com/Chalarangelo) are licensed under the [MIT](https://opensource.org/licenses/MIT) license.* -*This README is built using [markdown-builder](https://github.com/30-seconds/markdown-builder).* +## Collaborators + +| [](https://github.com/Chalarangelo)
    [Angelos Chalaris](https://github.com/Chalarangelo) | [](https://github.com/flxwu)
    [Felix Wu](https://github.com/Pl4gue) | [](https://github.com/fejes713)
    [Stefan Feješ](https://github.com/fejes713) | [](https://github.com/kingdavidmartins)
    [King David Martins](https://github.com/iamsoorena) | [](https://github.com/iamsoorena)
    [Soorena Soleimani](https://github.com/iamsoorena) | +| --- | --- | --- | --- | --- | +| [](https://github.com/elderhsouza)
    [Elder Henrique Souza](https://github.com/elderhsouza) | [](https://github.com/skatcat31)
    [Robert Mennell](https://github.com/skatcat31) | [](https://github.com/atomiks)
    [atomiks](https://github.com/atomiks) | + + +## Credits + +*Logos made by [Angelos Chalaris](https://github.com/Chalarangelo) are licensed under the [MIT](https://opensource.org/licenses/MIT) license.* +*This README is built using [markdown-builder](https://github.com/30-seconds/markdown-builder).* diff --git a/dist/_30s.es5.js b/dist/_30s.es5.js index 60ab509f0..44d325b23 100644 --- a/dist/_30s.es5.js +++ b/dist/_30s.es5.js @@ -118,54 +118,6 @@ var crypto = typeof require !== "undefined" && require('crypto'); - var CSVToArray = function CSVToArray(data) { - var delimiter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ','; - var omitFirstRow = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; - return data.slice(omitFirstRow ? data.indexOf('\n') + 1 : 0).split('\n').map(function (v) { - return v.split(delimiter); - }); - }; - var CSVToJSON = function CSVToJSON(data) { - var delimiter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ','; - var titles = data.slice(0, data.indexOf('\n')).split(delimiter); - return data.slice(data.indexOf('\n') + 1).split('\n').map(function (v) { - var values = v.split(delimiter); - return titles.reduce(function (obj, title, index) { - return obj[title] = values[index], obj; - }, {}); - }); - }; - var JSONToFile = function JSONToFile(obj, filename) { - return fs.writeFile("".concat(filename, ".json"), JSON.stringify(obj, null, 2)); - }; - var JSONtoCSV = function JSONtoCSV(arr, columns) { - var delimiter = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ','; - return [columns.join(delimiter)].concat(_toConsumableArray(arr.map(function (obj) { - return columns.reduce(function (acc, key) { - return "".concat(acc).concat(!acc.length ? '' : delimiter, "\"").concat(!obj[key] ? '' : obj[key], "\""); - }, ''); - }))).join('\n'); - }; - var RGBToHex = function RGBToHex(r, g, b) { - return ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0'); - }; - var URLJoin = function URLJoin() { - for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - return args.join('/').replace(/[\/]+/g, '/').replace(/^(.+):\//, '$1://').replace(/^file:/, 'file:/').replace(/\/(\?|&|#[^!])/g, '$1').replace(/\?/g, '&').replace('&', '?'); - }; - var UUIDGeneratorBrowser = function UUIDGeneratorBrowser() { - return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function (c) { - return (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16); - }); - }; - var UUIDGeneratorNode = function UUIDGeneratorNode() { - return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function (c) { - return (c ^ crypto.randomBytes(1)[0] & 15 >> c / 4).toString(16); - }); - }; var all = function all(arr) { var fn = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : Boolean; return arr.every(fn); @@ -200,8 +152,8 @@ }; var ary = function ary(fn, n) { return function () { - for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - args[_key2] = arguments[_key2]; + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; } return fn.apply(void 0, _toConsumableArray(args.slice(0, n))); @@ -212,8 +164,8 @@ }; var attempt = function attempt(fn) { try { - for (var _len3 = arguments.length, args = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { - args[_key3 - 1] = arguments[_key3]; + for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { + args[_key2 - 1] = arguments[_key2]; } return fn.apply(void 0, args); @@ -222,8 +174,8 @@ } }; var average = function average() { - for (var _len4 = arguments.length, nums = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { - nums[_key4] = arguments[_key4]; + for (var _len3 = arguments.length, nums = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + nums[_key3] = arguments[_key3]; } return nums.reduce(function (acc, val) { @@ -248,21 +200,21 @@ }, [[], []]); }; var bind = function bind(fn, context) { - for (var _len5 = arguments.length, boundArgs = new Array(_len5 > 2 ? _len5 - 2 : 0), _key5 = 2; _key5 < _len5; _key5++) { - boundArgs[_key5 - 2] = arguments[_key5]; + for (var _len4 = arguments.length, boundArgs = new Array(_len4 > 2 ? _len4 - 2 : 0), _key4 = 2; _key4 < _len4; _key4++) { + boundArgs[_key4 - 2] = arguments[_key4]; } return function () { - for (var _len6 = arguments.length, args = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { - args[_key6] = arguments[_key6]; + for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { + args[_key5] = arguments[_key5]; } return fn.apply(context, boundArgs.concat(args)); }; }; var bindAll = function bindAll(obj) { - for (var _len7 = arguments.length, fns = new Array(_len7 > 1 ? _len7 - 1 : 0), _key7 = 1; _key7 < _len7; _key7++) { - fns[_key7 - 1] = arguments[_key7]; + for (var _len6 = arguments.length, fns = new Array(_len6 > 1 ? _len6 - 1 : 0), _key6 = 1; _key6 < _len6; _key6++) { + fns[_key6 - 1] = arguments[_key6]; } return fns.forEach(function (fn) { @@ -272,13 +224,13 @@ }); }; var bindKey = function bindKey(context, fn) { - for (var _len8 = arguments.length, boundArgs = new Array(_len8 > 2 ? _len8 - 2 : 0), _key8 = 2; _key8 < _len8; _key8++) { - boundArgs[_key8 - 2] = arguments[_key8]; + for (var _len7 = arguments.length, boundArgs = new Array(_len7 > 2 ? _len7 - 2 : 0), _key7 = 2; _key7 < _len7; _key7++) { + boundArgs[_key7 - 2] = arguments[_key7]; } return function () { - for (var _len9 = arguments.length, args = new Array(_len9), _key9 = 0; _key9 < _len9; _key9++) { - args[_key9] = arguments[_key9]; + for (var _len8 = arguments.length, args = new Array(_len8), _key8 = 0; _key8 < _len8; _key8++) { + args[_key8] = arguments[_key8]; } return context[fn].apply(context, boundArgs.concat(args)); @@ -308,8 +260,8 @@ return new Blob([str]).size; }; var call = function call(key) { - for (var _len10 = arguments.length, args = new Array(_len10 > 1 ? _len10 - 1 : 0), _key10 = 1; _key10 < _len10; _key10++) { - args[_key10 - 1] = arguments[_key10]; + for (var _len9 = arguments.length, args = new Array(_len9 > 1 ? _len9 - 1 : 0), _key9 = 1; _key9 < _len9; _key9++) { + args[_key9 - 1] = arguments[_key9]; } return function (context) { @@ -357,8 +309,8 @@ return new RegExp(regExp.source, regExp.flags); }; var coalesce = function coalesce() { - for (var _len11 = arguments.length, args = new Array(_len11), _key11 = 0; _key11 < _len11; _key11++) { - args[_key11] = arguments[_key11]; + for (var _len10 = arguments.length, args = new Array(_len10), _key10 = 0; _key10 < _len10; _key10++) { + args[_key10] = arguments[_key10]; } return args.find(function (_) { @@ -367,8 +319,8 @@ }; var coalesceFactory = function coalesceFactory(valid) { return function () { - for (var _len12 = arguments.length, args = new Array(_len12), _key12 = 0; _key12 < _len12; _key12++) { - args[_key12] = arguments[_key12]; + for (var _len11 = arguments.length, args = new Array(_len11), _key11 = 0; _key11 < _len11; _key11++) { + args[_key11] = arguments[_key11]; } return args.find(valid); @@ -376,16 +328,16 @@ }; var collectInto = function collectInto(fn) { return function () { - for (var _len13 = arguments.length, args = new Array(_len13), _key13 = 0; _key13 < _len13; _key13++) { - args[_key13] = arguments[_key13]; + for (var _len12 = arguments.length, args = new Array(_len12), _key12 = 0; _key12 < _len12; _key12++) { + args[_key12] = arguments[_key12]; } return fn(args); }; }; var colorize = function colorize() { - for (var _len14 = arguments.length, args = new Array(_len14), _key14 = 0; _key14 < _len14; _key14++) { - args[_key14] = arguments[_key14]; + for (var _len13 = arguments.length, args = new Array(_len13), _key13 = 0; _key13 < _len13; _key13++) { + args[_key13] = arguments[_key13]; } return { @@ -414,8 +366,8 @@ return str.replace(/\s{2,}/g, ' '); }; var compose = function compose() { - for (var _len15 = arguments.length, fns = new Array(_len15), _key15 = 0; _key15 < _len15; _key15++) { - fns[_key15] = arguments[_key15]; + for (var _len14 = arguments.length, fns = new Array(_len14), _key14 = 0; _key14 < _len14; _key14++) { + fns[_key14] = arguments[_key14]; } return fns.reduce(function (f, g) { @@ -425,8 +377,8 @@ }); }; var composeRight = function composeRight() { - for (var _len16 = arguments.length, fns = new Array(_len16), _key16 = 0; _key16 < _len16; _key16++) { - fns[_key16] = arguments[_key16]; + for (var _len15 = arguments.length, fns = new Array(_len15), _key15 = 0; _key15 < _len15; _key15++) { + fns[_key15] = arguments[_key15]; } return fns.reduce(function (f, g) { @@ -437,8 +389,8 @@ }; var converge = function converge(converger, fns) { return function () { - for (var _len17 = arguments.length, args = new Array(_len17), _key17 = 0; _key17 < _len17; _key17++) { - args[_key17] = arguments[_key17]; + for (var _len16 = arguments.length, args = new Array(_len16), _key16 = 0; _key16 < _len16; _key16++) { + args[_key16] = arguments[_key16]; } return converger.apply(void 0, _toConsumableArray(fns.map(function (fn) { @@ -471,11 +423,6 @@ return acc; }, {}); }; - var countOccurrences = function countOccurrences(arr, val) { - return arr.reduce(function (a, v) { - return v === val ? a + 1 : a; - }, 0); - }; var counter = function counter(selector, start, end) { var step = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : 1; var duration = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : 2000; @@ -491,6 +438,11 @@ return timer; }; + var countOccurrences = function countOccurrences(arr, val) { + return arr.reduce(function (a, v) { + return v === val ? a + 1 : a; + }, 0); + }; var createDirIfNotExists = function createDirIfNotExists(dir) { return !fs.existsSync(dir) ? fs.mkdirSync(dir) : undefined; }; @@ -519,14 +471,31 @@ } }; }; + var CSVToArray = function CSVToArray(data) { + var delimiter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ','; + var omitFirstRow = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; + return data.slice(omitFirstRow ? data.indexOf('\n') + 1 : 0).split('\n').map(function (v) { + return v.split(delimiter); + }); + }; + var CSVToJSON = function CSVToJSON(data) { + var delimiter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ','; + var titles = data.slice(0, data.indexOf('\n')).split(delimiter); + return data.slice(data.indexOf('\n') + 1).split('\n').map(function (v) { + var values = v.split(delimiter); + return titles.reduce(function (obj, title, index) { + return obj[title] = values[index], obj; + }, {}); + }); + }; var currentURL = function currentURL() { return window.location.href; }; var curry = function curry(fn) { var arity = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : fn.length; - for (var _len18 = arguments.length, args = new Array(_len18 > 2 ? _len18 - 2 : 0), _key18 = 2; _key18 < _len18; _key18++) { - args[_key18 - 2] = arguments[_key18]; + for (var _len17 = arguments.length, args = new Array(_len17 > 2 ? _len17 - 2 : 0), _key17 = 2; _key17 < _len17; _key17++) { + args[_key17 - 2] = arguments[_key17]; } return arity <= args.length ? fn.apply(void 0, args) : curry.bind.apply(curry, [null, fn, arity].concat(args)); @@ -540,8 +509,8 @@ return function () { var _this = this; - for (var _len19 = arguments.length, args = new Array(_len19), _key19 = 0; _key19 < _len19; _key19++) { - args[_key19] = arguments[_key19]; + for (var _len18 = arguments.length, args = new Array(_len18), _key18 = 0; _key18 < _len18; _key18++) { + args[_key18] = arguments[_key18]; } clearTimeout(timeoutId); @@ -563,7 +532,7 @@ Object.keys(clone).forEach(function (key) { return clone[key] = _typeof(obj[key]) === 'object' ? deepClone(obj[key]) : obj[key]; }); - return Array.isArray(obj) ? (clone.length = obj.length) && Array.from(clone) : clone; + return Array.isArray(obj) && obj.length ? (clone.length = obj.length) && Array.from(clone) : Array.isArray(obj) ? Array.from(obj) : clone; }; var deepFlatten = function deepFlatten(arr) { var _ref5; @@ -587,15 +556,15 @@ }, {}) : obj; }; var defaults = function defaults(obj) { - for (var _len20 = arguments.length, defs = new Array(_len20 > 1 ? _len20 - 1 : 0), _key20 = 1; _key20 < _len20; _key20++) { - defs[_key20 - 1] = arguments[_key20]; + for (var _len19 = arguments.length, defs = new Array(_len19 > 1 ? _len19 - 1 : 0), _key19 = 1; _key19 < _len19; _key19++) { + defs[_key19 - 1] = arguments[_key19]; } return Object.assign.apply(Object, [{}, obj].concat(_toConsumableArray(defs.reverse()), [obj])); }; var defer = function defer(fn) { - for (var _len21 = arguments.length, args = new Array(_len21 > 1 ? _len21 - 1 : 0), _key21 = 1; _key21 < _len21; _key21++) { - args[_key21 - 1] = arguments[_key21]; + for (var _len20 = arguments.length, args = new Array(_len20 > 1 ? _len20 - 1 : 0), _key20 = 1; _key20 < _len20; _key20++) { + args[_key20 - 1] = arguments[_key20]; } return setTimeout.apply(void 0, [fn, 1].concat(args)); @@ -604,8 +573,8 @@ return deg * Math.PI / 180.0; }; var delay = function delay(fn, wait) { - for (var _len22 = arguments.length, args = new Array(_len22 > 2 ? _len22 - 2 : 0), _key22 = 2; _key22 < _len22; _key22++) { - args[_key22 - 2] = arguments[_key22]; + for (var _len21 = arguments.length, args = new Array(_len21 > 2 ? _len21 - 2 : 0), _key21 = 2; _key21 < _len21; _key21++) { + args[_key21 - 2] = arguments[_key21]; } return setTimeout.apply(void 0, [fn, wait].concat(args)); @@ -826,8 +795,8 @@ }; var flip = function flip(fn) { return function (first) { - for (var _len23 = arguments.length, rest = new Array(_len23 > 1 ? _len23 - 1 : 0), _key23 = 1; _key23 < _len23; _key23++) { - rest[_key23 - 1] = arguments[_key23]; + for (var _len22 = arguments.length, rest = new Array(_len22 > 1 ? _len22 - 1 : 0), _key22 = 1; _key22 < _len22; _key22++) { + rest[_key22 - 1] = arguments[_key22]; } return fn.apply(void 0, rest.concat([first])); @@ -836,16 +805,6 @@ var forEachRight = function forEachRight(arr, callback) { return arr.slice(0).reverse().forEach(callback); }; - var forOwn = function forOwn(obj, fn) { - return Object.keys(obj).forEach(function (key) { - return fn(obj[key], key, obj); - }); - }; - var forOwnRight = function forOwnRight(obj, fn) { - return Object.keys(obj).reverse().forEach(function (key) { - return fn(obj[key], key, obj); - }); - }; var formatDuration = function formatDuration(ms) { if (ms < 0) ms = -ms; var time = { @@ -865,6 +824,16 @@ return "".concat(val, " ").concat(key).concat(val !== 1 ? 's' : ''); }).join(', '); }; + var forOwn = function forOwn(obj, fn) { + return Object.keys(obj).forEach(function (key) { + return fn(obj[key], key, obj); + }); + }; + var forOwnRight = function forOwnRight(obj, fn) { + return Object.keys(obj).reverse().forEach(function (key) { + return fn(obj[key], key, obj); + }); + }; var fromCamelCase = function fromCamelCase(str) { var separator = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '_'; return str.replace(/([a-z\d])([A-Z])/g, '$1' + separator + '$2').replace(/([A-Z]+)([A-Z][a-z\d]+)/g, '$1' + separator + '$2').toLowerCase(); @@ -883,8 +852,8 @@ return !y ? x : gcd(y, x % y); }; - for (var _len24 = arguments.length, arr = new Array(_len24), _key24 = 0; _key24 < _len24; _key24++) { - arr[_key24] = arguments[_key24]; + for (var _len23 = arguments.length, arr = new Array(_len23), _key23 = 0; _key23 < _len23; _key23++) { + arr[_key23] = arguments[_key23]; } return arr.concat().reduce(function (a, b) { @@ -901,8 +870,8 @@ }); }; var get = function get(from) { - for (var _len25 = arguments.length, selectors = new Array(_len25 > 1 ? _len25 - 1 : 0), _key25 = 1; _key25 < _len25; _key25++) { - selectors[_key25 - 1] = arguments[_key25]; + for (var _len24 = arguments.length, selectors = new Array(_len24 > 1 ? _len24 - 1 : 0), _key24 = 1; _key24 < _len24; _key24++) { + selectors[_key24 - 1] = arguments[_key24]; } return selectors.concat().map(function (s) { @@ -964,8 +933,8 @@ return el.classList.contains(className); }; var hasFlags = function hasFlags() { - for (var _len26 = arguments.length, flags = new Array(_len26), _key26 = 0; _key26 < _len26; _key26++) { - flags[_key26] = arguments[_key26]; + for (var _len25 = arguments.length, flags = new Array(_len25), _key25 = 0; _key25 < _len25; _key25++) { + flags[_key25] = arguments[_key25]; } return flags.every(function (flag) { @@ -1004,8 +973,8 @@ return 'rgb' + (alpha ? 'a' : '') + '(' + (h >>> (alpha ? 24 : 16)) + ', ' + ((h & (alpha ? 0x00ff0000 : 0x00ff00)) >>> (alpha ? 16 : 8)) + ', ' + ((h & (alpha ? 0x0000ff00 : 0x0000ff)) >>> (alpha ? 8 : 0)) + (alpha ? ", ".concat(h & 0x000000ff) : '') + ')'; }; var hide = function hide() { - for (var _len27 = arguments.length, el = new Array(_len27), _key27 = 0; _key27 < _len27; _key27++) { - el[_key27] = arguments[_key27]; + for (var _len26 = arguments.length, el = new Array(_len26), _key26 = 0; _key26 < _len26; _key26++) { + el[_key26] = arguments[_key26]; } return el.concat().forEach(function (e) { @@ -1056,17 +1025,6 @@ return 1000 * iterations / (performance.now() - before); }; - var inRange = function inRange(n, start) { - var end = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; - - if (end && start > end) { - var _ref12 = [start, end]; - end = _ref12[0]; - start = _ref12[1]; - } - - return end == null ? n >= 0 && n < start : n >= start && n < end; - }; var indentString = function indentString(str, count) { var indent = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ' '; return str.replace(/^/gm, indent.repeat(count)); @@ -1112,8 +1070,8 @@ return Array(n).fill(val); }; var initializeNDArray = function initializeNDArray(val) { - for (var _len28 = arguments.length, args = new Array(_len28 > 1 ? _len28 - 1 : 0), _key28 = 1; _key28 < _len28; _key28++) { - args[_key28 - 1] = arguments[_key28]; + for (var _len27 = arguments.length, args = new Array(_len27 > 1 ? _len27 - 1 : 0), _key27 = 1; _key27 < _len27; _key27++) { + args[_key27 - 1] = arguments[_key27]; } return args.length === 0 ? val : Array.from({ @@ -1122,6 +1080,17 @@ return initializeNDArray.apply(void 0, [val].concat(_toConsumableArray(args.slice(1)))); }); }; + var inRange = function inRange(n, start) { + var end = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null; + + if (end && start > end) { + var _ref12 = [start, end]; + end = _ref12[0]; + start = _ref12[1]; + } + + return end == null ? n >= 0 && n < start : n >= start && n < end; + }; var insertAfter = function insertAfter(el, htmlString) { return el.insertAdjacentHTML('afterend', htmlString); }; @@ -1312,6 +1281,17 @@ return i === arr.length - 2 ? acc + val + end : i === arr.length - 1 ? acc + val : acc + val + separator; }, ''); }; + var JSONtoCSV = function JSONtoCSV(arr, columns) { + var delimiter = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : ','; + return [columns.join(delimiter)].concat(_toConsumableArray(arr.map(function (obj) { + return columns.reduce(function (acc, key) { + return "".concat(acc).concat(!acc.length ? '' : delimiter, "\"").concat(!obj[key] ? '' : obj[key], "\""); + }, ''); + }))).join('\n'); + }; + var JSONToFile = function JSONToFile(obj, filename) { + return fs.writeFile("".concat(filename, ".json"), JSON.stringify(obj, null, 2)); + }; var last = function last(arr) { return arr[arr.length - 1]; }; @@ -1324,8 +1304,8 @@ return x * y / gcd(x, y); }; - for (var _len29 = arguments.length, arr = new Array(_len29), _key29 = 0; _key29 < _len29; _key29++) { - arr[_key29] = arguments[_key29]; + for (var _len28 = arguments.length, arr = new Array(_len28), _key28 = 0; _key28 < _len28; _key28++) { + arr[_key28] = arguments[_key28]; } return arr.concat().reduce(function (a, b) { @@ -1333,8 +1313,8 @@ }); }; var longestItem = function longestItem() { - for (var _len30 = arguments.length, vals = new Array(_len30), _key30 = 0; _key30 < _len30; _key30++) { - vals[_key30] = arguments[_key30]; + for (var _len29 = arguments.length, vals = new Array(_len29), _key29 = 0; _key29 < _len29; _key29++) { + vals[_key29] = arguments[_key29]; } return vals.reduce(function (a, x) { @@ -1405,8 +1385,8 @@ var maxDate = function maxDate() { var _Math$max; - for (var _len31 = arguments.length, dates = new Array(_len31), _key31 = 0; _key31 < _len31; _key31++) { - dates[_key31] = arguments[_key31]; + for (var _len30 = arguments.length, dates = new Array(_len30), _key30 = 0; _key30 < _len30; _key30++) { + dates[_key30] = arguments[_key30]; } return new Date((_Math$max = Math.max).apply.apply(_Math$max, [null].concat(dates))); @@ -1436,8 +1416,8 @@ return cached; }; var merge = function merge() { - for (var _len32 = arguments.length, objs = new Array(_len32), _key32 = 0; _key32 < _len32; _key32++) { - objs[_key32] = arguments[_key32]; + for (var _len31 = arguments.length, objs = new Array(_len31), _key31 = 0; _key31 < _len31; _key31++) { + objs[_key31] = arguments[_key31]; } return objs.concat().reduce(function (acc, obj) { @@ -1466,8 +1446,8 @@ var minDate = function minDate() { var _Math$min; - for (var _len33 = arguments.length, dates = new Array(_len33), _key33 = 0; _key33 < _len33; _key33++) { - dates[_key33] = arguments[_key33]; + for (var _len32 = arguments.length, dates = new Array(_len32), _key32 = 0; _key32 < _len32; _key32++) { + dates[_key32] = arguments[_key32]; } return new Date((_Math$min = Math.min).apply.apply(_Math$min, [null].concat(dates))); @@ -1516,8 +1496,8 @@ }; var nthArg = function nthArg(n) { return function () { - for (var _len34 = arguments.length, args = new Array(_len34), _key34 = 0; _key34 < _len34; _key34++) { - args[_key34] = arguments[_key34]; + for (var _len33 = arguments.length, args = new Array(_len33), _key33 = 0; _key33 < _len33; _key33++) { + args[_key33] = arguments[_key33]; } return args.slice(n)[0]; @@ -1588,6 +1568,19 @@ el.addEventListener(evt, opts.target ? delegatorFn : fn, opts.options || false); if (opts.target) return delegatorFn; }; + var once = function once(fn) { + var called = false; + return function () { + if (called) return; + called = true; + + for (var _len34 = arguments.length, args = new Array(_len34), _key34 = 0; _key34 < _len34; _key34++) { + args[_key34] = arguments[_key34]; + } + + return fn.apply(this, args); + }; + }; var onUserInputChange = function onUserInputChange(callback) { var type = 'mouse', lastTime = 0; @@ -1603,19 +1596,6 @@ type = 'touch', callback(type), document.addEventListener('mousemove', mousemoveHandler); }); }; - var once = function once(fn) { - var called = false; - return function () { - if (called) return; - called = true; - - for (var _len35 = arguments.length, args = new Array(_len35), _key35 = 0; _key35 < _len35; _key35++) { - args[_key35] = arguments[_key35]; - } - - return fn.apply(this, args); - }; - }; var orderBy = function orderBy(arr, props, orders) { return _toConsumableArray(arr).sort(function (a, b) { return props.reduce(function (acc, prop, i) { @@ -1633,13 +1613,13 @@ }); }; var over = function over() { - for (var _len36 = arguments.length, fns = new Array(_len36), _key36 = 0; _key36 < _len36; _key36++) { - fns[_key36] = arguments[_key36]; + for (var _len35 = arguments.length, fns = new Array(_len35), _key35 = 0; _key35 < _len35; _key35++) { + fns[_key35] = arguments[_key35]; } return function () { - for (var _len37 = arguments.length, args = new Array(_len37), _key37 = 0; _key37 < _len37; _key37++) { - args[_key37] = arguments[_key37]; + for (var _len36 = arguments.length, args = new Array(_len36), _key36 = 0; _key36 < _len36; _key36++) { + args[_key36] = arguments[_key36]; } return fns.map(function (fn) { @@ -1649,8 +1629,8 @@ }; var overArgs = function overArgs(fn, transforms) { return function () { - for (var _len38 = arguments.length, args = new Array(_len38), _key38 = 0; _key38 < _len38; _key38++) { - args[_key38] = arguments[_key38]; + for (var _len37 = arguments.length, args = new Array(_len37), _key37 = 0; _key37 < _len37; _key37++) { + args[_key37] = arguments[_key37]; } return fn.apply(void 0, _toConsumableArray(args.map(function (val, i) { @@ -1675,26 +1655,26 @@ }, {}); }; var partial = function partial(fn) { - for (var _len39 = arguments.length, partials = new Array(_len39 > 1 ? _len39 - 1 : 0), _key39 = 1; _key39 < _len39; _key39++) { - partials[_key39 - 1] = arguments[_key39]; + for (var _len38 = arguments.length, partials = new Array(_len38 > 1 ? _len38 - 1 : 0), _key38 = 1; _key38 < _len38; _key38++) { + partials[_key38 - 1] = arguments[_key38]; } return function () { - for (var _len40 = arguments.length, args = new Array(_len40), _key40 = 0; _key40 < _len40; _key40++) { - args[_key40] = arguments[_key40]; + for (var _len39 = arguments.length, args = new Array(_len39), _key39 = 0; _key39 < _len39; _key39++) { + args[_key39] = arguments[_key39]; } return fn.apply(void 0, partials.concat(args)); }; }; var partialRight = function partialRight(fn) { - for (var _len41 = arguments.length, partials = new Array(_len41 > 1 ? _len41 - 1 : 0), _key41 = 1; _key41 < _len41; _key41++) { - partials[_key41 - 1] = arguments[_key41]; + for (var _len40 = arguments.length, partials = new Array(_len40 > 1 ? _len40 - 1 : 0), _key40 = 1; _key40 < _len40; _key40++) { + partials[_key40 - 1] = arguments[_key40]; } return function () { - for (var _len42 = arguments.length, args = new Array(_len42), _key42 = 0; _key42 < _len42; _key42++) { - args[_key42] = arguments[_key42]; + for (var _len41 = arguments.length, args = new Array(_len41), _key41 = 0; _key41 < _len41; _key41++) { + args[_key41] = arguments[_key41]; } return fn.apply(void 0, args.concat(partials)); @@ -1732,8 +1712,8 @@ }, {}); }; var pipeAsyncFunctions = function pipeAsyncFunctions() { - for (var _len43 = arguments.length, fns = new Array(_len43), _key43 = 0; _key43 < _len43; _key43++) { - fns[_key43] = arguments[_key43]; + for (var _len42 = arguments.length, fns = new Array(_len42), _key42 = 0; _key42 < _len42; _key42++) { + fns[_key42] = arguments[_key42]; } return function (arg) { @@ -1743,8 +1723,8 @@ }; }; var pipeFunctions = function pipeFunctions() { - for (var _len44 = arguments.length, fns = new Array(_len44), _key44 = 0; _key44 < _len44; _key44++) { - fns[_key44] = arguments[_key44]; + for (var _len43 = arguments.length, fns = new Array(_len43), _key43 = 0; _key43 < _len43; _key43++) { + fns[_key43] = arguments[_key43]; } return fns.reduce(function (f, g) { @@ -1811,8 +1791,8 @@ }; var promisify = function promisify(func) { return function () { - for (var _len45 = arguments.length, args = new Array(_len45), _key45 = 0; _key45 < _len45; _key45++) { - args[_key45] = arguments[_key45]; + for (var _len44 = arguments.length, args = new Array(_len44), _key44 = 0; _key44 < _len44; _key44++) { + args[_key44] = arguments[_key44]; } return new Promise(function (resolve, reject) { @@ -1823,8 +1803,8 @@ }; }; var pull = function pull(arr) { - for (var _len46 = arguments.length, args = new Array(_len46 > 1 ? _len46 - 1 : 0), _key46 = 1; _key46 < _len46; _key46++) { - args[_key46 - 1] = arguments[_key46]; + for (var _len45 = arguments.length, args = new Array(_len45 > 1 ? _len45 - 1 : 0), _key45 = 1; _key45 < _len45; _key45++) { + args[_key45 - 1] = arguments[_key45]; } var argState = Array.isArray(args[0]) ? args[0] : args; @@ -1864,8 +1844,8 @@ return removed; }; var pullBy = function pullBy(arr) { - for (var _len47 = arguments.length, args = new Array(_len47 > 1 ? _len47 - 1 : 0), _key47 = 1; _key47 < _len47; _key47++) { - args[_key47 - 1] = arguments[_key47]; + for (var _len46 = arguments.length, args = new Array(_len46 > 1 ? _len46 - 1 : 0), _key46 = 1; _key46 < _len46; _key46++) { + args[_key46 - 1] = arguments[_key46]; } var length = args.length; @@ -1908,8 +1888,8 @@ }; var rearg = function rearg(fn, indexes) { return function () { - for (var _len48 = arguments.length, args = new Array(_len48), _key48 = 0; _key48 < _len48; _key48++) { - args[_key48] = arguments[_key48]; + for (var _len47 = arguments.length, args = new Array(_len47), _key47 = 0; _key47 < _len47; _key47++) { + args[_key47] = arguments[_key47]; } return fn.apply(void 0, _toConsumableArray(indexes.map(function (i) { @@ -1949,6 +1929,14 @@ var asLink = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; return asLink ? window.location.href = url : window.location.replace(url); }; + var reducedFilter = function reducedFilter(data, keys, fn) { + return data.filter(fn).map(function (el) { + return keys.reduce(function (acc, key) { + acc[key] = el[key]; + return acc; + }, {}); + }); + }; var reduceSuccessive = function reduceSuccessive(arr, fn, acc) { return arr.reduce(function (res, val, i, arr) { return res.push(fn(res.slice(-1)[0], val, i, arr)), res; @@ -1962,14 +1950,6 @@ return comparator(a, b) >= 0 ? b : a; }); }; - var reducedFilter = function reducedFilter(data, keys, fn) { - return data.filter(fn).map(function (el) { - return keys.reduce(function (acc, key) { - acc[key] = el[key]; - return acc; - }, {}); - }); - }; var reject = function reject(pred, array) { return array.filter(function () { return !pred.apply(void 0, arguments); @@ -1992,6 +1972,9 @@ var reverseString = function reverseString(str) { return _toConsumableArray(str).reverse().join(''); }; + var RGBToHex = function RGBToHex(r, g, b) { + return ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0'); + }; var round = function round(n) { var decimals = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; return Number("".concat(Math.round("".concat(n, "e").concat(decimals)), "e-").concat(decimals)); @@ -2062,15 +2045,15 @@ var index = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; var delCount = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 0; - for (var _len49 = arguments.length, elements = new Array(_len49 > 3 ? _len49 - 3 : 0), _key49 = 3; _key49 < _len49; _key49++) { - elements[_key49 - 3] = arguments[_key49]; + for (var _len48 = arguments.length, elements = new Array(_len48 > 3 ? _len48 - 3 : 0), _key48 = 3; _key48 < _len48; _key48++) { + elements[_key48 - 3] = arguments[_key48]; } return arr.slice(0, index).concat(elements).concat(arr.slice(index + delCount)); }; var show = function show() { - for (var _len50 = arguments.length, el = new Array(_len50), _key50 = 0; _key50 < _len50; _key50++) { - el[_key50] = arguments[_key50]; + for (var _len49 = arguments.length, el = new Array(_len49), _key49 = 0; _key49 < _len49; _key49++) { + el[_key49] = arguments[_key49]; } return el.concat().forEach(function (e) { @@ -2189,8 +2172,8 @@ return str.replace(/<[^>]*>/g, ''); }; var sum = function sum() { - for (var _len51 = arguments.length, arr = new Array(_len51), _key51 = 0; _key51 < _len51; _key51++) { - arr[_key51] = arguments[_key51]; + for (var _len50 = arguments.length, arr = new Array(_len50), _key50 = 0; _key50 < _len50; _key50++) { + arr[_key50] = arguments[_key50]; } return arr.concat().reduce(function (acc, val) { @@ -2313,18 +2296,18 @@ } }; }; - var timeTaken = function timeTaken(callback) { - console.time('timeTaken'); - var r = callback(); - console.timeEnd('timeTaken'); - return r; - }; var times = function times(n, fn) { var context = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : undefined; var i = 0; while (fn.call(context, i) !== false && ++i < n) {} }; + var timeTaken = function timeTaken(callback) { + console.time('timeTaken'); + var r = callback(); + console.timeEnd('timeTaken'); + return r; + }; var toCamelCase = function toCamelCase(str) { var s = 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(function (x) { return x.slice(0, 1).toUpperCase() + x.slice(1).toLowerCase(); @@ -2341,6 +2324,9 @@ var toDecimalMark = function toDecimalMark(num) { return num.toLocaleString('en-US'); }; + var toggleClass = function toggleClass(el, className) { + return el.classList.toggle(className); + }; var toHash = function toHash(object, key) { return Array.prototype.reduce.call(object, function (acc, data, index) { return acc[!key ? index : data[key]] = data, acc; @@ -2351,6 +2337,11 @@ return x.toLowerCase(); }).join('-'); }; + var tomorrow = function tomorrow() { + var t = new Date(); + t.setDate(t.getDate() + 1); + return t.toISOString().split('T')[0]; + }; var toOrdinalSuffix = function toOrdinalSuffix(num) { var int = parseInt(num), digits = [int % 10, int % 100], @@ -2372,14 +2363,6 @@ return x.charAt(0).toUpperCase() + x.slice(1); }).join(' '); }; - var toggleClass = function toggleClass(el, className) { - return el.classList.toggle(className); - }; - var tomorrow = function tomorrow() { - var t = new Date(); - t.setDate(t.getDate() + 1); - return t.toISOString().split('T')[0]; - }; var transform = function transform(obj, fn, acc) { return Object.keys(obj).reduce(function (a, k) { return fn(a, obj[k], k, obj); @@ -2414,8 +2397,8 @@ }; }; - for (var _len52 = arguments.length, args = new Array(_len52), _key52 = 0; _key52 < _len52; _key52++) { - args[_key52] = arguments[_key52]; + for (var _len51 = arguments.length, args = new Array(_len51), _key51 = 0; _key51 < _len51; _key51++) { + args[_key51] = arguments[_key51]; } if (n > args.length) throw new RangeError('Arguments too few!'); @@ -2528,6 +2511,23 @@ return fn.apply(void 0, _toConsumableArray(val)); }); }; + var URLJoin = function URLJoin() { + for (var _len52 = arguments.length, args = new Array(_len52), _key52 = 0; _key52 < _len52; _key52++) { + args[_key52] = arguments[_key52]; + } + + return args.join('/').replace(/[\/]+/g, '/').replace(/^(.+):\//, '$1://').replace(/^file:/, 'file:/').replace(/\/(\?|&|#[^!])/g, '$1').replace(/\?/g, '&').replace('&', '?'); + }; + var UUIDGeneratorBrowser = function UUIDGeneratorBrowser() { + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function (c) { + return (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16); + }); + }; + var UUIDGeneratorNode = function UUIDGeneratorNode() { + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function (c) { + return (c ^ crypto.randomBytes(1)[0] & 15 >> c / 4).toString(16); + }); + }; var validateNumber = function validateNumber(n) { return !isNaN(parseFloat(n)) && isFinite(n) && Number(n) == n; }; @@ -2602,14 +2602,6 @@ }); }; - exports.CSVToArray = CSVToArray; - exports.CSVToJSON = CSVToJSON; - exports.JSONToFile = JSONToFile; - exports.JSONtoCSV = JSONtoCSV; - exports.RGBToHex = RGBToHex; - exports.URLJoin = URLJoin; - exports.UUIDGeneratorBrowser = UUIDGeneratorBrowser; - exports.UUIDGeneratorNode = UUIDGeneratorNode; exports.all = all; exports.allEqual = allEqual; exports.any = any; @@ -2649,11 +2641,13 @@ exports.converge = converge; exports.copyToClipboard = copyToClipboard; exports.countBy = countBy; - exports.countOccurrences = countOccurrences; exports.counter = counter; + exports.countOccurrences = countOccurrences; exports.createDirIfNotExists = createDirIfNotExists; exports.createElement = createElement; exports.createEventHub = createEventHub; + exports.CSVToArray = CSVToArray; + exports.CSVToJSON = CSVToJSON; exports.currentURL = currentURL; exports.curry = curry; exports.dayOfYear = dayOfYear; @@ -2699,9 +2693,9 @@ exports.flattenObject = flattenObject; exports.flip = flip; exports.forEachRight = forEachRight; + exports.formatDuration = formatDuration; exports.forOwn = forOwn; exports.forOwnRight = forOwnRight; - exports.formatDuration = formatDuration; exports.fromCamelCase = fromCamelCase; exports.functionName = functionName; exports.functions = functions; @@ -2729,7 +2723,6 @@ exports.httpPost = httpPost; exports.httpsRedirect = httpsRedirect; exports.hz = hz; - exports.inRange = inRange; exports.indentString = indentString; exports.indexOfAll = indexOfAll; exports.initial = initial; @@ -2738,6 +2731,7 @@ exports.initializeArrayWithRangeRight = initializeArrayWithRangeRight; exports.initializeArrayWithValues = initializeArrayWithValues; exports.initializeNDArray = initializeNDArray; + exports.inRange = inRange; exports.insertAfter = insertAfter; exports.insertBefore = insertBefore; exports.intersection = intersection; @@ -2781,6 +2775,8 @@ exports.isValidJSON = isValidJSON; exports.isWritableStream = isWritableStream; exports.join = join; + exports.JSONtoCSV = JSONtoCSV; + exports.JSONToFile = JSONToFile; exports.last = last; exports.lcm = lcm; exports.longestItem = longestItem; @@ -2818,8 +2814,8 @@ exports.omit = omit; exports.omitBy = omitBy; exports.on = on; - exports.onUserInputChange = onUserInputChange; exports.once = once; + exports.onUserInputChange = onUserInputChange; exports.orderBy = orderBy; exports.over = over; exports.overArgs = overArgs; @@ -2854,14 +2850,15 @@ exports.rearg = rearg; exports.recordAnimationFrames = recordAnimationFrames; exports.redirect = redirect; + exports.reducedFilter = reducedFilter; exports.reduceSuccessive = reduceSuccessive; exports.reduceWhich = reduceWhich; - exports.reducedFilter = reducedFilter; exports.reject = reject; exports.remove = remove; exports.removeNonASCII = removeNonASCII; exports.renameKeys = renameKeys; exports.reverseString = reverseString; + exports.RGBToHex = RGBToHex; exports.round = round; exports.runAsync = runAsync; exports.runPromisesInSeries = runPromisesInSeries; @@ -2902,19 +2899,19 @@ exports.takeRightWhile = takeRightWhile; exports.takeWhile = takeWhile; exports.throttle = throttle; - exports.timeTaken = timeTaken; exports.times = times; + exports.timeTaken = timeTaken; exports.toCamelCase = toCamelCase; exports.toCurrency = toCurrency; exports.toDecimalMark = toDecimalMark; + exports.toggleClass = toggleClass; exports.toHash = toHash; exports.toKebabCase = toKebabCase; + exports.tomorrow = tomorrow; exports.toOrdinalSuffix = toOrdinalSuffix; exports.toSafeInteger = toSafeInteger; exports.toSnakeCase = toSnakeCase; exports.toTitleCase = toTitleCase; - exports.toggleClass = toggleClass; - exports.tomorrow = tomorrow; exports.transform = transform; exports.triggerEvent = triggerEvent; exports.truncateString = truncateString; @@ -2934,6 +2931,9 @@ exports.untildify = untildify; exports.unzip = unzip; exports.unzipWith = unzipWith; + exports.URLJoin = URLJoin; + exports.UUIDGeneratorBrowser = UUIDGeneratorBrowser; + exports.UUIDGeneratorNode = UUIDGeneratorNode; exports.validateNumber = validateNumber; exports.when = when; exports.without = without; diff --git a/dist/_30s.es5.min.js b/dist/_30s.es5.min.js index d2938cb42..dc587c2ae 100644 --- a/dist/_30s.es5.min.js +++ b/dist/_30s.es5.min.js @@ -1 +1 @@ -(function(e,t){'object'==typeof exports&&'undefined'!=typeof module?t(exports):'function'==typeof define&&define.amd?define(['exports'],t):t(e._30s={})})(this,function(e){'use strict';function t(e){return t='function'==typeof Symbol&&'symbol'==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&'function'==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?'symbol':typeof e},t(e)}function n(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e){for(var t=1;t>e/4).toString(16)})},e.UUIDGeneratorNode=function(){return'10000000-1000-4000-8000-100000000000'.replace(/[018]/g,function(e){return(e^x.randomBytes(1)[0]&15>>e/4).toString(16)})},e.all=function(e){var t=1'.concat(e,'
  • ')}).join('')}()},e.ary=function(e,t){return function(){for(var n=arguments.length,i=Array(n),r=0;rt||t>e)return 0;if(0===t||t===e)return 1;if(1===t||t===e-1)return e;e-t=(document.documentElement.scrollHeight||document.documentElement.clientHeight)},e.btoa=function(e){return Buffer.from(e,'binary').toString('base64')},e.byteSize=function(e){return new Blob([e]).size},e.call=function(e){for(var t=arguments.length,n=Array(1(n-t)*i?-i:i,o=setInterval(function(){a+=l,document.querySelector(e).innerHTML=a,a>=n&&(document.querySelector(e).innerHTML=n),a>=n&&clearInterval(o)},j(k(r/(n-t))));return o},e.createDirIfNotExists=function(e){return S.existsSync(e)?void 0:S.mkdirSync(e)},e.createElement=function(e){var t=document.createElement('div');return t.innerHTML=e,t.firstElementChild},e.createEventHub=function(){return{hub:Object.create(null),emit:function(e,t){(this.hub[e]||[]).forEach(function(e){return e(t)})},on:function(e,t){this.hub[e]||(this.hub[e]=[]),this.hub[e].push(t)},off:function(e,t){var n=(this.hub[e]||[]).findIndex(function(e){return e===t});-1'"]/g,function(e){return{"&":'&',"<":'<',">":'>',"'":''','"':'"'}[e]||e})},e.escapeRegExp=function(e){return e.replace(/[.*+?^${}()|[\]\\]/g,'\\$&')},e.everyNth=function(e,t){return e.filter(function(n,e){return e%t==t-1})},e.extendHex=function(e){return'#'+e.slice(e.startsWith('#')?1:0).split('').map(function(e){return e+e}).join('')},e.factorial=function e(t){return 0>t?function(){throw new TypeError('Negative numbers are not allowed!')}():1>=t?1:t*e(t-1)},e.fibonacci=function(e){return Array.from({length:e}).reduce(function(e,t,n){return e.concat(1e&&(e=-e);var t={day:k(e/864e5),hour:k(e/36e5)%24,minute:k(e/6e4)%60,second:k(e/1e3)%60,millisecond:k(e)%1e3};return Object.entries(t).filter(function(e){return 0!==e[1]}).map(function(e){var t=r(e,2),n=t[0],i=t[1];return''.concat(i,' ').concat(n).concat(1===i?'':'s')}).join(', ')},e.fromCamelCase=function(e){var t=1e?e%12+'am':e%12+'pm'},e.getScrollPosition=function(){var e=0>>(t?24:16))+', '+((n&(t?16711680:65280))>>>(t?16:8))+', '+((n&(t?65280:255))>>>(t?8:0))+(t?', '.concat(255&n):'')+')'},e.hide=function(){for(var e=arguments.length,t=Array(e),n=0;nn){var i=[t,n];n=i[0],t=i[1]}return null==n?0<=e&&e=t&&et},e.isAnagram=function(e,t){var n=function(e){return e.toLowerCase().replace(/[^a-z0-9]/gi,'').split('').sort().join('')};return n(e)===n(t)},e.isArrayLike=function(e){return null!=e&&'function'==typeof e[Symbol.iterator]},e.isBeforeDate=function(e,t){return ee.length?t:e})},e.lowercaseKeys=function(e){return Object.keys(e).reduce(function(t,n){return t[n.toLowerCase()]=e[n],t},{})},e.luhnCheck=function(e){var t=(e+'').split('').reverse().map(function(e){return parseInt(e)}),n=t.splice(0,1)[0],i=t.reduce(function(e,t,n){return 0==n%2?e+2*t%9||9:e+t},0);return i+=n,0==i%10},e.mapKeys=function(e,t){return Object.keys(e).reduce(function(n,i){return n[t(e[i],i,e)]=e[i],n},{})},e.mapObject=function(e,t){return function(n){return n=[e,e.map(t)],n[0].reduce(function(e,t,i){return e[t]=n[1][i],e},{})}()},e.mapString=function(e,t){return e.split('').map(function(n,r){return t(n,r,e)}).join('')},e.mapValues=function(e,t){return Object.keys(e).reduce(function(n,i){return n[i]=t(e[i],i,e),n},{})},e.mask=function(e){var t=1r-n&&(t='mouse',e(t),document.removeEventListener('mousemove',i)),n=r};document.addEventListener('touchstart',function(){'touch'==t||(t='touch',e(t),document.addEventListener('mousemove',i))})},e.once=function(e){var t=!1;return function(){if(!t){t=!0;for(var n=arguments.length,i=Array(n),r=0;rd?1:sj(e))return e+(i?' ':'')+r[0];var a=m(k(Math.log10(0>e?-e:e)/3),r.length-1),l=+((0>e?-e:e)/u(1e3,a)).toPrecision(t);return(0>e?'-':'')+l+(i?' ':'')+r[a]},e.primes=function(e){var t=Array.from({length:e-1}).map(function(e,t){return t+2}),n=k(g(e)),i=Array.from({length:n-1}).map(function(e,t){return t+2});return i.forEach(function(e){return t=t.filter(function(t){return 0!=t%e||t===e})}),t},e.promisify=function(e){return function(){for(var t=arguments.length,n=Array(t),i=0;ie[e.length-1],i=e.findIndex(function(e){return n?t>=e:t<=e});return-1===i?e.length:i},e.sortedIndexBy=function(e,t,n){var i=n(e[0])>n(e[e.length-1]),r=n(t),a=e.findIndex(function(e){return i?r>=n(e):r<=n(e)});return-1===a?e.length:a},e.sortedLastIndex=function(e,t){var n=e[0]>e[e.length-1],i=e.reverse().findIndex(function(e){return n?t<=e:t>=e});return-1===i?0:e.length-i},e.sortedLastIndexBy=function(e,t,n){var i=n(e[0])>n(e[e.length-1]),r=n(t),a=e.map(n).reverse().findIndex(function(e){return i?r<=e:r>=e});return-1===a?0:e.length-a},e.splitLines=function(e){return e.split(/\r?\n/)},e.spreadOver=function(e){return function(t){return e.apply(void 0,o(t))}},e.stableSort=function(e,t){return e.map(function(e,t){return{item:e,index:t}}).sort(function(e,n){return t(e.item,n.item)||e.index-n.index}).map(function(e){var t=e.item;return t})},e.standardDeviation=function(e){var t=!!(1=t.length?2===t.length?[t,t[1]+t[0]]:[t]:t.split('').reduce(function(n,r,a){return n.concat(e(t.slice(0,a)+t.slice(a+1)).map(function(e){return r+e}))},[])},e.stripHTMLTags=function(e){return e.replace(/<[^>]*>/g,'')},e.sum=function(){for(var e=arguments.length,t=Array(e),n=0;n=t&&(e.apply(a,l),r=Date.now())},_(t-(Date.now()-r),0))):(e.apply(a,l),r=Date.now(),n=!0)}},e.timeTaken=function(e){console.time('timeTaken');var t=e();return console.timeEnd('timeTaken'),t},e.times=function(e,t){for(var n=2t?e.slice(0,3r.length)throw new RangeError('Arguments too few!');return n(e)(r.slice(0,t))}},e.unescapeHTML=function(e){return e.replace(/&|<|>|'|"/g,function(e){return{"&":'&',"<":'<',">":'>',"'":'\'',""":'"'}[e]||e})},e.unflattenObject=function(e){return Object.keys(e).reduce(function(t,n){if(-1!==n.indexOf('.')){var r=n.split('.');Object.assign(t,JSON.parse('{'+r.map(function(e,t){return t===r.length-1?'"'.concat(e,'":'):'"'.concat(e,'":{')}).join('')+e[n]+'}'.repeat(r.length)))}else t[n]=e[n];return t},{})},e.unfold=function(e,t){for(var n=[],i=[null,t];i=e(i[1]);)n.push(i[0]);return n},e.union=function(e,t){return Array.from(new Set(o(e).concat(o(t))))},e.unionBy=function(e,t,n){var i=new Set(e.map(n));return Array.from(new Set(o(e).concat(o(t.filter(function(e){return!i.has(n(e))})))))},e.unionWith=function(e,t,n){return Array.from(new Set(o(e).concat(o(t.filter(function(t){return-1===e.findIndex(function(e){return n(t,e)})})))))},e.uniqueElements=function(e){return o(new Set(e))},e.uniqueElementsBy=function(e,t){return e.reduce(function(e,n){return e.some(function(e){return t(n,e)})||e.push(n),e},[])},e.uniqueElementsByRight=function(e,t){return e.reduceRight(function(e,n){return e.some(function(e){return t(n,e)})||e.push(n),e},[])},e.uniqueSymmetricDifference=function(e,t){return o(new Set(o(e.filter(function(e){return!t.includes(e)})).concat(o(t.filter(function(t){return!e.includes(t)})))))},e.untildify=function(e){return e.replace(/^~($|\/|\\)/,''.concat(require('os').homedir(),'$1'))},e.unzip=function(e){return e.reduce(function(e,t){return t.forEach(function(t,n){return e[n].push(t)}),e},Array.from({length:_.apply(Math,o(e.map(function(e){return e.length})))}).map(function(){return[]}))},e.unzipWith=function(e,t){return e.reduce(function(e,t){return t.forEach(function(t,n){return e[n].push(t)}),e},Array.from({length:_.apply(Math,o(e.map(function(e){return e.length})))}).map(function(){return[]})).map(function(e){return t.apply(void 0,o(e))})},e.validateNumber=function(e){return!isNaN(parseFloat(e))&&isFinite(e)&&+e==e},e.when=function(e,t){return function(n){return e(n)?t(n):n}},e.without=function(e){for(var t=arguments.length,n=Array(1'.concat(e,'')}).join('')}()},e.ary=function(e,t){return function(){for(var n=arguments.length,i=Array(n),r=0;rt||t>e)return 0;if(0===t||t===e)return 1;if(1===t||t===e-1)return e;e-t=(document.documentElement.scrollHeight||document.documentElement.clientHeight)},e.btoa=function(e){return Buffer.from(e,'binary').toString('base64')},e.byteSize=function(e){return new Blob([e]).size},e.call=function(e){for(var t=arguments.length,n=Array(1(n-t)*i?-i:i,o=setInterval(function(){a+=l,document.querySelector(e).innerHTML=a,a>=n&&(document.querySelector(e).innerHTML=n),a>=n&&clearInterval(o)},j(k(r/(n-t))));return o},e.countOccurrences=function(e,t){return e.reduce(function(e,n){return n===t?e+1:e},0)},e.createDirIfNotExists=function(e){return S.existsSync(e)?void 0:S.mkdirSync(e)},e.createElement=function(e){var t=document.createElement('div');return t.innerHTML=e,t.firstElementChild},e.createEventHub=function(){return{hub:Object.create(null),emit:function(e,t){(this.hub[e]||[]).forEach(function(e){return e(t)})},on:function(e,t){this.hub[e]||(this.hub[e]=[]),this.hub[e].push(t)},off:function(e,t){var n=(this.hub[e]||[]).findIndex(function(e){return e===t});-1'"]/g,function(e){return{"&":'&',"<":'<',">":'>',"'":''','"':'"'}[e]||e})},e.escapeRegExp=function(e){return e.replace(/[.*+?^${}()|[\]\\]/g,'\\$&')},e.everyNth=function(e,t){return e.filter(function(n,e){return e%t==t-1})},e.extendHex=function(e){return'#'+e.slice(e.startsWith('#')?1:0).split('').map(function(e){return e+e}).join('')},e.factorial=function e(t){return 0>t?function(){throw new TypeError('Negative numbers are not allowed!')}():1>=t?1:t*e(t-1)},e.fibonacci=function(e){return Array.from({length:e}).reduce(function(e,t,n){return e.concat(1e&&(e=-e);var t={day:k(e/864e5),hour:k(e/36e5)%24,minute:k(e/6e4)%60,second:k(e/1e3)%60,millisecond:k(e)%1e3};return Object.entries(t).filter(function(e){return 0!==e[1]}).map(function(e){var t=r(e,2),n=t[0],i=t[1];return''.concat(i,' ').concat(n).concat(1===i?'':'s')}).join(', ')},e.forOwn=function(e,t){return Object.keys(e).forEach(function(n){return t(e[n],n,e)})},e.forOwnRight=function(e,t){return Object.keys(e).reverse().forEach(function(n){return t(e[n],n,e)})},e.fromCamelCase=function(e){var t=1e?e%12+'am':e%12+'pm'},e.getScrollPosition=function(){var e=0>>(t?24:16))+', '+((n&(t?16711680:65280))>>>(t?16:8))+', '+((n&(t?65280:255))>>>(t?8:0))+(t?', '.concat(255&n):'')+')'},e.hide=function(){for(var e=arguments.length,t=Array(e),n=0;nn){var i=[t,n];n=i[0],t=i[1]}return null==n?0<=e&&e=t&&et},e.isAnagram=function(e,t){var n=function(e){return e.toLowerCase().replace(/[^a-z0-9]/gi,'').split('').sort().join('')};return n(e)===n(t)},e.isArrayLike=function(e){return null!=e&&'function'==typeof e[Symbol.iterator]},e.isBeforeDate=function(e,t){return ee.length?t:e})},e.lowercaseKeys=function(e){return Object.keys(e).reduce(function(t,n){return t[n.toLowerCase()]=e[n],t},{})},e.luhnCheck=function(e){var t=(e+'').split('').reverse().map(function(e){return parseInt(e)}),n=t.splice(0,1)[0],i=t.reduce(function(e,t,n){return 0==n%2?e+2*t%9||9:e+t},0);return i+=n,0==i%10},e.mapKeys=function(e,t){return Object.keys(e).reduce(function(n,i){return n[t(e[i],i,e)]=e[i],n},{})},e.mapObject=function(e,t){return function(n){return n=[e,e.map(t)],n[0].reduce(function(e,t,i){return e[t]=n[1][i],e},{})}()},e.mapString=function(e,t){return e.split('').map(function(n,r){return t(n,r,e)}).join('')},e.mapValues=function(e,t){return Object.keys(e).reduce(function(n,i){return n[i]=t(e[i],i,e),n},{})},e.mask=function(e){var t=1r-n&&(t='mouse',e(t),document.removeEventListener('mousemove',i)),n=r};document.addEventListener('touchstart',function(){'touch'==t||(t='touch',e(t),document.addEventListener('mousemove',i))})},e.orderBy=function(e,t,n){return o(e).sort(function(e,a){return t.reduce(function(t,l,o){if(0===t){var i=n&&'desc'===n[o]?[a[l],e[l]]:[e[l],a[l]],c=r(i,2),s=c[0],d=c[1];t=s>d?1:sj(e))return e+(i?' ':'')+r[0];var a=m(k(Math.log10(0>e?-e:e)/3),r.length-1),l=+((0>e?-e:e)/u(1e3,a)).toPrecision(t);return(0>e?'-':'')+l+(i?' ':'')+r[a]},e.primes=function(e){var t=Array.from({length:e-1}).map(function(e,t){return t+2}),n=k(g(e)),i=Array.from({length:n-1}).map(function(e,t){return t+2});return i.forEach(function(e){return t=t.filter(function(t){return 0!=t%e||t===e})}),t},e.promisify=function(e){return function(){for(var t=arguments.length,n=Array(t),i=0;ie[e.length-1],i=e.findIndex(function(e){return n?t>=e:t<=e});return-1===i?e.length:i},e.sortedIndexBy=function(e,t,n){var i=n(e[0])>n(e[e.length-1]),r=n(t),a=e.findIndex(function(e){return i?r>=n(e):r<=n(e)});return-1===a?e.length:a},e.sortedLastIndex=function(e,t){var n=e[0]>e[e.length-1],i=e.reverse().findIndex(function(e){return n?t<=e:t>=e});return-1===i?0:e.length-i},e.sortedLastIndexBy=function(e,t,n){var i=n(e[0])>n(e[e.length-1]),r=n(t),a=e.map(n).reverse().findIndex(function(e){return i?r<=e:r>=e});return-1===a?0:e.length-a},e.splitLines=function(e){return e.split(/\r?\n/)},e.spreadOver=function(e){return function(t){return e.apply(void 0,o(t))}},e.stableSort=function(e,t){return e.map(function(e,t){return{item:e,index:t}}).sort(function(e,n){return t(e.item,n.item)||e.index-n.index}).map(function(e){var t=e.item;return t})},e.standardDeviation=function(e){var t=!!(1=t.length?2===t.length?[t,t[1]+t[0]]:[t]:t.split('').reduce(function(n,r,a){return n.concat(e(t.slice(0,a)+t.slice(a+1)).map(function(e){return r+e}))},[])},e.stripHTMLTags=function(e){return e.replace(/<[^>]*>/g,'')},e.sum=function(){for(var e=arguments.length,t=Array(e),n=0;n=t&&(e.apply(a,l),r=Date.now())},_(t-(Date.now()-r),0))):(e.apply(a,l),r=Date.now(),n=!0)}},e.times=function(e,t){for(var n=2t?e.slice(0,3r.length)throw new RangeError('Arguments too few!');return n(e)(r.slice(0,t))}},e.unescapeHTML=function(e){return e.replace(/&|<|>|'|"/g,function(e){return{"&":'&',"<":'<',">":'>',"'":'\'',""":'"'}[e]||e})},e.unflattenObject=function(e){return Object.keys(e).reduce(function(t,n){if(-1!==n.indexOf('.')){var r=n.split('.');Object.assign(t,JSON.parse('{'+r.map(function(e,t){return t===r.length-1?'"'.concat(e,'":'):'"'.concat(e,'":{')}).join('')+e[n]+'}'.repeat(r.length)))}else t[n]=e[n];return t},{})},e.unfold=function(e,t){for(var n=[],i=[null,t];i=e(i[1]);)n.push(i[0]);return n},e.union=function(e,t){return Array.from(new Set(o(e).concat(o(t))))},e.unionBy=function(e,t,n){var i=new Set(e.map(n));return Array.from(new Set(o(e).concat(o(t.filter(function(e){return!i.has(n(e))})))))},e.unionWith=function(e,t,n){return Array.from(new Set(o(e).concat(o(t.filter(function(t){return-1===e.findIndex(function(e){return n(t,e)})})))))},e.uniqueElements=function(e){return o(new Set(e))},e.uniqueElementsBy=function(e,t){return e.reduce(function(e,n){return e.some(function(e){return t(n,e)})||e.push(n),e},[])},e.uniqueElementsByRight=function(e,t){return e.reduceRight(function(e,n){return e.some(function(e){return t(n,e)})||e.push(n),e},[])},e.uniqueSymmetricDifference=function(e,t){return o(new Set(o(e.filter(function(e){return!t.includes(e)})).concat(o(t.filter(function(t){return!e.includes(t)})))))},e.untildify=function(e){return e.replace(/^~($|\/|\\)/,''.concat(require('os').homedir(),'$1'))},e.unzip=function(e){return e.reduce(function(e,t){return t.forEach(function(t,n){return e[n].push(t)}),e},Array.from({length:_.apply(Math,o(e.map(function(e){return e.length})))}).map(function(){return[]}))},e.unzipWith=function(e,t){return e.reduce(function(e,t){return t.forEach(function(t,n){return e[n].push(t)}),e},Array.from({length:_.apply(Math,o(e.map(function(e){return e.length})))}).map(function(){return[]})).map(function(e){return t.apply(void 0,o(e))})},e.URLJoin=function(){for(var e=arguments.length,t=Array(e),n=0;n>e/4).toString(16)})},e.UUIDGeneratorNode=function(){return'10000000-1000-4000-8000-100000000000'.replace(/[018]/g,function(e){return(e^x.randomBytes(1)[0]&15>>e/4).toString(16)})},e.validateNumber=function(e){return!isNaN(parseFloat(e))&&isFinite(e)&&+e==e},e.when=function(e,t){return function(n){return e(n)?t(n):n}},e.without=function(e){for(var t=arguments.length,n=Array(1 - data - .slice(omitFirstRow ? data.indexOf('\n') + 1 : 0) - .split('\n') - .map(v => v.split(delimiter)); -const CSVToJSON = (data, delimiter = ',') => { - const titles = data.slice(0, data.indexOf('\n')).split(delimiter); - return data - .slice(data.indexOf('\n') + 1) - .split('\n') - .map(v => { - const values = v.split(delimiter); - return titles.reduce((obj, title, index) => ((obj[title] = values[index]), obj), {}); - }); -}; -const JSONToFile = (obj, filename) => - fs.writeFile(`${filename}.json`, JSON.stringify(obj, null, 2)); -const JSONtoCSV = (arr, columns, delimiter = ',') => - [ - columns.join(delimiter), - ...arr.map(obj => - columns.reduce( - (acc, key) => `${acc}${!acc.length ? '' : delimiter}"${!obj[key] ? '' : obj[key]}"`, - '' - ) - ) - ].join('\n'); -const RGBToHex = (r, g, b) => ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0'); -const URLJoin = (...args) => - args - .join('/') - .replace(/[\/]+/g, '/') - .replace(/^(.+):\//, '$1://') - .replace(/^file:/, 'file:/') - .replace(/\/(\?|&|#[^!])/g, '$1') - .replace(/\?/g, '&') - .replace('&', '?'); -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 all = (arr, fn = Boolean) => arr.every(fn); const allEqual = arr => arr.every(val => val === arr[0]); const any = (arr, fn = Boolean) => arr.some(fn); @@ -169,7 +124,6 @@ const countBy = (arr, fn) => acc[val] = (acc[val] || 0) + 1; return acc; }, {}); -const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0); const counter = (selector, start, end, step = 1, duration = 2000) => { let current = start, _step = (end - start) * step < 0 ? -step : step, @@ -181,6 +135,7 @@ const counter = (selector, start, end, step = 1, duration = 2000) => { }, Math.abs(Math.floor(duration / (end - start)))); return timer; }; +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 el = document.createElement('div'); @@ -201,6 +156,21 @@ const createEventHub = () => ({ if (i > -1) this.hub[event].splice(i, 1); } }); +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 titles = data.slice(0, data.indexOf('\n')).split(delimiter); + return data + .slice(data.indexOf('\n') + 1) + .split('\n') + .map(v => { + const values = v.split(delimiter); + return titles.reduce((obj, title, index) => ((obj[title] = values[index]), obj), {}); + }); +}; const currentURL = () => window.location.href; const curry = (fn, arity = fn.length, ...args) => arity <= args.length ? fn(...args) : curry.bind(null, fn, arity, ...args); @@ -220,7 +190,7 @@ const deepClone = 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; + return Array.isArray(obj) && obj.length ? (clone.length = obj.length) && Array.from(clone) : Array.isArray(obj) ? Array.from(obj) : clone; }; const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v))); const deepFreeze = obj => @@ -374,11 +344,6 @@ const forEachRight = (arr, callback) => .slice(0) .reverse() .forEach(callback); -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 formatDuration = ms => { if (ms < 0) ms = -ms; const time = { @@ -393,6 +358,11 @@ const formatDuration = ms => { .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) => + Object.keys(obj) + .reverse() + .forEach(key => fn(obj[key], key, obj)); const fromCamelCase = (str, separator = '_') => str .replace(/([a-z\d])([A-Z])/g, '$1' + separator + '$2') @@ -521,10 +491,6 @@ const hz = (fn, iterations = 100) => { for (let i = 0; i < iterations; i++) fn(); return (1000 * iterations) / (performance.now() - before); }; -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 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); @@ -541,6 +507,10 @@ 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) => { + 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) => { @@ -652,6 +622,18 @@ const join = (arr, separator = ',', end = separator) => : acc + val + separator, '' ); +const JSONtoCSV = (arr, columns, delimiter = ',') => + [ + columns.join(delimiter), + ...arr.map(obj => + columns.reduce( + (acc, key) => `${acc}${!acc.length ? '' : delimiter}"${!obj[key] ? '' : obj[key]}"`, + '' + ) + ) + ].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 gcd = (x, y) => (!y ? x : gcd(y, x % y)); @@ -784,6 +766,14 @@ const on = (el, evt, fn, opts = {}) => { el.addEventListener(evt, opts.target ? delegatorFn : fn, opts.options || false); if (opts.target) return delegatorFn; }; +const once = fn => { + let called = false; + return function(...args) { + if (called) return; + called = true; + return fn.apply(this, args); + }; +}; const onUserInputChange = callback => { let type = 'mouse', lastTime = 0; @@ -798,14 +788,6 @@ const onUserInputChange = callback => { (type = 'touch'), callback(type), document.addEventListener('mousemove', mousemoveHandler); }); }; -const once = fn => { - let called = false; - return function(...args) { - if (called) return; - called = true; - return fn.apply(this, args); - }; -}; const orderBy = (arr, props, orders) => [...arr].sort((a, b) => props.reduce((acc, prop, i) => { @@ -964,10 +946,6 @@ const recordAnimationFrames = (callback, autoStart = true) => { }; const redirect = (url, asLink = true) => asLink ? (window.location.href = url) : window.location.replace(url); -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) => - arr.reduce((a, b) => (comparator(a, b) >= 0 ? b : a)); const reducedFilter = (data, keys, fn) => data.filter(fn).map(el => keys.reduce((acc, key) => { @@ -975,6 +953,10 @@ const reducedFilter = (data, keys, fn) => return 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) => + arr.reduce((a, b) => (comparator(a, b) >= 0 ? b : a)); const reject = (pred, array) => array.filter((...args) => !pred(...args)); const remove = (arr, func) => Array.isArray(arr) @@ -993,6 +975,7 @@ const renameKeys = (keysMap, obj) => {} ); 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( @@ -1167,16 +1150,16 @@ const throttle = (fn, wait) => { } }; }; +const times = (n, fn, context = undefined) => { + let i = 0; + while (fn.call(context, i) !== false && ++i < n) {} +}; const timeTaken = callback => { console.time('timeTaken'); const r = callback(); console.timeEnd('timeTaken'); return r; }; -const times = (n, fn, context = undefined) => { - let i = 0; - while (fn.call(context, i) !== false && ++i < n) {} -}; const toCamelCase = str => { let s = str && @@ -1189,6 +1172,7 @@ const toCamelCase = str => { 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) => Array.prototype.reduce.call( object, @@ -1201,6 +1185,11 @@ const toKebabCase = 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 = () => { + let t = new Date(); + t.setDate(t.getDate() + 1); + return t.toISOString().split('T')[0]; +}; const toOrdinalSuffix = num => { const int = parseInt(num), digits = [int % 10, int % 100], @@ -1224,12 +1213,6 @@ const toTitleCase = 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 toggleClass = (el, className) => el.classList.toggle(className); -const tomorrow = () => { - let t = new Date(); - t.setDate(t.getDate() + 1); - return t.toISOString().split('T')[0]; -}; 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 })); @@ -1314,6 +1297,23 @@ const unzipWith = (arr, fn) => }).map(x => []) ) .map(val => fn(...val)); +const URLJoin = (...args) => + args + .join('/') + .replace(/[\/]+/g, '/') + .replace(/^(.+):\//, '$1://') + .replace(/^file:/, 'file:/') + .replace(/\/(\?|&|#[^!])/g, '$1') + .replace(/\?/g, '&') + .replace('&', '?'); +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)); @@ -1337,4 +1337,4 @@ const zipWith = (...array) => { ); }; -export { CSVToArray, CSVToJSON, JSONToFile, JSONtoCSV, RGBToHex, URLJoin, UUIDGeneratorBrowser, UUIDGeneratorNode, 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, compactWhitespace, compose, composeRight, converge, copyToClipboard, countBy, countOccurrences, counter, createDirIfNotExists, createElement, createEventHub, 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, forOwn, forOwnRight, formatDuration, 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, inRange, indentString, indexOfAll, initial, initialize2DArray, initializeArrayWithRange, initializeArrayWithRangeRight, initializeArrayWithValues, initializeNDArray, 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, 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, onUserInputChange, once, 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, reduceSuccessive, reduceWhich, reducedFilter, reject, remove, removeNonASCII, renameKeys, reverseString, 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, timeTaken, times, toCamelCase, toCurrency, toDecimalMark, toHash, toKebabCase, toOrdinalSuffix, toSafeInteger, toSnakeCase, toTitleCase, toggleClass, tomorrow, transform, triggerEvent, truncateString, truthCheckCollection, unary, uncurry, unescapeHTML, unflattenObject, unfold, union, unionBy, unionWith, uniqueElements, uniqueElementsBy, uniqueElementsByRight, uniqueSymmetricDifference, untildify, unzip, unzipWith, validateNumber, when, without, words, xProd, yesNo, zip, zipObject, zipWith }; +export { 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, compactWhitespace, 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 }; diff --git a/dist/_30s.js b/dist/_30s.js index f30d8f3cd..7ffbb412c 100644 --- a/dist/_30s.js +++ b/dist/_30s.js @@ -7,51 +7,6 @@ const fs = typeof require !== "undefined" && require('fs'); const crypto = typeof require !== "undefined" && require('crypto'); - 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 titles = data.slice(0, data.indexOf('\n')).split(delimiter); - return data - .slice(data.indexOf('\n') + 1) - .split('\n') - .map(v => { - const values = v.split(delimiter); - return titles.reduce((obj, title, index) => ((obj[title] = values[index]), obj), {}); - }); - }; - const JSONToFile = (obj, filename) => - fs.writeFile(`${filename}.json`, JSON.stringify(obj, null, 2)); - const JSONtoCSV = (arr, columns, delimiter = ',') => - [ - columns.join(delimiter), - ...arr.map(obj => - columns.reduce( - (acc, key) => `${acc}${!acc.length ? '' : delimiter}"${!obj[key] ? '' : obj[key]}"`, - '' - ) - ) - ].join('\n'); - const RGBToHex = (r, g, b) => ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0'); - const URLJoin = (...args) => - args - .join('/') - .replace(/[\/]+/g, '/') - .replace(/^(.+):\//, '$1://') - .replace(/^file:/, 'file:/') - .replace(/\/(\?|&|#[^!])/g, '$1') - .replace(/\?/g, '&') - .replace('&', '?'); - 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 all = (arr, fn = Boolean) => arr.every(fn); const allEqual = arr => arr.every(val => val === arr[0]); const any = (arr, fn = Boolean) => arr.some(fn); @@ -175,7 +130,6 @@ acc[val] = (acc[val] || 0) + 1; return acc; }, {}); - const countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0); const counter = (selector, start, end, step = 1, duration = 2000) => { let current = start, _step = (end - start) * step < 0 ? -step : step, @@ -187,6 +141,7 @@ }, Math.abs(Math.floor(duration / (end - start)))); return timer; }; + 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 el = document.createElement('div'); @@ -207,6 +162,21 @@ if (i > -1) this.hub[event].splice(i, 1); } }); + 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 titles = data.slice(0, data.indexOf('\n')).split(delimiter); + return data + .slice(data.indexOf('\n') + 1) + .split('\n') + .map(v => { + const values = v.split(delimiter); + return titles.reduce((obj, title, index) => ((obj[title] = values[index]), obj), {}); + }); + }; const currentURL = () => window.location.href; const curry = (fn, arity = fn.length, ...args) => arity <= args.length ? fn(...args) : curry.bind(null, fn, arity, ...args); @@ -226,7 +196,7 @@ 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; + return Array.isArray(obj) && obj.length ? (clone.length = obj.length) && Array.from(clone) : Array.isArray(obj) ? Array.from(obj) : clone; }; const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v))); const deepFreeze = obj => @@ -380,11 +350,6 @@ .slice(0) .reverse() .forEach(callback); - 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 formatDuration = ms => { if (ms < 0) ms = -ms; const time = { @@ -399,6 +364,11 @@ .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) => + Object.keys(obj) + .reverse() + .forEach(key => fn(obj[key], key, obj)); const fromCamelCase = (str, separator = '_') => str .replace(/([a-z\d])([A-Z])/g, '$1' + separator + '$2') @@ -527,10 +497,6 @@ for (let i = 0; i < iterations; i++) fn(); return (1000 * iterations) / (performance.now() - before); }; - 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 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); @@ -547,6 +513,10 @@ args.length === 0 ? val : Array.from({ length: args[0] }).map(() => initializeNDArray(val, ...args.slice(1))); + 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) => { @@ -658,6 +628,18 @@ : acc + val + separator, '' ); + const JSONtoCSV = (arr, columns, delimiter = ',') => + [ + columns.join(delimiter), + ...arr.map(obj => + columns.reduce( + (acc, key) => `${acc}${!acc.length ? '' : delimiter}"${!obj[key] ? '' : obj[key]}"`, + '' + ) + ) + ].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 gcd = (x, y) => (!y ? x : gcd(y, x % y)); @@ -790,6 +772,14 @@ el.addEventListener(evt, opts.target ? delegatorFn : fn, opts.options || false); if (opts.target) return delegatorFn; }; + const once = fn => { + let called = false; + return function(...args) { + if (called) return; + called = true; + return fn.apply(this, args); + }; + }; const onUserInputChange = callback => { let type = 'mouse', lastTime = 0; @@ -804,14 +794,6 @@ (type = 'touch'), callback(type), document.addEventListener('mousemove', mousemoveHandler); }); }; - const once = fn => { - let called = false; - return function(...args) { - if (called) return; - called = true; - return fn.apply(this, args); - }; - }; const orderBy = (arr, props, orders) => [...arr].sort((a, b) => props.reduce((acc, prop, i) => { @@ -970,10 +952,6 @@ }; const redirect = (url, asLink = true) => asLink ? (window.location.href = url) : window.location.replace(url); - 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) => - arr.reduce((a, b) => (comparator(a, b) >= 0 ? b : a)); const reducedFilter = (data, keys, fn) => data.filter(fn).map(el => keys.reduce((acc, key) => { @@ -981,6 +959,10 @@ return 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) => + arr.reduce((a, b) => (comparator(a, b) >= 0 ? b : a)); const reject = (pred, array) => array.filter((...args) => !pred(...args)); const remove = (arr, func) => Array.isArray(arr) @@ -999,6 +981,7 @@ {} ); 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( @@ -1173,16 +1156,16 @@ } }; }; + const times = (n, fn, context = undefined) => { + let i = 0; + while (fn.call(context, i) !== false && ++i < n) {} + }; const timeTaken = callback => { console.time('timeTaken'); const r = callback(); console.timeEnd('timeTaken'); return r; }; - const times = (n, fn, context = undefined) => { - let i = 0; - while (fn.call(context, i) !== false && ++i < n) {} - }; const toCamelCase = str => { let s = str && @@ -1195,6 +1178,7 @@ 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) => Array.prototype.reduce.call( object, @@ -1207,6 +1191,11 @@ .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 = () => { + let t = new Date(); + t.setDate(t.getDate() + 1); + return t.toISOString().split('T')[0]; + }; const toOrdinalSuffix = num => { const int = parseInt(num), digits = [int % 10, int % 100], @@ -1230,12 +1219,6 @@ .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 toggleClass = (el, className) => el.classList.toggle(className); - const tomorrow = () => { - let t = new Date(); - t.setDate(t.getDate() + 1); - return t.toISOString().split('T')[0]; - }; 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 })); @@ -1320,6 +1303,23 @@ }).map(x => []) ) .map(val => fn(...val)); + const URLJoin = (...args) => + args + .join('/') + .replace(/[\/]+/g, '/') + .replace(/^(.+):\//, '$1://') + .replace(/^file:/, 'file:/') + .replace(/\/(\?|&|#[^!])/g, '$1') + .replace(/\?/g, '&') + .replace('&', '?'); + 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)); @@ -1343,14 +1343,6 @@ ); }; - exports.CSVToArray = CSVToArray; - exports.CSVToJSON = CSVToJSON; - exports.JSONToFile = JSONToFile; - exports.JSONtoCSV = JSONtoCSV; - exports.RGBToHex = RGBToHex; - exports.URLJoin = URLJoin; - exports.UUIDGeneratorBrowser = UUIDGeneratorBrowser; - exports.UUIDGeneratorNode = UUIDGeneratorNode; exports.all = all; exports.allEqual = allEqual; exports.any = any; @@ -1390,11 +1382,13 @@ exports.converge = converge; exports.copyToClipboard = copyToClipboard; exports.countBy = countBy; - exports.countOccurrences = countOccurrences; exports.counter = counter; + exports.countOccurrences = countOccurrences; exports.createDirIfNotExists = createDirIfNotExists; exports.createElement = createElement; exports.createEventHub = createEventHub; + exports.CSVToArray = CSVToArray; + exports.CSVToJSON = CSVToJSON; exports.currentURL = currentURL; exports.curry = curry; exports.dayOfYear = dayOfYear; @@ -1440,9 +1434,9 @@ exports.flattenObject = flattenObject; exports.flip = flip; exports.forEachRight = forEachRight; + exports.formatDuration = formatDuration; exports.forOwn = forOwn; exports.forOwnRight = forOwnRight; - exports.formatDuration = formatDuration; exports.fromCamelCase = fromCamelCase; exports.functionName = functionName; exports.functions = functions; @@ -1470,7 +1464,6 @@ exports.httpPost = httpPost; exports.httpsRedirect = httpsRedirect; exports.hz = hz; - exports.inRange = inRange; exports.indentString = indentString; exports.indexOfAll = indexOfAll; exports.initial = initial; @@ -1479,6 +1472,7 @@ exports.initializeArrayWithRangeRight = initializeArrayWithRangeRight; exports.initializeArrayWithValues = initializeArrayWithValues; exports.initializeNDArray = initializeNDArray; + exports.inRange = inRange; exports.insertAfter = insertAfter; exports.insertBefore = insertBefore; exports.intersection = intersection; @@ -1522,6 +1516,8 @@ exports.isValidJSON = isValidJSON; exports.isWritableStream = isWritableStream; exports.join = join; + exports.JSONtoCSV = JSONtoCSV; + exports.JSONToFile = JSONToFile; exports.last = last; exports.lcm = lcm; exports.longestItem = longestItem; @@ -1559,8 +1555,8 @@ exports.omit = omit; exports.omitBy = omitBy; exports.on = on; - exports.onUserInputChange = onUserInputChange; exports.once = once; + exports.onUserInputChange = onUserInputChange; exports.orderBy = orderBy; exports.over = over; exports.overArgs = overArgs; @@ -1595,14 +1591,15 @@ exports.rearg = rearg; exports.recordAnimationFrames = recordAnimationFrames; exports.redirect = redirect; + exports.reducedFilter = reducedFilter; exports.reduceSuccessive = reduceSuccessive; exports.reduceWhich = reduceWhich; - exports.reducedFilter = reducedFilter; exports.reject = reject; exports.remove = remove; exports.removeNonASCII = removeNonASCII; exports.renameKeys = renameKeys; exports.reverseString = reverseString; + exports.RGBToHex = RGBToHex; exports.round = round; exports.runAsync = runAsync; exports.runPromisesInSeries = runPromisesInSeries; @@ -1643,19 +1640,19 @@ exports.takeRightWhile = takeRightWhile; exports.takeWhile = takeWhile; exports.throttle = throttle; - exports.timeTaken = timeTaken; exports.times = times; + exports.timeTaken = timeTaken; exports.toCamelCase = toCamelCase; exports.toCurrency = toCurrency; exports.toDecimalMark = toDecimalMark; + exports.toggleClass = toggleClass; exports.toHash = toHash; exports.toKebabCase = toKebabCase; + exports.tomorrow = tomorrow; exports.toOrdinalSuffix = toOrdinalSuffix; exports.toSafeInteger = toSafeInteger; exports.toSnakeCase = toSnakeCase; exports.toTitleCase = toTitleCase; - exports.toggleClass = toggleClass; - exports.tomorrow = tomorrow; exports.transform = transform; exports.triggerEvent = triggerEvent; exports.truncateString = truncateString; @@ -1675,6 +1672,9 @@ exports.untildify = untildify; exports.unzip = unzip; exports.unzipWith = unzipWith; + exports.URLJoin = URLJoin; + exports.UUIDGeneratorBrowser = UUIDGeneratorBrowser; + exports.UUIDGeneratorNode = UUIDGeneratorNode; exports.validateNumber = validateNumber; exports.when = when; exports.without = without; diff --git a/docs/adapter.html b/docs/adapter.html index 563c6cfae..19a7cdefe 100644 --- a/docs/adapter.html +++ b/docs/adapter.html @@ -133,7 +133,7 @@ Object.assig x => x + 3, async x => (await x) + 4 ); -(async () => { +(async() => { console.log(await sum(5)); // 15 (after one second) })();

    pipeFunctions

    Performs left-to-right function composition.

    Use Array.prototype.reduce() with the spread operator (...) to perform left-to-right function composition. The first (leftmost) function can accept one or more arguments; the remaining functions must be unary.

    const pipeFunctions = (...fns) => fns.reduce((f, g) => (...args) => g(f(...args)));
    diff --git a/docs/index.html b/docs/index.html
    index 73e0effb7..4b119a1d3 100644
    --- a/docs/index.html
    +++ b/docs/index.html
    @@ -407,8 +407,7 @@
     

    reject

    Takes a predicate and array, like Array.prototype.filter(), but only keeps x if pred(x) === false.

    const reject = (pred, array) => array.filter((...args) => !pred(...args));
     
    reject(x => x % 2 === 0, [1, 2, 3, 4, 5]); // [1, 3, 5]
     reject(word => word.length > 4, ['Apple', 'Pear', 'Kiwi', 'Banana']); // ['Pear', 'Kiwi']
    -

    remove

    Removes elements from an array for which the given function returns false.

    Use Array.prototype.filter() to find array elements that return truthy values and Array.prototype.reduce() to remove elements using Array.prototype.splice(). The func is invoked with three arguments (value, index, array).

    -const remove = (arr, func) =>
    +

    remove

    Removes elements from an array for which the given function returns false.

    Use Array.prototype.filter() to find array elements that return truthy values and Array.prototype.reduce() to remove elements using Array.prototype.splice(). The func is invoked with three arguments (value, index, array).

    const remove = (arr, func) =>
       Array.isArray(arr)
         ? arr.filter(func).reduce((acc, val) => {
           arr.splice(arr.indexOf(val), 1);
    diff --git a/docs/math.html b/docs/math.html
    index f1a9bb838..ad21ae6e8 100644
    --- a/docs/math.html
    +++ b/docs/math.html
    @@ -152,8 +152,8 @@ own individual rating by supplying it as the third argument.
     

    factorial

    Calculates the factorial of a number.

    Use recursion. If n is less than or equal to 1, return 1. Otherwise, return the product of n and the factorial of n - 1. Throws an exception if n is a negative number.

    const factorial = n =>
       n < 0
         ? (() => {
    -        throw new TypeError('Negative numbers are not allowed!');
    -      })()
    +      throw new TypeError('Negative numbers are not allowed!');
    +    })()
         : n <= 1
           ? 1
           : n * factorial(n - 1);
    diff --git a/docs/object.html b/docs/object.html
    index ec13a5447..31acfc9ee 100644
    --- a/docs/object.html
    +++ b/docs/object.html
    @@ -115,7 +115,11 @@
       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;
    +  return Array.isArray(obj) && obj.length
    +    ? (clone.length = obj.length) && Array.from(clone)
    +    : Array.isArray(obj)
    +      ? Array.from(obj)
    +      : clone;
     };
     
    const a = { foo: 'bar', obj: { a: 1, b: 2 } };
     const b = deepClone(a); // a !== b, a.obj !== b.obj
    @@ -174,9 +178,9 @@ o[1in obj
         ? obj[target]
         : Object.values(obj).reduce((acc, val) => {
    -        if (acc !== undefined) return acc;
    -        if (typeof val === 'object') return dig(val, target);
    -      }, undefined);
    +      if (acc !== undefined) return acc;
    +      if (typeof val === 'object') return dig(val, target);
    +    }, undefined);
     
    const data = {
       level1: {
         level2: {
    diff --git a/snippets/deepClone.md b/snippets/deepClone.md
    index 78b646da8..2b47cdb51 100644
    --- a/snippets/deepClone.md
    +++ b/snippets/deepClone.md
    @@ -12,7 +12,11 @@ const deepClone = obj => {
       Object.keys(clone).forEach(
         key => (clone[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key])
       );
    -  return Array.isArray(obj) ? Array.from(obj) : clone;
    +  return Array.isArray(obj) && obj.length
    +    ? (clone.length = obj.length) && Array.from(clone)
    +    : Array.isArray(obj)
    +      ? Array.from(obj)
    +      : clone;
     };
     ```
     
    diff --git a/snippets/dig.md b/snippets/dig.md
    index c97559833..737130b6e 100644
    --- a/snippets/dig.md
    +++ b/snippets/dig.md
    @@ -10,9 +10,9 @@ const dig = (obj, target) =>
       target in obj
         ? obj[target]
         : Object.values(obj).reduce((acc, val) => {
    -        if (acc !== undefined) return acc;
    -        if (typeof val === 'object') return dig(val, target);
    -      }, undefined);
    +      if (acc !== undefined) return acc;
    +      if (typeof val === 'object') return dig(val, target);
    +    }, undefined);
     ```
     
     ```js
    diff --git a/snippets/factorial.md b/snippets/factorial.md
    index 86ebe69b6..cf3acc9cc 100644
    --- a/snippets/factorial.md
    +++ b/snippets/factorial.md
    @@ -11,8 +11,8 @@ Throws an exception if `n` is a negative number.
     const factorial = n =>
       n < 0
         ? (() => {
    -        throw new TypeError('Negative numbers are not allowed!');
    -      })()
    +      throw new TypeError('Negative numbers are not allowed!');
    +    })()
         : n <= 1
           ? 1
           : n * factorial(n - 1);
    diff --git a/snippets/pipeAsyncFunctions.md b/snippets/pipeAsyncFunctions.md
    index 8c93add3b..47d6f620c 100644
    --- a/snippets/pipeAsyncFunctions.md
    +++ b/snippets/pipeAsyncFunctions.md
    @@ -17,7 +17,7 @@ const sum = pipeAsyncFunctions(
       x => x + 3,
       async x => (await x) + 4
     );
    -(async () => {
    +(async() => {
       console.log(await sum(5)); // 15 (after one second)
     })();
     ```
    diff --git a/snippets/remove.md b/snippets/remove.md
    index 1c457d2d9..58de9c2e0 100644
    --- a/snippets/remove.md
    +++ b/snippets/remove.md
    @@ -6,7 +6,6 @@ Use `Array.prototype.filter()` to find array elements that return truthy values
     The `func` is invoked with three arguments (`value, index, array`).
     
     ```js
    -
     const remove = (arr, func) =>
       Array.isArray(arr)
         ? arr.filter(func).reduce((acc, val) => {
    diff --git a/test/_30s.js b/test/_30s.js
    index 11e43a58e..12089b816 100644
    --- a/test/_30s.js
    +++ b/test/_30s.js
    @@ -1,1511 +1,1511 @@
     const fs = typeof require !== "undefined" && require('fs');
     const crypto = typeof require !== "undefined" && require('crypto');
     
    -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 titles = data.slice(0, data.indexOf('\n')).split(delimiter);
    -  return data
    -    .slice(data.indexOf('\n') + 1)
    -    .split('\n')
    -    .map(v => {
    -      const values = v.split(delimiter);
    -      return titles.reduce((obj, title, index) => ((obj[title] = values[index]), obj), {});
    -    });
    -};
    -
    -const JSONToFile = (obj, filename) =>
    -  fs.writeFile(`${filename}.json`, JSON.stringify(obj, null, 2));
    -const JSONtoCSV = (arr, columns, delimiter = ',') =>
    -  [
    -    columns.join(delimiter),
    -    ...arr.map(obj =>
    -      columns.reduce(
    -        (acc, key) => `${acc}${!acc.length ? '' : delimiter}"${!obj[key] ? '' : obj[key]}"`,
    -        ''
    -      )
    -    )
    -  ].join('\n');
    -const RGBToHex = (r, g, b) => ((r << 16) + (g << 8) + b).toString(16).padStart(6, '0');
    -const URLJoin = (...args) =>
    -  args
    -    .join('/')
    -    .replace(/[\/]+/g, '/')
    -    .replace(/^(.+):\//, '$1://')
    -    .replace(/^file:/, 'file:/')
    -    .replace(/\/(\?|&|#[^!])/g, '$1')
    -    .replace(/\?/g, '&')
    -    .replace('&', '?');
    -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 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) =>
    -  (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) => { - 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) => - arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0) / - arr.length; -const bifurcate = (arr, filter) => - arr.reduce((acc, val, i) => (acc[filter[i] ? 0 : 1].push(val), acc), [[], []]); -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) => - fns.forEach( - fn => ( - (f = obj[fn]), - (obj[fn] = function() { - return f.apply(obj); - }) - ) - ); -const bindKey = (context, fn, ...boundArgs) => (...args) => - context[fn].apply(context, [...boundArgs, ...args]); -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; - if (k === 1 || k === n - 1) return n; - if (n - k < k) k = n - k; - let res = n; - for (let j = 2; j <= k; j++) res *= (n - j + 1) / j; - return Math.round(res); -}; -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 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) => + (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) => { + 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) => + arr.map(typeof fn === 'function' ? fn : val => val[fn]).reduce((acc, val) => acc + val, 0) / + arr.length; +const bifurcate = (arr, filter) => + arr.reduce((acc, val, i) => (acc[filter[i] ? 0 : 1].push(val), acc), [[], []]); +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) => + fns.forEach( + fn => ( + (f = obj[fn]), + (obj[fn] = function() { + return f.apply(obj); + }) + ) + ); +const bindKey = (context, fn, ...boundArgs) => (...args) => + context[fn].apply(context, [...boundArgs, ...args]); +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; + if (k === 1 || k === n - 1) return n; + if (n - k < k) k = n - k; + let res = n; + for (let j = 2; j <= k; j++) res *= (n - j + 1) / j; + return Math.round(res); +}; +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) => - 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 => { - let curr = 0; - const last = fns[fns.length - 1]; - const next = () => { - const fn = fns[curr++]; - fn === last ? fn() : fn(next); - }; - next(); -}; -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 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 => { + let curr = 0; + const last = fns[fns.length - 1]; + const next = () => { + const fn = fns[curr++]; + fn === last ? fn() : fn(next); + }; + next(); +}; +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) => ({ - black: `\x1b[30m${args.join(' ')}`, - red: `\x1b[31m${args.join(' ')}`, - green: `\x1b[32m${args.join(' ')}`, - yellow: `\x1b[33m${args.join(' ')}`, - blue: `\x1b[34m${args.join(' ')}`, - magenta: `\x1b[35m${args.join(' ')}`, - cyan: `\x1b[36m${args.join(' ')}`, - white: `\x1b[37m${args.join(' ')}`, - bgBlack: `\x1b[40m${args.join(' ')}\x1b[0m`, - bgRed: `\x1b[41m${args.join(' ')}\x1b[0m`, - bgGreen: `\x1b[42m${args.join(' ')}\x1b[0m`, - bgYellow: `\x1b[43m${args.join(' ')}\x1b[0m`, - bgBlue: `\x1b[44m${args.join(' ')}\x1b[0m`, - bgMagenta: `\x1b[45m${args.join(' ')}\x1b[0m`, - bgCyan: `\x1b[46m${args.join(' ')}\x1b[0m`, - bgWhite: `\x1b[47m${args.join(' ')}\x1b[0m` -}); -const compact = arr => arr.filter(Boolean); -const compactWhitespace = str => str.replace(/\s{2,}/g, ' '); -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', ''); - el.style.position = 'absolute'; - el.style.left = '-9999px'; - document.body.appendChild(el); - const selected = - document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false; - el.select(); - document.execCommand('copy'); - document.body.removeChild(el); - if (selected) { - document.getSelection().removeAllRanges(); - document.getSelection().addRange(selected); - } -}; -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 countOccurrences = (arr, val) => arr.reduce((a, v) => (v === val ? a + 1 : a), 0); -const counter = (selector, start, end, step = 1, duration = 2000) => { - let current = start, - _step = (end - start) * step < 0 ? -step : step, - timer = setInterval(() => { - current += _step; - document.querySelector(selector).innerHTML = current; - if (current >= end) document.querySelector(selector).innerHTML = end; - if (current >= end) clearInterval(timer); - }, Math.abs(Math.floor(duration / (end - start)))); - return timer; -}; - -const createDirIfNotExists = dir => (!fs.existsSync(dir) ? fs.mkdirSync(dir) : undefined); -const createElement = str => { - const el = document.createElement('div'); - el.innerHTML = str; - return el.firstElementChild; -}; -const createEventHub = () => ({ - hub: Object.create(null), - emit(event, data) { - (this.hub[event] || []).forEach(handler => handler(data)); - }, - on(event, handler) { - if (!this.hub[event]) this.hub[event] = []; - this.hub[event].push(handler); - }, - off(event, handler) { - const i = (this.hub[event] || []).findIndex(h => h === handler); - if (i > -1) this.hub[event].splice(i, 1); - } -}); -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 => - Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24); -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) => - first.toLowerCase() + (upperRest ? rest.join('').toUpperCase() : rest.join('')); -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 => - 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)) - : typeof obj === 'object' - ? Object.keys(obj).reduce((acc, current) => { - const val = obj[current]; - acc[f(current)] = - val !== null && typeof val === 'object' ? deepMapKeys(val, f) : (acc[f(current)] = val); - 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 = () => - /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) - ? 'Mobile' - : 'Desktop'; -const difference = (a, b) => { - const s = new Set(b); - return a.filter(x => !s.has(x)); -}; -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 dig = (obj, target) => - target in obj - ? obj[target] - : Object.values(obj).reduce((acc, val) => { - 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) => { - while (arr.length > 0 && !func(arr[arr.length - 1])) arr = arr.slice(0, -1); - return arr; -}; -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 { top, left, bottom, right } = el.getBoundingClientRect(); - const { innerHeight, innerWidth } = window; - return partiallyVisible - ? ((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) && - ((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth)) - : top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth; -}; -const elo = ([...ratings], kFactor = 32, selfRating) => { - const [a, b] = ratings; - const expectedScore = (self, opponent) => 1 / (1 + 10 ** ((opponent - self) / 400)); - const newRating = (rating, i) => - (selfRating || rating) + kFactor * (i - expectedScore(i ? a : b, i ? b : a)); - if (ratings.length === 2) return [newRating(a, 1), newRating(b, 0)]; - - for (let i = 0, len = ratings.length; i < len; i++) { - let j = i; - while (j < len - 1) { - j++; - [ratings[i], ratings[j]] = elo([ratings[i], ratings[j]], kFactor); - } - } - return ratings; -}; -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; - if (a === null || a === undefined || b === null || b === undefined) return false; - if (a.prototype !== b.prototype) return false; - let keys = Object.keys(a); - if (keys.length !== Object.keys(b).length) return false; - return keys.every(k => equals(a[k], b[k])); -}; -const escapeHTML = str => - str.replace( - /[&<>'"]/g, - tag => - ({ - '&': '&', - '<': '<', - '>': '>', - "'": ''', - '"': '"' - }[tag] || tag) - ); -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 - ? (() => { - throw new TypeError('Negative numbers are not allowed!'); - })() - : n <= 1 - ? 1 - : n * factorial(n - 1); -const fibonacci = n => - Array.from({ length: n }).reduce( - (acc, val, i) => acc.concat(i > 1 ? acc[i - 1] + acc[i - 2] : i), - [] - ); +const colorize = (...args) => ({ + black: `\x1b[30m${args.join(' ')}`, + red: `\x1b[31m${args.join(' ')}`, + green: `\x1b[32m${args.join(' ')}`, + yellow: `\x1b[33m${args.join(' ')}`, + blue: `\x1b[34m${args.join(' ')}`, + magenta: `\x1b[35m${args.join(' ')}`, + cyan: `\x1b[36m${args.join(' ')}`, + white: `\x1b[37m${args.join(' ')}`, + bgBlack: `\x1b[40m${args.join(' ')}\x1b[0m`, + bgRed: `\x1b[41m${args.join(' ')}\x1b[0m`, + bgGreen: `\x1b[42m${args.join(' ')}\x1b[0m`, + bgYellow: `\x1b[43m${args.join(' ')}\x1b[0m`, + bgBlue: `\x1b[44m${args.join(' ')}\x1b[0m`, + bgMagenta: `\x1b[45m${args.join(' ')}\x1b[0m`, + bgCyan: `\x1b[46m${args.join(' ')}\x1b[0m`, + bgWhite: `\x1b[47m${args.join(' ')}\x1b[0m` +}); +const compact = arr => arr.filter(Boolean); + const compactWhitespace = str => str.replace(/\s{2,}/g, ' '); + 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', ''); + el.style.position = 'absolute'; + el.style.left = '-9999px'; + document.body.appendChild(el); + const selected = + document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false; + el.select(); + document.execCommand('copy'); + document.body.removeChild(el); + if (selected) { + document.getSelection().removeAllRanges(); + document.getSelection().addRange(selected); + } +}; + 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) => { + let current = start, + _step = (end - start) * step < 0 ? -step : step, + timer = setInterval(() => { + current += _step; + document.querySelector(selector).innerHTML = current; + if (current >= end) document.querySelector(selector).innerHTML = end; + if (current >= end) clearInterval(timer); + }, Math.abs(Math.floor(duration / (end - start)))); + return timer; +}; +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 el = document.createElement('div'); + el.innerHTML = str; + return el.firstElementChild; +}; +const createEventHub = () => ({ + hub: Object.create(null), + emit(event, data) { + (this.hub[event] || []).forEach(handler => handler(data)); + }, + on(event, handler) { + if (!this.hub[event]) this.hub[event] = []; + this.hub[event].push(handler); + }, + off(event, handler) { + const i = (this.hub[event] || []).findIndex(h => h === handler); + if (i > -1) this.hub[event].splice(i, 1); + } +}); +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 titles = data.slice(0, data.indexOf('\n')).split(delimiter); + return data + .slice(data.indexOf('\n') + 1) + .split('\n') + .map(v => { + const values = v.split(delimiter); + return titles.reduce((obj, title, index) => ((obj[title] = values[index]), obj), {}); + }); +}; +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 => + Math.floor((date - new Date(date.getFullYear(), 0, 0)) / 1000 / 60 / 60 / 24); +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) => + first.toLowerCase() + (upperRest ? rest.join('').toUpperCase() : rest.join('')); + 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) && obj.length ? (clone.length = obj.length) && Array.from(clone) : Array.isArray(obj) ? Array.from(obj) : clone; +}; +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)) + : typeof obj === 'object' + ? Object.keys(obj).reduce((acc, current) => { + const val = obj[current]; + acc[f(current)] = + val !== null && typeof val === 'object' ? deepMapKeys(val, f) : (acc[f(current)] = val); + 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 = () => + /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) + ? 'Mobile' + : 'Desktop'; +const difference = (a, b) => { + const s = new Set(b); + return a.filter(x => !s.has(x)); +}; + 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 dig = (obj, target) => + target in obj + ? obj[target] + : Object.values(obj).reduce((acc, val) => { + 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) => { + while (arr.length > 0 && !func(arr[arr.length - 1])) arr = arr.slice(0, -1); + return arr; +}; +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 { top, left, bottom, right } = el.getBoundingClientRect(); + const { innerHeight, innerWidth } = window; + return partiallyVisible + ? ((top > 0 && top < innerHeight) || (bottom > 0 && bottom < innerHeight)) && + ((left > 0 && left < innerWidth) || (right > 0 && right < innerWidth)) + : top >= 0 && left >= 0 && bottom <= innerHeight && right <= innerWidth; +}; + const elo = ([...ratings], kFactor = 32, selfRating) => { + const [a, b] = ratings; + const expectedScore = (self, opponent) => 1 / (1 + 10 ** ((opponent - self) / 400)); + const newRating = (rating, i) => + (selfRating || rating) + kFactor * (i - expectedScore(i ? a : b, i ? b : a)); + if (ratings.length === 2) return [newRating(a, 1), newRating(b, 0)]; + + for (let i = 0, len = ratings.length; i < len; i++) { + let j = i; + while (j < len - 1) { + j++; + [ratings[i], ratings[j]] = elo([ratings[i], ratings[j]], kFactor); + } + } + return ratings; +}; +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; + if (a === null || a === undefined || b === null || b === undefined) return false; + if (a.prototype !== b.prototype) return false; + let keys = Object.keys(a); + if (keys.length !== Object.keys(b).length) return false; + return keys.every(k => equals(a[k], b[k])); +}; +const escapeHTML = str => + str.replace( + /[&<>'"]/g, + tag => + ({ + '&': '&', + '<': '<', + '>': '>', + "'": ''', + '"': '"' + }[tag] || tag) + ); +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 + ? (() => { + throw new TypeError('Negative numbers are not allowed!'); + })() + : n <= 1 + ? 1 + : n * factorial(n - 1); +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) => - 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) => - arr - .map((val, i) => [i, val]) - .filter(([i, val]) => fn(val, i, arr)) - .pop()[0]; -const findLastKey = (obj, fn) => - Object.keys(obj) - .reverse() - .find(key => fn(obj[key], key, obj)); -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 = '') => - 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 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) => + arr + .map((val, i) => [i, val]) + .filter(([i, val]) => fn(val, i, arr)) + .pop()[0]; +const findLastKey = (obj, fn) => + Object.keys(obj) + .reverse() + .find(key => fn(obj[key], key, obj)); +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 = '') => + 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) => - arr - .slice(0) - .reverse() - .forEach(callback); -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 formatDuration = ms => { - if (ms < 0) ms = -ms; - const time = { - day: Math.floor(ms / 86400000), - hour: Math.floor(ms / 3600000) % 24, - minute: Math.floor(ms / 60000) % 60, - second: Math.floor(ms / 1000) % 60, - millisecond: Math.floor(ms) % 1000 - }; - return Object.entries(time) - .filter(val => val[1] !== 0) - .map(([key, val]) => `${val} ${key}${val !== 1 ? 's' : ''}`) - .join(', '); -}; -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) => - (inherited - ? [...Object.keys(obj), ...Object.keys(Object.getPrototypeOf(obj))] - : Object.keys(obj) - ).filter(key => typeof obj[key] === 'function'); -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) => - Array.from({ length: Math.floor(Math.log(end / start) / Math.log(step)) + 1 }).map( - (v, i) => start * step ** i - ); -const get = (from, ...selectors) => - [...selectors].map(s => - s - .replace(/\[([^\[\]]*)\]/g, '.$1.') - .split('.') - .filter(t => t !== '') - .reduce((prev, cur) => prev && prev[cur], from) - ); -const getColonTimeFromDate = date => date.toTimeString().slice(0, 8); -const getDaysDiffBetweenDates = (dateInitial, dateFinal) => - (dateFinal - dateInitial) / (1000 * 3600 * 24); -const getImages = (el, includeDuplicates = false) => { - const images = [...el.getElementsByTagName('img')].map(img => img.getAttribute('src')); - return includeDuplicates ? images : [...new Set(images)]; -}; -const getMeridiemSuffixOfInteger = num => - num === 0 || num === 24 - ? 12 + 'am' - : num === 12 - ? 12 + 'pm' - : num < 12 - ? (num % 12) + 'am' - : (num % 12) + 'pm'; -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 => - v === undefined ? 'undefined' : v === null ? 'null' : v.constructor.name.toLowerCase(); -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) => - 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) => - flags.every(flag => process.argv.includes(/^-{1,2}/.test(flag) ? flag : '--' + flag)); -const hashBrowser = val => - crypto.subtle.digest('SHA-256', new TextEncoder('utf-8').encode(val)).then(h => { - let hexes = [], - view = new DataView(h); - for (let i = 0; i < view.byteLength; i += 4) - hexes.push(('00000000' + view.getUint32(i).toString(16)).slice(-8)); - return hexes.join(''); - }); - -const hashNode = val => - new Promise(resolve => - setTimeout( - () => - resolve( - crypto - .createHash('sha256') - .update(val) - .digest('hex') - ), - 0 - ) - ); -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(''); - else if (h.length === 8) alpha = true; - h = parseInt(h, 16); - return ( - 'rgb' + - (alpha ? 'a' : '') + - '(' + - (h >>> (alpha ? 24 : 16)) + - ', ' + - ((h & (alpha ? 0x00ff0000 : 0x00ff00)) >>> (alpha ? 16 : 8)) + - ', ' + - ((h & (alpha ? 0x0000ff00 : 0x0000ff)) >>> (alpha ? 8 : 0)) + - (alpha ? `, ${h & 0x000000ff}` : '') + - ')' - ); -}; -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 request = new XMLHttpRequest(); - request.open('POST', url, true); - request.setRequestHeader('Content-type', 'application/json; charset=utf-8'); - request.onload = () => callback(request.responseText); - request.onerror = () => err(request); - request.send(data); -}; -const httpsRedirect = () => { - if (location.protocol !== 'https:') location.replace('https://' + location.href.split('//')[1]); -}; -const hz = (fn, iterations = 100) => { - const before = performance.now(); - for (let i = 0; i < iterations; i++) fn(); - return (1000 * iterations) / (performance.now() - before); -}; -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 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) => - Array.from({ length: Math.ceil((end - start + 1) / step) }, (v, i) => i * step + start); -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) => - args.length === 0 - ? val - : Array.from({ length: args[0] }).map(() => initializeNDArray(val, ...args.slice(1))); -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 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) => - 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 normalize = str => - str - .toLowerCase() - .replace(/[^a-z0-9]/gi, '') - .split('') - .sort() - .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 => - val !== null && - typeof val === 'object' && - typeof val.pipe === 'function' && - typeof val._read === 'function' && - 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 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 => - obj !== null && - (typeof obj === 'object' || typeof obj === 'function') && - typeof obj.then === 'function'; -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 => { - let direction = -(arr[0] - arr[1]); - for (let [i, val] of arr.entries()) { - direction = !direction ? -(arr[i - 1] - arr[i]) : direction; - if (i === arr.length - 1) return !direction ? 0 : direction; - 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 => { - try { - JSON.parse(str); - return true; - } catch (e) { - return false; - } -}; -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) => - arr.reduce( - (acc, val, i) => - i === arr.length - 2 - ? acc + val + end - : i === arr.length - 1 - ? acc + val - : acc + val + separator, - '' - ); -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 => - Object.keys(obj).reduce((acc, key) => { - acc[key.toLowerCase()] = obj[key]; - return acc; - }, {}); -const luhnCheck = num => { - let arr = (num + '') - .split('') - .reverse() - .map(x => parseInt(x)); - let lastDigit = arr.splice(0, 1)[0]; - let sum = arr.reduce((acc, val, i) => (i % 2 !== 0 ? acc + val : acc + ((val * 2) % 9) || 9), 0); - sum += lastDigit; - return sum % 10 === 0; -}; -const mapKeys = (obj, fn) => - Object.keys(obj).reduce((acc, k) => { - acc[fn(obj[k], k, obj)] = obj[k]; - return acc; - }, {}); -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) => - str - .split('') - .map((c, i) => fn(c, i, str)) - .join(''); -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) => - Object.keys(source).every(key => obj.hasOwnProperty(key) && obj[key] === source[key]); -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 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 cache = new Map(); - const cached = function(val) { - return cache.has(val) ? cache.get(val) : cache.set(val, fn.call(this, val)) && cache.get(val); - }; - cached.cache = cache; - return cached; -}; -const merge = (...objs) => - [...objs].reduce( - (acc, obj) => - Object.keys(obj).reduce((a, k) => { - acc[k] = acc.hasOwnProperty(k) ? [].concat(acc[k]).concat(obj[k]) : obj[k]; - return acc; - }, {}), - {} - ); -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(); - return performance.now() - before; - }); - return times.indexOf(Math.min(...times)); -}; -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 observer = new MutationObserver(mutations => mutations.forEach(m => callback(m))); - observer.observe( - element, - Object.assign( - { - childList: true, - attributes: true, - attributeOldValue: true, - characterData: true, - characterDataOldValue: true, - subtree: true - }, - options - ) - ); - 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) => - Object.keys(obj) - .filter(k => !arr.includes(k)) - .reduce((acc, key) => ((acc[key] = obj[key]), acc), {}); -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 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 onUserInputChange = callback => { - let type = 'mouse', - lastTime = 0; - const mousemoveHandler = () => { - const now = performance.now(); - if (now - lastTime < 20) - (type = 'mouse'), callback(type), document.removeEventListener('mousemove', mousemoveHandler); - lastTime = now; - }; - document.addEventListener('touchstart', () => { - if (type === 'touch') return; - (type = 'touch'), callback(type), document.addEventListener('mousemove', mousemoveHandler); - }); -}; -const once = fn => { - let called = false; - return function(...args) { - if (called) return; - called = true; - return fn.apply(this, args); - }; -}; -const orderBy = (arr, props, orders) => - [...arr].sort((a, b) => - props.reduce((acc, prop, i) => { - if (acc === 0) { - const [p1, p2] = orders && orders[i] === 'desc' ? [b[prop], a[prop]] : [a[prop], b[prop]]; - acc = p1 > p2 ? 1 : p1 < p2 ? -1 : 0; - } - 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 = ' ') => - str.padStart((str.length + length) / 2, char).padEnd(length, char); -const palindrome = str => { - const s = str.toLowerCase().replace(/[\W_]/g, ''); - return s === [...s].reverse().join(''); -}; -const parseCookie = str => - str - .split(';') - .map(v => v.split('=')) - .reduce((acc, v) => { - 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) => - arr.reduce( - (acc, val, i, arr) => { - acc[fn(val, i, arr) ? 0 : 1].push(val); - return acc; - }, - [[], []] - ); -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 => { - if (arr.length <= 2) return arr.length === 2 ? [arr, [arr[1], arr[0]]] : arr; - return arr.reduce( - (acc, item, i) => - acc.concat( - permutations([...arr.slice(0, i), ...arr.slice(i + 1)]).map(val => [item, ...val]) - ), - [] - ); -}; -const pick = (obj, arr) => - arr.reduce((acc, curr) => (curr in obj && (acc[curr] = obj[curr]), acc), {}); -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 _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 capitalizedProp = prop.charAt(0).toUpperCase() + prop.slice(1); - const prefixes = ['', 'webkit', 'moz', 'ms', 'o']; - const i = prefixes.findIndex( - prefix => typeof document.body.style[prefix ? prefix + capitalizedProp : prop] !== 'undefined' - ); - return i !== -1 ? (i === 0 ? prop : prefixes[i] + capitalizedProp) : null; -}; -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 => { - 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) => - new Promise((resolve, reject) => - func(...args, (err, result) => (err ? reject(err) : resolve(result))) - ); -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) => { - let removed = []; - let pulled = arr - .map((v, i) => (pullArr.includes(i) ? removed.push(v) : v)) - .filter((v, i) => !pullArr.includes(i)); - arr.length = 0; - pulled.forEach(v => arr.push(v)); - return removed; -}; -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)); - arr.length = 0; - mutateTo.forEach(v => arr.push(v)); - return removed; -}; -const pullBy = (arr, ...args) => { - const length = args.length; - let fn = length > 1 ? args[length - 1] : undefined; - fn = typeof fn == 'function' ? (args.pop(), fn) : undefined; - let argState = (Array.isArray(args[0]) ? args[0] : args).map(val => fn(val)); - let pulled = arr.filter((v, i) => !argState.includes(fn(v))); - arr.length = 0; - pulled.forEach(v => arr.push(v)); -}; -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) => - 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 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) => { - let running = true, - raf; - const stop = () => { - running = false; - cancelAnimationFrame(raf); - }; - const start = () => { - running = true; - run(); - }; - const run = () => { - raf = requestAnimationFrame(() => { - callback(); - if (running) run(); - }); - }; - if (autoStart) start(); - return { start, stop }; -}; -const redirect = (url, asLink = true) => - asLink ? (window.location.href = url) : window.location.replace(url); -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) => - arr.reduce((a, b) => (comparator(a, b) >= 0 ? b : a)); -const reducedFilter = (data, keys, fn) => - data.filter(fn).map(el => - keys.reduce((acc, key) => { - acc[key] = el[key]; - return acc; - }, {}) - ); -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) => - Object.keys(obj).reduce( - (acc, key) => ({ - ...acc, - ...{ [keysMap[key] || key]: obj[key] } - }), - {} - ); -const reverseString = str => [...str].reverse().join(''); -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' - }) - ); - return new Promise((res, rej) => { - worker.onmessage = ({ data }) => { - res(data), worker.terminate(); - }; - worker.onerror = err => { - rej(err), worker.terminate(); - }; - }); -}; -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--); - [arr[m], arr[i]] = [arr[i], arr[m]]; - } - return arr.slice(0, n); -}; -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 => { - let arr = str.split(''); - return arr.reduce( - (hashCode, currentVal) => - (hashCode = currentVal.charCodeAt(0) + (hashCode << 6) + (hashCode << 16) - hashCode), - 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) => - arr - .slice(0, index) - .concat(elements) - .concat(arr.slice(index + delCount)); -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--); - [arr[m], arr[i]] = [arr[i], arr[m]]; - } - return arr; -}; -const similarity = (arr, values) => arr.filter(v => values.includes(v)); -const size = val => - Array.isArray(val) - ? val.length - : val && typeof val === 'object' - ? val.size || val.length || Object.keys(val).length - : typeof val === 'string' - ? new Blob([val]).size - : 0; -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 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 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 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 isDescending = fn(arr[0]) > fn(arr[arr.length - 1]); - const val = fn(n); - const index = arr - .map(fn) - .reverse() - .findIndex(el => (isDescending ? val <= el : val >= el)); - return index === -1 ? 0 : arr.length - index; -}; -const splitLines = str => str.split(/\r?\n/); +const forEachRight = (arr, callback) => + arr + .slice(0) + .reverse() + .forEach(callback); +const formatDuration = ms => { + if (ms < 0) ms = -ms; + const time = { + day: Math.floor(ms / 86400000), + hour: Math.floor(ms / 3600000) % 24, + minute: Math.floor(ms / 60000) % 60, + second: Math.floor(ms / 1000) % 60, + millisecond: Math.floor(ms) % 1000 + }; + return Object.entries(time) + .filter(val => val[1] !== 0) + .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) => + Object.keys(obj) + .reverse() + .forEach(key => fn(obj[key], key, obj)); +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) => + (inherited + ? [...Object.keys(obj), ...Object.keys(Object.getPrototypeOf(obj))] + : Object.keys(obj) + ).filter(key => typeof obj[key] === 'function'); +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) => + Array.from({ length: Math.floor(Math.log(end / start) / Math.log(step)) + 1 }).map( + (v, i) => start * step ** i + ); +const get = (from, ...selectors) => + [...selectors].map(s => + s + .replace(/\[([^\[\]]*)\]/g, '.$1.') + .split('.') + .filter(t => t !== '') + .reduce((prev, cur) => prev && prev[cur], from) + ); + const getColonTimeFromDate = date => date.toTimeString().slice(0, 8); +const getDaysDiffBetweenDates = (dateInitial, dateFinal) => + (dateFinal - dateInitial) / (1000 * 3600 * 24); + const getImages = (el, includeDuplicates = false) => { + const images = [...el.getElementsByTagName('img')].map(img => img.getAttribute('src')); + return includeDuplicates ? images : [...new Set(images)]; +}; + const getMeridiemSuffixOfInteger = num => + num === 0 || num === 24 + ? 12 + 'am' + : num === 12 + ? 12 + 'pm' + : num < 12 + ? (num % 12) + 'am' + : (num % 12) + 'pm'; +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 => + v === undefined ? 'undefined' : v === null ? 'null' : v.constructor.name.toLowerCase(); +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) => + 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) => + flags.every(flag => process.argv.includes(/^-{1,2}/.test(flag) ? flag : '--' + flag)); +const hashBrowser = val => + crypto.subtle.digest('SHA-256', new TextEncoder('utf-8').encode(val)).then(h => { + let hexes = [], + view = new DataView(h); + for (let i = 0; i < view.byteLength; i += 4) + hexes.push(('00000000' + view.getUint32(i).toString(16)).slice(-8)); + return hexes.join(''); + }); + +const hashNode = val => + new Promise(resolve => + setTimeout( + () => + resolve( + crypto + .createHash('sha256') + .update(val) + .digest('hex') + ), + 0 + ) + ); +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(''); + else if (h.length === 8) alpha = true; + h = parseInt(h, 16); + return ( + 'rgb' + + (alpha ? 'a' : '') + + '(' + + (h >>> (alpha ? 24 : 16)) + + ', ' + + ((h & (alpha ? 0x00ff0000 : 0x00ff00)) >>> (alpha ? 16 : 8)) + + ', ' + + ((h & (alpha ? 0x0000ff00 : 0x0000ff)) >>> (alpha ? 8 : 0)) + + (alpha ? `, ${h & 0x000000ff}` : '') + + ')' + ); +}; + 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 request = new XMLHttpRequest(); + request.open('POST', url, true); + request.setRequestHeader('Content-type', 'application/json; charset=utf-8'); + request.onload = () => callback(request.responseText); + request.onerror = () => err(request); + request.send(data); +}; +const httpsRedirect = () => { + if (location.protocol !== 'https:') location.replace('https://' + location.href.split('//')[1]); +}; + 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) => + Array.from({ length: h }).map(() => Array.from({ length: w }).fill(val)); +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) => + 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) => + args.length === 0 + ? val + : Array.from({ length: args[0] }).map(() => initializeNDArray(val, ...args.slice(1))); +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 s = new Set(b); + return a.filter(x => s.has(x)); +}; +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) => + 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 normalize = str => + str + .toLowerCase() + .replace(/[^a-z0-9]/gi, '') + .split('') + .sort() + .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 => + val !== null && + typeof val === 'object' && + typeof val.pipe === 'function' && + typeof val._read === 'function' && + 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 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 => + obj !== null && + (typeof obj === 'object' || typeof obj === 'function') && + typeof obj.then === 'function'; + 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 => { + let direction = -(arr[0] - arr[1]); + for (let [i, val] of arr.entries()) { + direction = !direction ? -(arr[i - 1] - arr[i]) : direction; + if (i === arr.length - 1) return !direction ? 0 : direction; + 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 => { + try { + JSON.parse(str); + return true; + } catch (e) { + return false; + } +}; + 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) => + arr.reduce( + (acc, val, i) => + i === arr.length - 2 + ? acc + val + end + : i === arr.length - 1 + ? acc + val + : acc + val + separator, + '' + ); + const JSONtoCSV = (arr, columns, delimiter = ',') => + [ + columns.join(delimiter), + ...arr.map(obj => + columns.reduce( + (acc, key) => `${acc}${!acc.length ? '' : delimiter}"${!obj[key] ? '' : obj[key]}"`, + '' + ) + ) + ].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 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 => + Object.keys(obj).reduce((acc, key) => { + acc[key.toLowerCase()] = obj[key]; + return acc; + }, {}); + const luhnCheck = num => { + let arr = (num + '') + .split('') + .reverse() + .map(x => parseInt(x)); + let lastDigit = arr.splice(0, 1)[0]; + let sum = arr.reduce((acc, val, i) => (i % 2 !== 0 ? acc + val : acc + ((val * 2) % 9) || 9), 0); + sum += lastDigit; + return sum % 10 === 0; +}; +const mapKeys = (obj, fn) => + Object.keys(obj).reduce((acc, k) => { + acc[fn(obj[k], k, obj)] = obj[k]; + return acc; + }, {}); +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) => + str + .split('') + .map((c, i) => fn(c, i, str)) + .join(''); +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) => + Object.keys(source).every(key => obj.hasOwnProperty(key) && obj[key] === source[key]); +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 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 cache = new Map(); + const cached = function(val) { + return cache.has(val) ? cache.get(val) : cache.set(val, fn.call(this, val)) && cache.get(val); + }; + cached.cache = cache; + return cached; +}; +const merge = (...objs) => + [...objs].reduce( + (acc, obj) => + Object.keys(obj).reduce((a, k) => { + acc[k] = acc.hasOwnProperty(k) ? [].concat(acc[k]).concat(obj[k]) : obj[k]; + return acc; + }, {}), + {} + ); + 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(); + return performance.now() - before; + }); + return times.indexOf(Math.min(...times)); +}; +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 observer = new MutationObserver(mutations => mutations.forEach(m => callback(m))); + observer.observe( + element, + Object.assign( + { + childList: true, + attributes: true, + attributeOldValue: true, + characterData: true, + characterDataOldValue: true, + subtree: true + }, + options + ) + ); + 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) => + Object.keys(obj) + .filter(k => !arr.includes(k)) + .reduce((acc, key) => ((acc[key] = obj[key]), acc), {}); +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 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 => { + let called = false; + return function(...args) { + if (called) return; + called = true; + return fn.apply(this, args); + }; +}; +const onUserInputChange = callback => { + let type = 'mouse', + lastTime = 0; + const mousemoveHandler = () => { + const now = performance.now(); + if (now - lastTime < 20) + (type = 'mouse'), callback(type), document.removeEventListener('mousemove', mousemoveHandler); + lastTime = now; + }; + document.addEventListener('touchstart', () => { + if (type === 'touch') return; + (type = 'touch'), callback(type), document.addEventListener('mousemove', mousemoveHandler); + }); +}; +const orderBy = (arr, props, orders) => + [...arr].sort((a, b) => + props.reduce((acc, prop, i) => { + if (acc === 0) { + const [p1, p2] = orders && orders[i] === 'desc' ? [b[prop], a[prop]] : [a[prop], b[prop]]; + acc = p1 > p2 ? 1 : p1 < p2 ? -1 : 0; + } + 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 = ' ') => + str.padStart((str.length + length) / 2, char).padEnd(length, char); + const palindrome = str => { + const s = str.toLowerCase().replace(/[\W_]/g, ''); + return s === [...s].reverse().join(''); +}; +const parseCookie = str => + str + .split(';') + .map(v => v.split('=')) + .reduce((acc, v) => { + 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) => + arr.reduce( + (acc, val, i, arr) => { + acc[fn(val, i, arr) ? 0 : 1].push(val); + return acc; + }, + [[], []] + ); + 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 => { + if (arr.length <= 2) return arr.length === 2 ? [arr, [arr[1], arr[0]]] : arr; + return arr.reduce( + (acc, item, i) => + acc.concat( + permutations([...arr.slice(0, i), ...arr.slice(i + 1)]).map(val => [item, ...val]) + ), + [] + ); +}; +const pick = (obj, arr) => + arr.reduce((acc, curr) => (curr in obj && (acc[curr] = obj[curr]), acc), {}); +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 _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 capitalizedProp = prop.charAt(0).toUpperCase() + prop.slice(1); + const prefixes = ['', 'webkit', 'moz', 'ms', 'o']; + const i = prefixes.findIndex( + prefix => typeof document.body.style[prefix ? prefix + capitalizedProp : prop] !== 'undefined' + ); + return i !== -1 ? (i === 0 ? prop : prefixes[i] + capitalizedProp) : null; +}; +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 => { + 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) => + new Promise((resolve, reject) => + func(...args, (err, result) => (err ? reject(err) : resolve(result))) + ); +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) => { + let removed = []; + let pulled = arr + .map((v, i) => (pullArr.includes(i) ? removed.push(v) : v)) + .filter((v, i) => !pullArr.includes(i)); + arr.length = 0; + pulled.forEach(v => arr.push(v)); + return removed; +}; +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)); + arr.length = 0; + mutateTo.forEach(v => arr.push(v)); + return removed; +}; +const pullBy = (arr, ...args) => { + const length = args.length; + let fn = length > 1 ? args[length - 1] : undefined; + fn = typeof fn == 'function' ? (args.pop(), fn) : undefined; + let argState = (Array.isArray(args[0]) ? args[0] : args).map(val => fn(val)); + let pulled = arr.filter((v, i) => !argState.includes(fn(v))); + arr.length = 0; + pulled.forEach(v => arr.push(v)); +}; + 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) => + 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 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) => { + let running = true, + raf; + const stop = () => { + running = false; + cancelAnimationFrame(raf); + }; + const start = () => { + running = true; + run(); + }; + const run = () => { + raf = requestAnimationFrame(() => { + callback(); + if (running) run(); + }); + }; + if (autoStart) start(); + return { start, stop }; +}; +const redirect = (url, asLink = true) => + asLink ? (window.location.href = url) : window.location.replace(url); +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) => + 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) => + arr.reduce((a, b) => (comparator(a, b) >= 0 ? b : a)); +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) => + Object.keys(obj).reduce( + (acc, key) => ({ + ...acc, + ...{ [keysMap[key] || key]: obj[key] } + }), + {} + ); +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' + }) + ); + return new Promise((res, rej) => { + worker.onmessage = ({ data }) => { + res(data), worker.terminate(); + }; + worker.onerror = err => { + rej(err), worker.terminate(); + }; + }); +}; +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--); + [arr[m], arr[i]] = [arr[i], arr[m]]; + } + return arr.slice(0, n); +}; +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 => { + let arr = str.split(''); + return arr.reduce( + (hashCode, currentVal) => + (hashCode = currentVal.charCodeAt(0) + (hashCode << 6) + (hashCode << 16) - hashCode), + 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) => + arr + .slice(0, index) + .concat(elements) + .concat(arr.slice(index + delCount)); +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--); + [arr[m], arr[i]] = [arr[i], arr[m]]; + } + return arr; +}; +const similarity = (arr, values) => arr.filter(v => values.includes(v)); +const size = val => + Array.isArray(val) + ? val.length + : val && typeof val === 'object' + ? val.size || val.length || Object.keys(val).length + : typeof val === 'string' + ? new Blob([val]).size + : 0; +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 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 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 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 isDescending = fn(arr[0]) > fn(arr[arr.length - 1]); + const val = fn(n); + const index = arr + .map(fn) + .reverse() + .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) => - 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 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 => { - if (str.length <= 2) return str.length === 2 ? [str, str[1] + str[0]] : [str]; - return str - .split('') - .reduce( - (acc, letter, i) => - acc.concat(stringPermutations(str.slice(0, i) + str.slice(i + 1)).map(val => letter + val)), - [] - ); -}; -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) => - Array(end + 1 - start) - .fill(0) - .map((x, i) => (i + start) ** power) - .reduce((a, b) => a + b, 0); -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 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) => [ - ...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) => - arr.reduceRight((acc, el) => (func(el) ? acc : [el, ...acc]), []); -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) => { - let inThrottle, lastFn, lastTime; - return function() { - const context = this, - args = arguments; - if (!inThrottle) { - fn.apply(context, args); - lastTime = Date.now(); - inThrottle = true; - } else { - clearTimeout(lastFn); - lastFn = setTimeout(function() { - if (Date.now() - lastTime >= wait) { - fn.apply(context, args); - lastTime = Date.now(); - } - }, Math.max(wait - (Date.now() - lastTime), 0)); - } - }; -}; -const timeTaken = callback => { - console.time('timeTaken'); - const r = callback(); - console.timeEnd('timeTaken'); - return r; -}; -const times = (n, fn, context = undefined) => { - let i = 0; - while (fn.call(context, i) !== false && ++i < n) {} -}; -const toCamelCase = str => { - let s = - 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.slice(0, 1).toUpperCase() + x.slice(1).toLowerCase()) - .join(''); - return s.slice(0, 1).toLowerCase() + s.slice(1); -}; -const toCurrency = (n, curr, LanguageFormat = undefined) => - Intl.NumberFormat(LanguageFormat, { style: 'currency', currency: curr }).format(n); -const toDecimalMark = num => num.toLocaleString('en-US'); -const toHash = (object, key) => - Array.prototype.reduce.call( - object, - (acc, data, index) => ((acc[!key ? index : data[key]] = data), acc), - {} - ); -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 toOrdinalSuffix = num => { - const int = parseInt(num), - digits = [int % 10, int % 100], - ordinals = ['st', 'nd', 'rd', 'th'], - oPattern = [1, 2, 3, 4], - tPattern = [11, 12, 13, 14, 15, 16, 17, 18, 19]; - return oPattern.includes(digits[0]) && !tPattern.includes(digits[1]) - ? int + ordinals[digits[0] - 1] - : int + ordinals[3]; -}; -const toSafeInteger = num => - Math.round(Math.max(Math.min(num, Number.MAX_SAFE_INTEGER), Number.MIN_SAFE_INTEGER)); -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 => - 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 toggleClass = (el, className) => el.classList.toggle(className); -const tomorrow = () => { - let t = new Date(); - t.setDate(t.getDate() + 1); - return t.toISOString().split('T')[0]; -}; -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) => - 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 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 => - str.replace( - /&|<|>|'|"/g, - tag => - ({ - '&': '&', - '<': '<', - '>': '>', - ''': "'", - '"': '"' - }[tag] || tag) - ); -const unflattenObject = obj => - Object.keys(obj).reduce((acc, k) => { - if (k.indexOf('.') !== -1) { - const keys = k.split('.'); - Object.assign( - acc, - JSON.parse( - '{' + - keys.map((v, i) => (i !== keys.length - 1 ? `"${v}":{` : `"${v}":`)).join('') + - obj[k] + - '}'.repeat(keys.length) - ) - ); - } else acc[k] = obj[k]; - return acc; - }, {}); -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 s = new Set(a.map(fn)); - return Array.from(new Set([...a, ...b.filter(x => !s.has(fn(x)))])); -}; -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) => - arr.reduce((acc, v) => { - if (!acc.some(x => fn(v, x))) acc.push(v); - return acc; - }, []); -const uniqueElementsByRight = (arr, fn) => - arr.reduceRight((acc, v) => { - if (!acc.some(x => fn(v, x))) acc.push(v); - return acc; - }, []); -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 => - 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) => - 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 => []) - ) - .map(val => fn(...val)); -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 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) => - props.reduce((obj, prop, index) => ((obj[prop] = values[index]), obj), {}); -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 JSONToDate = arr => { - const dt = new Date(parseInt(arr.toString().substr(6))); - return `${dt.getDate()}/${dt.getMonth() + 1}/${dt.getFullYear()}`; -}; -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) => { - Object.keys(obj).forEach(key => { - if (key === childIndicator) { - cleanObj(obj[key], keysToKeep, childIndicator); - } else if (!keysToKeep.includes(key)) { - delete obj[key]; - } - }); - 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 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 isNeg = num < 0; - num = isNeg ? -num : num; - let array = Array.from({ length: num - 1 }) - .map((val, i) => (num % (i + 2) === 0 ? i + 2 : false)) - .filter(val => val); - if (isNeg) - array = array.reduce((acc, val) => { - acc.push(val); - acc.push(-val); - return acc; - }, []); - return primes ? array.filter(isPrime) : array; -}; -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 => { - 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 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) => { - if (divisor === 1 || divisor === -1) return Infinity; - if (divisor === 0) return 0; - let i = 0; - while (Number.isInteger(num / divisor)) { - i++; - num = num / divisor; - } - return i; -}; -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 request = new XMLHttpRequest(); - request.open("PUT", url, true); - request.setRequestHeader('Content-type','application/json; charset=utf-8'); - request.onload = () => callback(request); - request.onerror = () => err(request); - request.send(data); -}; -const isArmstrongNumber = digits => - (arr => arr.reduce((a, d) => a + parseInt(d) ** arr.length, 0) == digits)( - (digits + '').split('') - ); -const isSimilar = (pattern, str) => - [...str].reduce( - (matchIndex, char) => - char.toLowerCase() === (pattern[matchIndex] || '').toLowerCase() - ? matchIndex + 1 - : matchIndex, - 0 - ) === pattern.length; -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) - .fill(0) - .map((x, i) => [i]); - matrix[0] = Array(string1.length + 1) - .fill(0) - .map((x, i) => i); - for (let i = 1; i <= string2.length; i++) { - for (let j = 1; j <= string1.length; j++) { - if (string2[i - 1] === string1[j - 1]) { - matrix[i][j] = matrix[i - 1][j - 1]; - } else { - matrix[i][j] = Math.min( - matrix[i - 1][j - 1] + 1, - matrix[i][j - 1] + 1, - matrix[i - 1][j] + 1 - ); - } - } - } - return matrix[string2.length][string1.length]; -}; -const mphToKmph = (mph) => 1.6093440006146922 * mph; -const pipeLog = data => console.log(data) || data; -const quickSort = ([n, ...nums], desc) => - isNaN(n) - ? [] - : [ - ...quickSort(nums.filter(v => (desc ? v > n : v <= n)), desc), - n, - ...quickSort(nums.filter(v => (!desc ? v > n : v <= n)), desc) - ]; -const removeVowels = (str, repl = '') => str.replace(/[aeiou]/gi, repl); -const solveRPN = rpn => { - const OPERATORS = { - '*': (a, b) => a * b, - '+': (a, b) => a + b, - '-': (a, b) => a - b, - '/': (a, b) => a / b, - '**': (a, b) => a ** b - }; - const [stack, solve] = [ - [], - rpn - .replace(/\^/g, '**') - .split(/\s+/g) - .filter(el => !/\s+/.test(el) && el !== '') - ]; - solve.forEach(symbol => { - if (!isNaN(parseFloat(symbol)) && isFinite(symbol)) { - stack.push(symbol); - } else if (Object.keys(OPERATORS).includes(symbol)) { - const [a, b] = [stack.pop(), stack.pop()]; - stack.push(OPERATORS[symbol](parseFloat(b), parseFloat(a))); - } else { - throw `${symbol} is not a recognized symbol`; - } - }); - 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 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 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 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 => { + if (str.length <= 2) return str.length === 2 ? [str, str[1] + str[0]] : [str]; + return str + .split('') + .reduce( + (acc, letter, i) => + acc.concat(stringPermutations(str.slice(0, i) + str.slice(i + 1)).map(val => letter + val)), + [] + ); +}; +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) => + Array(end + 1 - start) + .fill(0) + .map((x, i) => (i + start) ** power) + .reduce((a, b) => a + b, 0); +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 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) => [ + ...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) => + arr.reduceRight((acc, el) => (func(el) ? acc : [el, ...acc]), []); +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) => { + let inThrottle, lastFn, lastTime; + return function() { + const context = this, + args = arguments; + if (!inThrottle) { + fn.apply(context, args); + lastTime = Date.now(); + inThrottle = true; + } else { + clearTimeout(lastFn); + lastFn = setTimeout(function() { + if (Date.now() - lastTime >= wait) { + fn.apply(context, args); + lastTime = Date.now(); + } + }, Math.max(wait - (Date.now() - lastTime), 0)); + } + }; +}; +const times = (n, fn, context = undefined) => { + let i = 0; + while (fn.call(context, i) !== false && ++i < n) {} +}; +const timeTaken = callback => { + console.time('timeTaken'); + const r = callback(); + console.timeEnd('timeTaken'); + return r; +}; +const toCamelCase = str => { + let s = + 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.slice(0, 1).toUpperCase() + x.slice(1).toLowerCase()) + .join(''); + return s.slice(0, 1).toLowerCase() + s.slice(1); +}; +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) => + Array.prototype.reduce.call( + object, + (acc, data, index) => ((acc[!key ? index : data[key]] = data), acc), + {} + ); +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 = () => { + let t = new Date(); + t.setDate(t.getDate() + 1); + return t.toISOString().split('T')[0]; +}; +const toOrdinalSuffix = num => { + const int = parseInt(num), + digits = [int % 10, int % 100], + ordinals = ['st', 'nd', 'rd', 'th'], + oPattern = [1, 2, 3, 4], + tPattern = [11, 12, 13, 14, 15, 16, 17, 18, 19]; + return oPattern.includes(digits[0]) && !tPattern.includes(digits[1]) + ? int + ordinals[digits[0] - 1] + : int + ordinals[3]; +}; +const toSafeInteger = num => + Math.round(Math.max(Math.min(num, Number.MAX_SAFE_INTEGER), Number.MIN_SAFE_INTEGER)); +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 => + 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) => + el.dispatchEvent(new CustomEvent(eventType, { detail })); +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 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 => + str.replace( + /&|<|>|'|"/g, + tag => + ({ + '&': '&', + '<': '<', + '>': '>', + ''': "'", + '"': '"' + }[tag] || tag) + ); +const unflattenObject = obj => + Object.keys(obj).reduce((acc, k) => { + if (k.indexOf('.') !== -1) { + const keys = k.split('.'); + Object.assign( + acc, + JSON.parse( + '{' + + keys.map((v, i) => (i !== keys.length - 1 ? `"${v}":{` : `"${v}":`)).join('') + + obj[k] + + '}'.repeat(keys.length) + ) + ); + } else acc[k] = obj[k]; + return acc; + }, {}); +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 s = new Set(a.map(fn)); + return Array.from(new Set([...a, ...b.filter(x => !s.has(fn(x)))])); +}; +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) => + arr.reduce((acc, v) => { + if (!acc.some(x => fn(v, x))) acc.push(v); + return acc; + }, []); +const uniqueElementsByRight = (arr, fn) => + arr.reduceRight((acc, v) => { + if (!acc.some(x => fn(v, x))) acc.push(v); + return acc; + }, []); +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 => + 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) => + 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 => []) + ) + .map(val => fn(...val)); +const URLJoin = (...args) => + args + .join('/') + .replace(/[\/]+/g, '/') + .replace(/^(.+):\//, '$1://') + .replace(/^file:/, 'file:/') + .replace(/\/(\?|&|#[^!])/g, '$1') + .replace(/\?/g, '&') + .replace('&', '?'); +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) => + /^(y|yes)$/i.test(val) ? true : /^(n|no)$/i.test(val) ? false : def; +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) => + props.reduce((obj, prop, index) => ((obj[prop] = values[index]), obj), {}); +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) => { + 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) => { + Object.keys(obj).forEach(key => { + if (key === childIndicator) { + cleanObj(obj[key], keysToKeep, childIndicator); + } else if (!keysToKeep.includes(key)) { + delete obj[key]; + } + }); + 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 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 isNeg = num < 0; + num = isNeg ? -num : num; + let array = Array.from({ length: num - 1 }) + .map((val, i) => (num % (i + 2) === 0 ? i + 2 : false)) + .filter(val => val); + if (isNeg) + array = array.reduce((acc, val) => { + acc.push(val); + acc.push(-val); + return acc; + }, []); + return primes ? array.filter(isPrime) : array; +}; + 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 => { + 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 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) => { + if (divisor === 1 || divisor === -1) return Infinity; + if (divisor === 0) return 0; + let i = 0; + while (Number.isInteger(num / divisor)) { + i++; + num = num / divisor; + } + return i; +}; + 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 request = new XMLHttpRequest(); + request.open("PUT", url, true); + request.setRequestHeader('Content-type','application/json; charset=utf-8'); + request.onload = () => callback(request); + request.onerror = () => err(request); + request.send(data); +}; + const isArmstrongNumber = digits => + (arr => arr.reduce((a, d) => a + parseInt(d) ** arr.length, 0) == digits)( + (digits + '').split('') + ); + const isSimilar = (pattern, str) => + [...str].reduce( + (matchIndex, char) => + char.toLowerCase() === (pattern[matchIndex] || '').toLowerCase() + ? matchIndex + 1 + : matchIndex, + 0 + ) === pattern.length; + 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) => { + if (string1.length === 0) return string2.length; + if (string2.length === 0) return string1.length; + let matrix = Array(string2.length + 1) + .fill(0) + .map((x, i) => [i]); + matrix[0] = Array(string1.length + 1) + .fill(0) + .map((x, i) => i); + for (let i = 1; i <= string2.length; i++) { + for (let j = 1; j <= string1.length; j++) { + if (string2[i - 1] === string1[j - 1]) { + matrix[i][j] = matrix[i - 1][j - 1]; + } else { + matrix[i][j] = Math.min( + matrix[i - 1][j - 1] + 1, + matrix[i][j - 1] + 1, + matrix[i - 1][j] + 1 + ); + } + } + } + return matrix[string2.length][string1.length]; +}; + const mphToKmph = (mph) => 1.6093440006146922 * mph; + const pipeLog = data => console.log(data) || data; + const quickSort = ([n, ...nums], desc) => + isNaN(n) + ? [] + : [ + ...quickSort(nums.filter(v => (desc ? v > n : v <= n)), desc), + n, + ...quickSort(nums.filter(v => (!desc ? v > n : v <= n)), desc) + ]; + const removeVowels = (str, repl = '') => str.replace(/[aeiou]/gi, repl); + const solveRPN = rpn => { + const OPERATORS = { + '*': (a, b) => a * b, + '+': (a, b) => a + b, + '-': (a, b) => a - b, + '/': (a, b) => a / b, + '**': (a, b) => a ** b + }; + const [stack, solve] = [ + [], + rpn + .replace(/\^/g, '**') + .split(/\s+/g) + .filter(el => !/\s+/.test(el) && el !== '') + ]; + solve.forEach(symbol => { + if (!isNaN(parseFloat(symbol)) && isFinite(symbol)) { + stack.push(symbol); + } else if (Object.keys(OPERATORS).includes(symbol)) { + const [a, b] = [stack.pop(), stack.pop()]; + stack.push(OPERATORS[symbol](parseFloat(b), parseFloat(a))); + } else { + throw `${symbol} is not a recognized symbol`; + } + }); + 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 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); -module.exports = {CSVToArray,CSVToJSON,JSONToFile,JSONtoCSV,RGBToHex,URLJoin,UUIDGeneratorBrowser,UUIDGeneratorNode,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,compactWhitespace,compose,composeRight,converge,copyToClipboard,countBy,countOccurrences,counter,createDirIfNotExists,createElement,createEventHub,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,forOwn,forOwnRight,formatDuration,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,inRange,indentString,indexOfAll,initial,initialize2DArray,initializeArrayWithRange,initializeArrayWithRangeRight,initializeArrayWithValues,initializeNDArray,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,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,onUserInputChange,once,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,reduceSuccessive,reduceWhich,reducedFilter,reject,remove,removeNonASCII,renameKeys,reverseString,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,timeTaken,times,toCamelCase,toCurrency,toDecimalMark,toHash,toKebabCase,toOrdinalSuffix,toSafeInteger,toSnakeCase,toTitleCase,toggleClass,tomorrow,transform,triggerEvent,truncateString,truthCheckCollection,unary,uncurry,unescapeHTML,unflattenObject,unfold,union,unionBy,unionWith,uniqueElements,uniqueElementsBy,uniqueElementsByRight,uniqueSymmetricDifference,untildify,unzip,unzipWith,validateNumber,when,without,words,xProd,yesNo,zip,zipObject,zipWith,JSONToDate,binarySearch,celsiusToFahrenheit,cleanObj,collatz,countVowels,factors,fahrenheitToCelsius,fibonacciCountUntilNum,fibonacciUntilNum,heronArea,howManyTimes,httpDelete,httpPut,isArmstrongNumber,isSimilar,kmphToMph,levenshteinDistance,mphToKmph,pipeLog,quickSort,removeVowels,solveRPN,speechSynthesis,squareSum} \ No newline at end of file +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,compactWhitespace,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 diff --git a/test/deepClone.test.js b/test/deepClone.test.js index 688ac9dd9..c7272feab 100644 --- a/test/deepClone.test.js +++ b/test/deepClone.test.js @@ -4,24 +4,33 @@ const {deepClone} = require('./_30s.js'); test('deepClone is a Function', () => { expect(deepClone).toBeInstanceOf(Function); }); -const a = { foo: 'bar', obj: { a: 1, b: 2 } }; -const b = deepClone(a); -const c = [{ foo: 'bar' }]; -const d = deepClone(c); -const e = { edge: [] }; -const f = deepClone(e); +const data = { + a: [], + b: [1, 2, 3], + c: [{ foo: 'bar' }], + d: {}, + e: { a: 'a', b: 'b', c: 'c', d: ['a', 'b', 'c'] }, + f: 1, + g: true +}; +const dupe = deepClone(data); test('Shallow cloning works', () => { - expect(a).not.toBe(b); -}); -test('Deep cloning works', () => { - expect(a.obj).not.toBe(b.obj); -}); -test('Array shallow cloning works', () => { - expect(c).not.toBe(d); -}); -test('Array deep cloning works', () => { - expect(c[0]).not.toBe(d[0]); + expect(data).not.toBe(dupe); }); test('Array shallow cloning edge case works', () => { - expect(f.edge).toEqual([]); + expect(dupe.a).toEqual([]); }); +test('Array shallow cloning works', () => { + expect(data.b).not.toBe(dupe.b); +}); +test('Array deep cloning works', () => { + expect(data.c[0]).not.toBe(dupe.c[0]); +}); +test('Deep cloning works', () => { + expect(data.d).not.toBe(dupe.d); + expect(data.e).not.toBe(dupe.e); +}); +test('Cloning primitives works', () => { + expect(data.f).toBe(dupe.f); + expect(data.g).toBe(dupe.g); +}); \ No newline at end of file