From fb6a1fae0a0475a498bba27bd2c906c11f9f2498 Mon Sep 17 00:00:00 2001 From: Matheus Bonavite dos Reis Cardoso <36443980+MatheusBonavite@users.noreply.github.com> Date: Tue, 8 Dec 2020 04:59:32 -0300 Subject: [PATCH 001/264] Add Horner's Method (#575) * Add Horner's Method * Update README.md Co-authored-by: matheus --- src/algorithms/math/horner-method/README.md | 21 +++++++++++++++++++ .../__test__/hornerMethod.test.js | 14 +++++++++++++ .../math/horner-method/hornerMethod.js | 17 +++++++++++++++ 3 files changed, 52 insertions(+) create mode 100644 src/algorithms/math/horner-method/README.md create mode 100644 src/algorithms/math/horner-method/__test__/hornerMethod.test.js create mode 100644 src/algorithms/math/horner-method/hornerMethod.js diff --git a/src/algorithms/math/horner-method/README.md b/src/algorithms/math/horner-method/README.md new file mode 100644 index 0000000000..719257b330 --- /dev/null +++ b/src/algorithms/math/horner-method/README.md @@ -0,0 +1,21 @@ +# Horner's Method + +In mathematics, Horner's method (or Horner's scheme) is an algorithm for polynomial evaluation. +With this method, it is possible to evaluate a polynomial with only n additions and n multiplications. +Hence, its storage requirements are n times the number of bits of x. + +Horner's method can be based on the following identity: +![](https://wikimedia.org/api/rest_v1/media/math/render/svg/2a576e42d875496f8b0f0dda5ebff7c2415532e4) +, which is called Horner's rule. + +To solve the right part of the identity above, for a given x, we start by iterating through the polynomial from the inside out, +accumulating each iteration result. After n iterations, with n being the order of the polynomial, the accumulated result gives +us the polynomial evaluation. + +Using the polynomial: +![](http://www.sciweavers.org/tex2img.php?eq=%244x%5E4%20%2B%202x%5E3%20%2B%203x%5E2%2B%20x%5E1%20%2B%203%24&bc=White&fc=Black&im=jpg&fs=12&ff=arev&edit=0), a traditional approach to evaluate it at x = 2, could be representing it as an array [3,1,3,2,4] and iterate over it saving each iteration value at an accumulator, such as acc += pow(x=2,index) * array[index]. In essence, each power of a number (pow) operation is n-1 multiplications. So, in this scenario, a total of 15 operations would have happened, composed of 5 additions, 5 multiplications, and 5 pows. + +Now, using the same scenario but with Horner's rule, the polynomial can be re-written as ![](http://www.sciweavers.org/tex2img.php?eq=%24x%28x%28x%284x%2B2%29%2B3%29%2B1%29%2B3%24&bc=White&fc=Black&im=jpg&fs=12&ff=arev&edit=0), representing it as [4,2,3,1,3] it is possible to save the first iteration as acc = arr[0]*(x=2) + arr[1], and then finish iterations for acc *= (x=2) + arr[index]. In the same scenario but using Horner's rule, a total of 10 operations would have happened, composed of only 5 additions and 5 multiplications. +## References + +- [Wikipedia](https://en.wikipedia.org/wiki/Horner%27s_method) diff --git a/src/algorithms/math/horner-method/__test__/hornerMethod.test.js b/src/algorithms/math/horner-method/__test__/hornerMethod.test.js new file mode 100644 index 0000000000..85d74bbc8d --- /dev/null +++ b/src/algorithms/math/horner-method/__test__/hornerMethod.test.js @@ -0,0 +1,14 @@ +import hornerMethod from '../hornerMethod'; + +describe('hornerMethod', () => { + it('should evaluate the polynomial on the specified point correctly', () => { + expect(hornerMethod([8],0.1)).toBe(8); + expect(hornerMethod([2,4,2,5],0.555)).toBe(7.68400775); + expect(hornerMethod([2,4,2,5],0.75)).toBe(9.59375); + expect(hornerMethod([1,1,1,1,1],1.75)).toBe(20.55078125); + expect(hornerMethod([15,3.5,0,2,1.42,0.41],0.315)).toBe(1.136730065140625); + expect(hornerMethod([0,0,2.77,1.42,0.41],1.35)).toBe(7.375325000000001); + expect(hornerMethod([0,0,2.77,1.42,2.3311],1.35)).toBe(9.296425000000001); + expect(hornerMethod([2,0,0,5.757,5.31412,12.3213],3.141)).toBe(697.2731167035034); + }); +}); \ No newline at end of file diff --git a/src/algorithms/math/horner-method/hornerMethod.js b/src/algorithms/math/horner-method/hornerMethod.js new file mode 100644 index 0000000000..11b029f879 --- /dev/null +++ b/src/algorithms/math/horner-method/hornerMethod.js @@ -0,0 +1,17 @@ +/** + * Returns the evaluation of a polynomial function at a certain point. + * Uses Horner's rule. + * @param {number[]} numbers + * @return {number} + */ +export default function hornerMethod(numbers, point) { + // polynomial function is just a constant. + if (numbers.length === 1) { + return numbers[0]; + } + return numbers.reduce((accumulator, currentValue, index) => { + return index === 1 + ? numbers[0] * point + currentValue + : accumulator * point + currentValue; + }); +} From 21400e36fc56a8e89ed94a02942bcde06211325c Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Tue, 8 Dec 2020 09:52:37 +0100 Subject: [PATCH 002/264] Simplify Horner's Method code and add the link to it in main READMe. --- README.md | 1 + src/algorithms/math/horner-method/README.md | 21 +++++++-------- .../__test__/classicPolynome.test.js | 14 ++++++++++ .../__test__/hornerMethod.test.js | 27 ++++++++++++------- .../math/horner-method/classicPolynome.js | 16 +++++++++++ .../math/horner-method/hornerMethod.js | 21 +++++++-------- 6 files changed, 68 insertions(+), 32 deletions(-) create mode 100644 src/algorithms/math/horner-method/__test__/classicPolynome.test.js create mode 100644 src/algorithms/math/horner-method/classicPolynome.js diff --git a/README.md b/README.md index 88d3b7ca89..a8d1b9e7f6 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Complex Number](src/algorithms/math/complex-number) - complex numbers and basic operations with them * `B` [Radian & Degree](src/algorithms/math/radian) - radians to degree and backwards conversion * `B` [Fast Powering](src/algorithms/math/fast-powering) + * `B` [Horner's method](src/algorithms/math/horner-method) - polynomial evaluation * `A` [Integer Partition](src/algorithms/math/integer-partition) * `A` [Square Root](src/algorithms/math/square-root) - Newton's method * `A` [Liu Hui π Algorithm](src/algorithms/math/liu-hui) - approximate π calculations based on N-gons diff --git a/src/algorithms/math/horner-method/README.md b/src/algorithms/math/horner-method/README.md index 719257b330..4526e5b167 100644 --- a/src/algorithms/math/horner-method/README.md +++ b/src/algorithms/math/horner-method/README.md @@ -1,21 +1,20 @@ # Horner's Method -In mathematics, Horner's method (or Horner's scheme) is an algorithm for polynomial evaluation. -With this method, it is possible to evaluate a polynomial with only n additions and n multiplications. -Hence, its storage requirements are n times the number of bits of x. +In mathematics, Horner's method (or Horner's scheme) is an algorithm for polynomial evaluation. With this method, it is possible to evaluate a polynomial with only `n` additions and `n` multiplications. Hence, its storage requirements are `n` times the number of bits of `x`. Horner's method can be based on the following identity: -![](https://wikimedia.org/api/rest_v1/media/math/render/svg/2a576e42d875496f8b0f0dda5ebff7c2415532e4) -, which is called Horner's rule. -To solve the right part of the identity above, for a given x, we start by iterating through the polynomial from the inside out, -accumulating each iteration result. After n iterations, with n being the order of the polynomial, the accumulated result gives -us the polynomial evaluation. +![Horner's rule](https://wikimedia.org/api/rest_v1/media/math/render/svg/2a576e42d875496f8b0f0dda5ebff7c2415532e4) -Using the polynomial: -![](http://www.sciweavers.org/tex2img.php?eq=%244x%5E4%20%2B%202x%5E3%20%2B%203x%5E2%2B%20x%5E1%20%2B%203%24&bc=White&fc=Black&im=jpg&fs=12&ff=arev&edit=0), a traditional approach to evaluate it at x = 2, could be representing it as an array [3,1,3,2,4] and iterate over it saving each iteration value at an accumulator, such as acc += pow(x=2,index) * array[index]. In essence, each power of a number (pow) operation is n-1 multiplications. So, in this scenario, a total of 15 operations would have happened, composed of 5 additions, 5 multiplications, and 5 pows. +This identity is called _Horner's rule_. + +To solve the right part of the identity above, for a given `x`, we start by iterating through the polynomial from the inside out, accumulating each iteration result. After `n` iterations, with `n` being the order of the polynomial, the accumulated result gives us the polynomial evaluation. + +**Using the polynomial:** +![Traditional approach](http://www.sciweavers.org/tex2img.php?eq=%244x%5E4%20%2B%202x%5E3%20%2B%203x%5E2%2B%20x%5E1%20%2B%203%24&bc=White&fc=Black&im=jpg&fs=12&ff=arev&edit=0), a traditional approach to evaluate it at `x = 2`, could be representing it as an array `[3, 1, 3, 2, 4]` and iterate over it saving each iteration value at an accumulator, such as `acc += pow(x=2, index) * array[index]`. In essence, each power of a number (`pow`) operation is `n-1` multiplications. So, in this scenario, a total of `14` operations would have happened, composed of `4` additions, `5` multiplications, and `5` pows (we're assuming that each power is calculated by repeated multiplication). + +Now, **using the same scenario but with Horner's rule**, the polynomial can be re-written as ![Horner's rule approach](http://www.sciweavers.org/tex2img.php?eq=%24x%28x%28x%284x%2B2%29%2B3%29%2B1%29%2B3%24&bc=White&fc=Black&im=jpg&fs=12&ff=arev&edit=0), representing it as `[4, 2, 3, 1, 3]` it is possible to save the first iteration as `acc = arr[0] * (x=2) + arr[1]`, and then finish iterations for `acc *= (x=2) + arr[index]`. In the same scenario but using Horner's rule, a total of `10` operations would have happened, composed of only `4` additions and `4` multiplications. -Now, using the same scenario but with Horner's rule, the polynomial can be re-written as ![](http://www.sciweavers.org/tex2img.php?eq=%24x%28x%28x%284x%2B2%29%2B3%29%2B1%29%2B3%24&bc=White&fc=Black&im=jpg&fs=12&ff=arev&edit=0), representing it as [4,2,3,1,3] it is possible to save the first iteration as acc = arr[0]*(x=2) + arr[1], and then finish iterations for acc *= (x=2) + arr[index]. In the same scenario but using Horner's rule, a total of 10 operations would have happened, composed of only 5 additions and 5 multiplications. ## References - [Wikipedia](https://en.wikipedia.org/wiki/Horner%27s_method) diff --git a/src/algorithms/math/horner-method/__test__/classicPolynome.test.js b/src/algorithms/math/horner-method/__test__/classicPolynome.test.js new file mode 100644 index 0000000000..8cdf950d6e --- /dev/null +++ b/src/algorithms/math/horner-method/__test__/classicPolynome.test.js @@ -0,0 +1,14 @@ +import classicPolynome from '../classicPolynome'; + +describe('classicPolynome', () => { + it('should evaluate the polynomial for the specified value of x correctly', () => { + expect(classicPolynome([8], 0.1)).toBe(8); + expect(classicPolynome([2, 4, 2, 5], 0.555)).toBe(7.68400775); + expect(classicPolynome([2, 4, 2, 5], 0.75)).toBe(9.59375); + expect(classicPolynome([1, 1, 1, 1, 1], 1.75)).toBe(20.55078125); + expect(classicPolynome([15, 3.5, 0, 2, 1.42, 0.41], 0.315)).toBe(1.1367300651406251); + expect(classicPolynome([0, 0, 2.77, 1.42, 0.41], 1.35)).toBe(7.375325000000001); + expect(classicPolynome([0, 0, 2.77, 1.42, 2.3311], 1.35)).toBe(9.296425000000001); + expect(classicPolynome([2, 0, 0, 5.757, 5.31412, 12.3213], 3.141)).toBe(697.2731167035034); + }); +}); diff --git a/src/algorithms/math/horner-method/__test__/hornerMethod.test.js b/src/algorithms/math/horner-method/__test__/hornerMethod.test.js index 85d74bbc8d..177ceb1aad 100644 --- a/src/algorithms/math/horner-method/__test__/hornerMethod.test.js +++ b/src/algorithms/math/horner-method/__test__/hornerMethod.test.js @@ -1,14 +1,21 @@ import hornerMethod from '../hornerMethod'; +import classicPolynome from '../classicPolynome'; describe('hornerMethod', () => { - it('should evaluate the polynomial on the specified point correctly', () => { - expect(hornerMethod([8],0.1)).toBe(8); - expect(hornerMethod([2,4,2,5],0.555)).toBe(7.68400775); - expect(hornerMethod([2,4,2,5],0.75)).toBe(9.59375); - expect(hornerMethod([1,1,1,1,1],1.75)).toBe(20.55078125); - expect(hornerMethod([15,3.5,0,2,1.42,0.41],0.315)).toBe(1.136730065140625); - expect(hornerMethod([0,0,2.77,1.42,0.41],1.35)).toBe(7.375325000000001); - expect(hornerMethod([0,0,2.77,1.42,2.3311],1.35)).toBe(9.296425000000001); - expect(hornerMethod([2,0,0,5.757,5.31412,12.3213],3.141)).toBe(697.2731167035034); + it('should evaluate the polynomial for the specified value of x correctly', () => { + expect(hornerMethod([8], 0.1)).toBe(8); + expect(hornerMethod([2, 4, 2, 5], 0.555)).toBe(7.68400775); + expect(hornerMethod([2, 4, 2, 5], 0.75)).toBe(9.59375); + expect(hornerMethod([1, 1, 1, 1, 1], 1.75)).toBe(20.55078125); + expect(hornerMethod([15, 3.5, 0, 2, 1.42, 0.41], 0.315)).toBe(1.136730065140625); + expect(hornerMethod([0, 0, 2.77, 1.42, 0.41], 1.35)).toBe(7.375325000000001); + expect(hornerMethod([0, 0, 2.77, 1.42, 2.3311], 1.35)).toBe(9.296425000000001); + expect(hornerMethod([2, 0, 0, 5.757, 5.31412, 12.3213], 3.141)).toBe(697.2731167035034); }); -}); \ No newline at end of file + + it('should evaluate the same polynomial value as classical approach', () => { + expect(hornerMethod([8], 0.1)).toBe(classicPolynome([8], 0.1)); + expect(hornerMethod([2, 4, 2, 5], 0.555)).toBe(classicPolynome([2, 4, 2, 5], 0.555)); + expect(hornerMethod([2, 4, 2, 5], 0.75)).toBe(classicPolynome([2, 4, 2, 5], 0.75)); + }); +}); diff --git a/src/algorithms/math/horner-method/classicPolynome.js b/src/algorithms/math/horner-method/classicPolynome.js new file mode 100644 index 0000000000..1f6aa8613c --- /dev/null +++ b/src/algorithms/math/horner-method/classicPolynome.js @@ -0,0 +1,16 @@ +/** + * Returns the evaluation of a polynomial function at a certain point. + * Uses straightforward approach with powers. + * + * @param {number[]} coefficients - i.e. [4, 3, 2] for (4 * x^2 + 3 * x + 2) + * @param {number} xVal + * @return {number} + */ +export default function classicPolynome(coefficients, xVal) { + return coefficients.reverse().reduce( + (accumulator, currentCoefficient, index) => { + return accumulator + currentCoefficient * (xVal ** index); + }, + 0, + ); +} diff --git a/src/algorithms/math/horner-method/hornerMethod.js b/src/algorithms/math/horner-method/hornerMethod.js index 11b029f879..2236170ed1 100644 --- a/src/algorithms/math/horner-method/hornerMethod.js +++ b/src/algorithms/math/horner-method/hornerMethod.js @@ -1,17 +1,16 @@ /** * Returns the evaluation of a polynomial function at a certain point. * Uses Horner's rule. - * @param {number[]} numbers + * + * @param {number[]} coefficients - i.e. [4, 3, 2] for (4 * x^2 + 3 * x + 2) + * @param {number} xVal * @return {number} */ -export default function hornerMethod(numbers, point) { - // polynomial function is just a constant. - if (numbers.length === 1) { - return numbers[0]; - } - return numbers.reduce((accumulator, currentValue, index) => { - return index === 1 - ? numbers[0] * point + currentValue - : accumulator * point + currentValue; - }); +export default function hornerMethod(coefficients, xVal) { + return coefficients.reduce( + (accumulator, currentCoefficient) => { + return accumulator * xVal + currentCoefficient; + }, + 0, + ); } From 9751670a06afb2aab359cb5f5fe78a4be713a023 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Tue, 8 Dec 2020 09:56:46 +0100 Subject: [PATCH 003/264] Use text formulas instead of images since images a not loading sometimes. --- src/algorithms/math/horner-method/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/algorithms/math/horner-method/README.md b/src/algorithms/math/horner-method/README.md index 4526e5b167..991a674deb 100644 --- a/src/algorithms/math/horner-method/README.md +++ b/src/algorithms/math/horner-method/README.md @@ -11,9 +11,9 @@ This identity is called _Horner's rule_. To solve the right part of the identity above, for a given `x`, we start by iterating through the polynomial from the inside out, accumulating each iteration result. After `n` iterations, with `n` being the order of the polynomial, the accumulated result gives us the polynomial evaluation. **Using the polynomial:** -![Traditional approach](http://www.sciweavers.org/tex2img.php?eq=%244x%5E4%20%2B%202x%5E3%20%2B%203x%5E2%2B%20x%5E1%20%2B%203%24&bc=White&fc=Black&im=jpg&fs=12&ff=arev&edit=0), a traditional approach to evaluate it at `x = 2`, could be representing it as an array `[3, 1, 3, 2, 4]` and iterate over it saving each iteration value at an accumulator, such as `acc += pow(x=2, index) * array[index]`. In essence, each power of a number (`pow`) operation is `n-1` multiplications. So, in this scenario, a total of `14` operations would have happened, composed of `4` additions, `5` multiplications, and `5` pows (we're assuming that each power is calculated by repeated multiplication). +`4 * x^4 + 2 * x^3 + 3 * x^2 + x^1 + 3`, a traditional approach to evaluate it at `x = 2`, could be representing it as an array `[3, 1, 3, 2, 4]` and iterate over it saving each iteration value at an accumulator, such as `acc += pow(x=2, index) * array[index]`. In essence, each power of a number (`pow`) operation is `n-1` multiplications. So, in this scenario, a total of `14` operations would have happened, composed of `4` additions, `5` multiplications, and `5` pows (we're assuming that each power is calculated by repeated multiplication). -Now, **using the same scenario but with Horner's rule**, the polynomial can be re-written as ![Horner's rule approach](http://www.sciweavers.org/tex2img.php?eq=%24x%28x%28x%284x%2B2%29%2B3%29%2B1%29%2B3%24&bc=White&fc=Black&im=jpg&fs=12&ff=arev&edit=0), representing it as `[4, 2, 3, 1, 3]` it is possible to save the first iteration as `acc = arr[0] * (x=2) + arr[1]`, and then finish iterations for `acc *= (x=2) + arr[index]`. In the same scenario but using Horner's rule, a total of `10` operations would have happened, composed of only `4` additions and `4` multiplications. +Now, **using the same scenario but with Horner's rule**, the polynomial can be re-written as `x * (x * (x * (4 * x + 2) + 3) + 1) + 3`, representing it as `[4, 2, 3, 1, 3]` it is possible to save the first iteration as `acc = arr[0] * (x=2) + arr[1]`, and then finish iterations for `acc *= (x=2) + arr[index]`. In the same scenario but using Horner's rule, a total of `10` operations would have happened, composed of only `4` additions and `4` multiplications. ## References From 2ec7fe2f022d4025545b2068c486c4f5f4100e3c Mon Sep 17 00:00:00 2001 From: Rodrigo Stuani Date: Wed, 9 Dec 2020 04:09:29 -0300 Subject: [PATCH 004/264] set Data Structure to "Estrutura de Dados" (#547) set Data Structure to "Estrutura de Dados". Co-authored-by: Oleksii Trekhleb --- README.pt-BR.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.pt-BR.md b/README.pt-BR.md index c4d225e025..a1556c7fc2 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -21,7 +21,7 @@ _Leia isto em outros idiomas:_ [_Español_](README.es-ES.md), [_Türk_](README.tr-TR.md) -## Data Structures +## Estrutura de Dados Uma estrutura de dados é uma maneira particular de organizar e armazenar dados em um computador para que ele possa ser acessado e modificado de forma eficiente. Mais precisamente, uma estrutura de dados é uma coleção de dados From ebd6ffd2c0f3e9d3120dbf61c1961882b26f38e7 Mon Sep 17 00:00:00 2001 From: Brian Tomlin Date: Wed, 9 Dec 2020 01:11:03 -0600 Subject: [PATCH 005/264] Fix typo in tree BFS testcase name (#542) --- .../breadth-first-search/__test__/breadthFirstSearch.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/tree/breadth-first-search/__test__/breadthFirstSearch.test.js b/src/algorithms/tree/breadth-first-search/__test__/breadthFirstSearch.test.js index 4a77f0f310..2bf653a9cf 100644 --- a/src/algorithms/tree/breadth-first-search/__test__/breadthFirstSearch.test.js +++ b/src/algorithms/tree/breadth-first-search/__test__/breadthFirstSearch.test.js @@ -2,7 +2,7 @@ import BinaryTreeNode from '../../../../data-structures/tree/BinaryTreeNode'; import breadthFirstSearch from '../breadthFirstSearch'; describe('breadthFirstSearch', () => { - it('should perform DFS operation on tree', () => { + it('should perform BFS operation on tree', () => { const nodeA = new BinaryTreeNode('A'); const nodeB = new BinaryTreeNode('B'); const nodeC = new BinaryTreeNode('C'); From 8a12653ac3c1ef5fe2059c38fbf83aaf96618301 Mon Sep 17 00:00:00 2001 From: Xiaoming Fu Date: Tue, 8 Dec 2020 23:13:05 -0800 Subject: [PATCH 006/264] Fix typo in comment (#540) Address issue #528 --- src/data-structures/tree/red-black-tree/RedBlackTree.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data-structures/tree/red-black-tree/RedBlackTree.js b/src/data-structures/tree/red-black-tree/RedBlackTree.js index 6bb47130c8..6e747afc75 100644 --- a/src/data-structures/tree/red-black-tree/RedBlackTree.js +++ b/src/data-structures/tree/red-black-tree/RedBlackTree.js @@ -155,7 +155,7 @@ export default class RedBlackTree extends BinarySearchTree { parentNode.parent = null; } - // Swap colors of granParent and parent nodes. + // Swap colors of grandParentNode and parentNode. this.swapNodeColors(parentNode, grandParentNode); // Return new root node. From 87b5b2b5cffb39b54cc0c474d024bd49a8847d74 Mon Sep 17 00:00:00 2001 From: Kirill Kazakov <33637819+Gorgchap@users.noreply.github.com> Date: Wed, 9 Dec 2020 10:18:36 +0300 Subject: [PATCH 007/264] added README.ru-RU.md (#533) --- README.ru-RU.md | 303 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 README.ru-RU.md diff --git a/README.ru-RU.md b/README.ru-RU.md new file mode 100644 index 0000000000..5669731dd9 --- /dev/null +++ b/README.ru-RU.md @@ -0,0 +1,303 @@ +# Алгоритмы и структуры данных в JavaScript + +[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) + +В этом репозитории содержатся базовые JavaScript-примеры +многих популярных алгоритмов и структур данных. + +Для каждого алгоритма и структуры данных есть свой файл README +с соответствующими пояснениями и ссылками на материалы для дальнейшего +изучения (в том числе и ссылки на видеоролики в Ютубе). + +_Читать на других языках:_ +[_English_](https://github.com/trekhleb/javascript-algorithms/), +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_한국어_](README.ko-KR.md), +[_日本語_](README.ja-JP.md), +[_Polski_](README.pl-PL.md), +[_Français_](README.fr-FR.md), +[_Español_](README.es-ES.md), +[_Português_](README.pt-BR.md) + +*☝ Замечание: этот репозиторий предназначен только для +учебно-исследовательских целей (**не** для продакшена).* + +## Структуры данных + +Структура данных — определённый способ систематизации и хранения данных в компьютере таким образом, +чтобы они могли быть легко доступны и изменяемы. Структура данных — совокупность коллекции значений +данных, взаимосвязей между ними и функций или операций, которые могут применяться к данным. + +`B` - Новичок, `A` - Продвинутый + +* `B` [Связный список](src/data-structures/linked-list) +* `B` [Двунаправленный связный список](src/data-structures/doubly-linked-list) +* `B` [Очередь](src/data-structures/queue) +* `B` [Стек](src/data-structures/stack) +* `B` [Хеш-табица](src/data-structures/hash-table) +* `B` [Куча](src/data-structures/heap) — максимальная и минимальная версии +* `B` [Очередь с приоритетом](src/data-structures/priority-queue) +* `A` [Префиксное дерево](src/data-structures/trie) +* `A` [Деревья](src/data-structures/tree) + * `A` [Двоичное дерево поиска](src/data-structures/tree/binary-search-tree) + * `A` [АВЛ-дерево](src/data-structures/tree/avl-tree) + * `A` [Красно-чёрное дерево](src/data-structures/tree/red-black-tree) + * `A` [Дерево отрезков](src/data-structures/tree/segment-tree) — для минимума, максимума и суммы отрезков + * `A` [Дерево Фенвика](src/data-structures/tree/fenwick-tree) (двоичное индексированное дерево) +* `A` [Граф](src/data-structures/graph) (ориентированный и неориентированный) +* `A` [Система непересекающихся множеств](src/data-structures/disjoint-set) +* `A` [Фильтр Блума](src/data-structures/bloom-filter) + +## Алгоритмы + +Алгоритм — однозначная спецификация по решению целого ряда задач (иными словами, +это список правил, чётко определяющих ту или иную последовательность операций). + +`B` — Новичок, `A` — Продвинутый + +### Тематическое разделение алгоритмов + +* **Математика** + * `B` [Битовые манипуляции](src/algorithms/math/bits) — получение/запись/сброс/обновление битов, умножение/деление на 2, сделать отрицательным и т.п. + * `B` [Факториал](src/algorithms/math/factorial) + * `B` [Числа Фибоначчи](src/algorithms/math/fibonacci) — классическое решение, решение в замкнутой форме + * `B` [Тест простоты](src/algorithms/math/primality-test) (метод пробного деления) + * `B` [Алгоритм Евклида](src/algorithms/math/euclidean-algorithm) — нахождение наибольшего общего делителя (НОД) + * `B` [Наименьшее общее кратное](src/algorithms/math/least-common-multiple) (НОК) + * `B` [Решето Эратосфена](src/algorithms/math/sieve-of-eratosthenes) — нахождение всех простых чисел до некоторого целого числа n + * `B` [Степень двойки](src/algorithms/math/is-power-of-two) — является ли число степенью двойки (простое и побитовое решения) + * `B` [Треугольник Паскаля](src/algorithms/math/pascal-triangle) + * `B` [Комплексные числа](src/algorithms/math/complex-number) — комплексные числа, базовые операции над ними + * `B` [Радианы и градусы](src/algorithms/math/radian) — конвертирование радианов в градусы и наоборот + * `B` [Быстрое возведение в степень](src/algorithms/math/fast-powering) + * `A` [Разбиение числа](src/algorithms/math/integer-partition) + * `A` [Квадратный корень](src/algorithms/math/square-root) — метод Ньютона + * `A` [Алгоритм Лю Хуэя](src/algorithms/math/liu-hui) — расчёт числа π с заданной точностью методом вписанных правильных многоугольников + * `A` [Дискретное преобразование Фурье](src/algorithms/math/fourier-transform) — разложение временной функции (сигнала) на частотные составляющие +* **Множества** + * `B` [Декартово произведение](src/algorithms/sets/cartesian-product) — результат перемножения множеств + * `B` [Тасование Фишера — Йетса](src/algorithms/sets/fisher-yates) — создание случайных перестановок конечного множества + * `A` [Булеан](src/algorithms/sets/power-set) — все подмножества заданного множества (побитовый поиск и поиск с возвратом) + * `A` [Перестановки](src/algorithms/sets/permutations) (с повторениями и без повторений) + * `A` [Сочетания](src/algorithms/sets/combinations) (с повторениями и без повторений) + * `A` [Наибольшая общая подпоследовательность](src/algorithms/sets/longest-common-subsequence) + * `A` [Наибольшая увеличивающаяся подпоследовательность](src/algorithms/sets/longest-increasing-subsequence) + * `A` [Наименьшая общая суперпоследовательность](src/algorithms/sets/shortest-common-supersequence) + * `A` [Задача о рюкзаке](src/algorithms/sets/knapsack-problem) — "0/1" и "неограниченный" рюкзаки + * `A` [Максимальный подмассив](src/algorithms/sets/maximum-subarray) — метод полного перебора и алгоритм Кадане + * `A` [Комбинации сумм](src/algorithms/sets/combination-sum) — нахождение всех комбинаций, сумма каждой из которых равна заданному числу +* **Алгоритмы на строках** + * `B` [Расстояние Хэмминга](src/algorithms/string/hamming-distance) — число позиций, в которых соответствующие символы различны + * `A` [Расстояние Левенштейна](src/algorithms/string/levenshtein-distance) — метрика, измеряющая разность между двумя последовательностями + * `A` [Алгоритм Кнута — Морриса — Пратта](src/algorithms/string/knuth-morris-pratt) — поиск подстроки (сопоставление с шаблоном) + * `A` [Z-функция](src/algorithms/string/z-algorithm) — поиск подстроки (сопоставление с шаблоном) + * `A` [Алгоритм Рабина — Карпа](src/algorithms/string/rabin-karp) — поиск подстроки + * `A` [Наибольшая общая подстрока](src/algorithms/string/longest-common-substring) + * `A` [Разборщик регулярных выражений](src/algorithms/string/regular-expression-matching) +* **Алгоритмы поиска** + * `B` [Линейный поиск](src/algorithms/search/linear-search) + * `B` [Поиск с перескоком](src/algorithms/search/jump-search) (поиск блоков) — поиск в упорядоченном массиве + * `B` [Двоичный поиск](src/algorithms/search/binary-search) — поиск в упорядоченном массиве + * `B` [Интерполяционный поиск](src/algorithms/search/interpolation-search) — поиск в равномерно распределённом упорядоченном массиве. +* **Сортировки** + * `B` [Сортировка пузырьком](src/algorithms/sorting/bubble-sort) + * `B` [Сортировка выбором](src/algorithms/sorting/selection-sort) + * `B` [Сортировка вставками](src/algorithms/sorting/insertion-sort) + * `B` [Пирамидальная сортировка (сортировка кучей)](src/algorithms/sorting/heap-sort) + * `B` [Сортировка слиянием](src/algorithms/sorting/merge-sort) + * `B` [Быстрая сортировка](src/algorithms/sorting/quick-sort) — с использованием дополнительной памяти и без её использования + * `B` [Сортировка Шелла](src/algorithms/sorting/shell-sort) + * `B` [Сортировка подсчётом](src/algorithms/sorting/counting-sort) + * `B` [Поразрядная сортировка](src/algorithms/sorting/radix-sort) +* **Связный список** + * `B` [Прямой обход](src/algorithms/linked-list/traversal) + * `B` [Обратный обход](src/algorithms/linked-list/reverse-traversal) +* **Деревья** + * `B` [Поиск в глубину](src/algorithms/tree/depth-first-search) + * `B` [Поиск в ширину](src/algorithms/tree/breadth-first-search) +* **Графы** + * `B` [Поиск в глубину](src/algorithms/graph/depth-first-search) + * `B` [Поиск в ширину](src/algorithms/graph/breadth-first-search) + * `B` [Алгоритм Краскала](src/algorithms/graph/kruskal) — нахождение минимального остовного дерева для взвешенного неориентированного графа + * `A` [Алгоритм Дейкстры](src/algorithms/graph/dijkstra) — нахождение кратчайших путей от одной из вершин графа до всех остальных + * `A` [Алгоритм Беллмана — Форда](src/algorithms/graph/bellman-ford) — нахождение кратчайших путей от одной из вершин графа до всех остальных + * `A` [Алгоритм Флойда — Уоршелла](src/algorithms/graph/floyd-warshall) — нахождение кратчайших расстояний между всеми вершинами графа + * `A` [Задача нахождения цикла](src/algorithms/graph/detect-cycle) — для ориентированных и неориентированных графов (на основе поиска в глубину и системы непересекающихся множеств) + * `A` [Алгоритм Прима](src/algorithms/graph/prim) — нахождение минимального остовного дерева для взвешенного неориентированного графа + * `A` [Топологическая сортировка](src/algorithms/graph/topological-sorting) — на основе поиска в глубину + * `A` [Шарниры (разделяющие вершины)](src/algorithms/graph/articulation-points) — алгоритм Тарьяна (на основе поиска в глубину) + * `A` [Мосты](src/algorithms/graph/bridges) — на основе поиска в глубину + * `A` [Эйлеров путь и Эйлеров цикл](src/algorithms/graph/eulerian-path) — алгоритм Флёри (однократное посещение каждой вершины) + * `A` [Гамильтонов цикл](src/algorithms/graph/hamiltonian-cycle) — проходит через каждую вершину графа ровно один раз + * `A` [Компоненты сильной связности](src/algorithms/graph/strongly-connected-components) — алгоритм Косарайю + * `A` [Задача коммивояжёра](src/algorithms/graph/travelling-salesman) — кратчайший маршрут, проходящий через указанные города с последующим возвратом в исходный город +* **Криптография** + * `B` [Полиноминальный хэш](src/algorithms/cryptography/polynomial-hash) — функция кольцевого хэша, основанная на полиноме +* **Машинное обучение** + * `B` [Нано-нейрон](https://github.com/trekhleb/nano-neuron) — 7 простых JavaScript функций, отображающих способности машины к обучению (прямое и обратное распространение) +* **Прочие алгоритмы** + * `B` [Ханойская башня](src/algorithms/uncategorized/hanoi-tower) + * `B` [Поворот квадратной матрицы](src/algorithms/uncategorized/square-matrix-rotation) — используется дополнительная память + * `B` [Прыжки](src/algorithms/uncategorized/jump-game) — на основе бэктрекинга, динамического программирования (сверху-вниз + снизу-вверх) и жадных алгоритмов + * `B` [Поиск уникальных путей](src/algorithms/uncategorized/unique-paths) — на основе бэктрекинга, динамического программирования и треугольника Паскаля + * `B` [Подсчёт дождевой воды](src/algorithms/uncategorized/rain-terraces) — на основе перебора и динамического программирования + * `B` [Задача о рекурсивной лестнице](src/algorithms/uncategorized/recursive-staircase) — подсчёт количества путей, по которым можно достичь верха лестницы (4 способа) + * `A` [Задача об N ферзях](src/algorithms/uncategorized/n-queens) + * `A` [Маршрут коня](src/algorithms/uncategorized/knight-tour) + +### Парадигмы программирования + +Парадигма программирования — общий метод или подход, лежащий в основе целого класса алгоритмов. +Понятие "парадигма программирования" является более абстрактным по отношению к понятию "алгоритм", +которое в свою очередь является более абстрактным по отношению к понятию "компьютерная пограмма". + +* **Алгоритмы полного перебора** — поиск лучшего решения исчерпыванием всевозможных вариантов + * `B` [Линейный поиск](src/algorithms/search/linear-search) + * `B` [Подсчёт дождевой воды](src/algorithms/uncategorized/rain-terraces) + * `B` [Задача о рекурсивной лестнице](src/algorithms/uncategorized/recursive-staircase) — подсчёт количества путей, по которым можно достичь верха лестницы + * `A` [Максимальный подмассив](src/algorithms/sets/maximum-subarray) + * `A` [Задача коммивояжёра](src/algorithms/graph/travelling-salesman) — кратчайший маршрут, проходящий через указанные города с последующим возвратом в исходный город + * `A` [Дискретное преобразование Фурье](src/algorithms/math/fourier-transform) — разложение временной функции (сигнала) на частотные составляющие +* **Жадные алгоритмы** — принятие локально оптимальных решений с учётом допущения об оптимальности конечного решения + * `B` [Прыжки](src/algorithms/uncategorized/jump-game) + * `A` [Задача о неограниченном рюкзаке](src/algorithms/sets/knapsack-problem) + * `A` [Алгоритм Дейкстры](src/algorithms/graph/dijkstra) — нахождение кратчайших путей от одной из вершин графа до всех остальных + * `A` [Алгоритм Прима](src/algorithms/graph/prim) — нахождение минимального остовного дерева для взвешенного неориентированного графа + * `A` [Алгоритм Краскала](src/algorithms/graph/kruskal) — нахождение минимального остовного дерева для взвешенного неориентированного графа +* **Разделяй и властвуй** — рекурсивное разбиение решаемой задачи на более мелкие + * `B` [Двоичный поиск](src/algorithms/search/binary-search) + * `B` [Ханойская башня](src/algorithms/uncategorized/hanoi-tower) + * `B` [Треугольник Паскаля](src/algorithms/math/pascal-triangle) + * `B` [Алгоритм Евклида](src/algorithms/math/euclidean-algorithm) — нахождение наибольшего общего делителя (НОД) + * `B` [Сортировка слиянием](src/algorithms/sorting/merge-sort) + * `B` [Быстрая сортировка](src/algorithms/sorting/quick-sort) + * `B` [Поиск в глубину (дерево)](src/algorithms/tree/depth-first-search) + * `B` [Поиск в глубину (граф)](src/algorithms/graph/depth-first-search) + * `B` [Прыжки](src/algorithms/uncategorized/jump-game) + * `B` [Быстрое возведение в степень](src/algorithms/math/fast-powering) + * `A` [Перестановки](src/algorithms/sets/permutations) (с повторениями и без повторений) + * `A` [Сочетания](src/algorithms/sets/combinations) (с повторениями и без повторений) +* **Динамическое программирование** — решение общей задачи конструируется на основе ранее найденных решений подзадач + * `B` [Числа Фибоначчи](src/algorithms/math/fibonacci) + * `B` [Прыжки](src/algorithms/uncategorized/jump-game) + * `B` [Поиск уникальных путей](src/algorithms/uncategorized/unique-paths) + * `B` [Подсчёт дождевой воды](src/algorithms/uncategorized/rain-terraces) + * `B` [Задача о рекурсивной лестнице](src/algorithms/uncategorized/recursive-staircase) — подсчёт количества путей, по которым можно достичь верха лестницы + * `A` [Расстояние Левенштейна](src/algorithms/string/levenshtein-distance) — метрика, измеряющая разность между двумя последовательностями + * `A` [Наибольшая общая подпоследовательность](src/algorithms/sets/longest-common-subsequence) + * `A` [Наибольшая общая подстрока](src/algorithms/string/longest-common-substring) + * `A` [Наибольшая увеличивающаяся подпоследовательность](src/algorithms/sets/longest-increasing-subsequence) + * `A` [Наименьшая общая суперпоследовательность](src/algorithms/sets/shortest-common-supersequence) + * `A` [Рюкзак 0-1](src/algorithms/sets/knapsack-problem) + * `A` [Разбиение числа](src/algorithms/math/integer-partition) + * `A` [Максимальный подмассив](src/algorithms/sets/maximum-subarray) + * `A` [Алгоритм Беллмана — Форда](src/algorithms/graph/bellman-ford) — поиск кратчайшего пути во взвешенном графе + * `A` [Алгоритм Флойда — Уоршелла](src/algorithms/graph/floyd-warshall) — нахождение кратчайших путей от одной из вершин графа до всех остальных + * `A` [Разборщик регулярных выражений](src/algorithms/string/regular-expression-matching) +* **Поиск с возвратом (бэктрекинг)** — при поиске решения многократно делается попытка расширить текущее частичное решение. Если расширение +невозможно, то происходит возврат к предыдущему более короткому частичному решению, и делается попытка его расширить другим возможным способом. +Обычно используется обход пространства состояний в глубину. + * `B` [Прыжки](src/algorithms/uncategorized/jump-game) + * `B` [Поиск уникальных путей](src/algorithms/uncategorized/unique-paths) + * `B` [Булеан](src/algorithms/sets/power-set) — все подмножества заданного множества + * `A` [Гамильтонов цикл](src/algorithms/graph/hamiltonian-cycle) — проходит через каждую вершину графа ровно один раз + * `A` [Задача об N ферзях](src/algorithms/uncategorized/n-queens) + * `A` [Маршрут коня](src/algorithms/uncategorized/knight-tour) + * `A` [Комбинации сумм](src/algorithms/sets/combination-sum) — нахождение всех комбинаций, сумма каждой из которых равна заданному числу +* **Метод ветвей и границ** — основан на упорядоченном переборе решений и рассмотрении только тех из них, которые являются перспективными +(по тем или иным признакам) и отбрасывании бесперспективных множеств решений. Обычно используется обход в ширину в совокупности с обходом +дерева пространства состояний в глубину. + +## Команды по использованию репозитория + +**Установка всех зависимостей** +``` +npm install +``` + +**Запустить ESLint** + +Возможно, эта команда потребуется Вам для проверки качества кода. + +``` +npm run lint +``` + +**Запустить все тесты** +``` +npm test +``` + +**Запустить определённый тест** +``` +npm test -- 'LinkedList' +``` + +**Playground** + +Вы можете поэкспериментировать с алгоритмами и структурами данных в файле `./src/playground/playground.js` +(файл `./src/playground/__test__/playground.test.js` предназначен для написания тестов). + +Для проверки работоспособности вашего кода используйте команду: + +``` +npm test -- 'playground' +``` + +## Полезная информация + +### Ссылки + +[▶ О структурах данных и алгоритмах](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) + +### Нотация «О» большое + +*Нотация «О» большое* используется для классификации алгоритмов в соответствии с ростом времени выполнения и затрачиваемой памяти при увеличении размера входных данных. +На диаграмме ниже представлены общие порядки роста алгоритмов в соответствии с нотацией «О» большое. + +![Big O graphs](./assets/big-o-graph.png) + +Источник: [Big O Cheat Sheet](http://bigocheatsheet.com/). + +Ниже представлены часто используемые обозначения в нотации «О» большое, а также сравнение их производительностей на различных размерах входных данных. + +| Нотация «О» большое | 10 элементов | 100 элементов | 1000 элементов | +| ------------------- | ------------ | ------------- | -------------- | +| **O(1)** | 1 | 1 | 1 | +| **O(log N)** | 3 | 6 | 9 | +| **O(N)** | 10 | 100 | 1000 | +| **O(N log N)** | 30 | 600 | 9000 | +| **O(N^2)** | 100 | 10000 | 1000000 | +| **O(2^N)** | 1024 | 1.26e+29 | 1.07e+301 | +| **O(N!)** | 3628800 | 9.3e+157 | 4.02e+2567 | + +### Сложности операций в структурах данных + +| Структура данных | Получение | Поиск | Вставка | Удаление | Комментарии | +| -------------------------- | :-------: | :-------: | :-------: | :-------: | :---------- | +| **Массив** | 1 | n | n | n | | +| **Стек** | n | n | 1 | 1 | | +| **Очередь** | n | n | 1 | 1 | | +| **Связный список** | n | n | 1 | n | | +| **Хеш-таблица** | - | n | n | n | Для идеальной хеш-функции — O(1) | +| **Двоичное дерево поиска** | n | n | n | n | В сбалансированном дереве — O(log(n)) | +| **B-дерево** | log(n) | log(n) | log(n) | log(n) | | +| **Красно-чёрное дерево** | log(n) | log(n) | log(n) | log(n) | | +| **АВЛ-дерево** | log(n) | log(n) | log(n) | log(n) | | +| **Фильтр Блума** | - | 1 | 1 | - | Возможно получение ложноположительного срабатывания | + +### Сложности алгоритмов сортировки + +| Наименование | Лучший случай | Средний случай | Худший случай | Память | Устойчивость | Комментарии | +| -------------------------- | :-----------: | :------------: | :-----------: | :----: | :----------: | :---------- | +| **Сортировка пузырьком** | n | n2 | n2 | 1 | Да | | +| **Сортировка вставками** | n | n2 | n2 | 1 | Да | | +| **Сортировка выбором** | n2 | n2 | n2 | 1 | Нет | | +| **Сортировка кучей** | n log(n) | n log(n) | n log(n) | 1 | Нет | | +| **Сортировка слиянием** | n log(n) | n log(n) | n log(n) | n | Да | | +| **Быстрая сортировка** | n log(n) | n log(n) | n2 | log(n) | Нет | Быстрая сортировка обычно выполняется с использованием O(log(n)) дополнительной памяти | +| **Сортировка Шелла** | n log(n) | зависит от выбранных шагов | n (log(n))2 | 1 | Нет | | +| **Сортировка подсчётом** | n + r | n + r | n + r | n + r | Да | r — наибольшее число в массиве | +| **Поразрядная сортировка** | n * k | n * k | n * k | n + k | Да | k — длина самого длинного ключа | From e55dc809b6fc0053747d048ef7b3ecb1fd9a4672 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 9 Dec 2020 08:37:37 +0100 Subject: [PATCH 008/264] Add README in Russian. --- README.es-ES.md | 3 ++- README.fr-FR.md | 3 ++- README.ja-JP.md | 3 ++- README.ko-KR.md | 3 ++- README.md | 5 ++-- README.pl-PL.md | 3 ++- README.pt-BR.md | 3 ++- README.ru-RU.md | 68 ++++++++++++++++++++----------------------------- README.tr-TR.md | 3 ++- README.zh-CN.md | 3 ++- README.zh-TW.md | 3 ++- 11 files changed, 49 insertions(+), 51 deletions(-) diff --git a/README.es-ES.md b/README.es-ES.md index 5f190efc76..a65ca9f096 100644 --- a/README.es-ES.md +++ b/README.es-ES.md @@ -18,7 +18,8 @@ _Léelo en otros idiomas:_ [_Polski_](README.pl-PL.md), [_Français_](README.fr-FR.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Русский_](README.ru-RU.md) *☝ Nótese que este proyecto está pensado con fines de aprendizaje e investigación, y **no** para ser usado en producción.* diff --git a/README.fr-FR.md b/README.fr-FR.md index f1c79d77a4..6559542132 100644 --- a/README.fr-FR.md +++ b/README.fr-FR.md @@ -19,7 +19,8 @@ _Lisez ceci dans d'autres langues:_ [_Polski_](README.pl-PL.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Русский_](README.ru-RU.md) ## Data Structures diff --git a/README.ja-JP.md b/README.ja-JP.md index d80e6bfbc7..f166cd2d78 100644 --- a/README.ja-JP.md +++ b/README.ja-JP.md @@ -18,7 +18,8 @@ _Read this in other languages:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Русский_](README.ru-RU.md) ## データ構造 diff --git a/README.ko-KR.md b/README.ko-KR.md index 2dccf75bd6..7759e33bca 100644 --- a/README.ko-KR.md +++ b/README.ko-KR.md @@ -17,7 +17,8 @@ _Read this in other languages:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Русский_](README.ru-RU.md) ## 자료 구조 diff --git a/README.md b/README.md index a8d1b9e7f6..f49f578424 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,11 @@ _Read this in other languages:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Русский_](README.ru-RU.md) *☝ Note that this project is meant to be used for learning and researching purposes -only and it is **not** meant to be used for production.* +only, and it is **not** meant to be used for production.* ## Data Structures diff --git a/README.pl-PL.md b/README.pl-PL.md index f2b76b1dab..8d2faa4b73 100644 --- a/README.pl-PL.md +++ b/README.pl-PL.md @@ -19,7 +19,8 @@ _Read this in other languages:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Русский_](README.ru-RU.md) ## Struktury Danych diff --git a/README.pt-BR.md b/README.pt-BR.md index a1556c7fc2..74f7709075 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -19,7 +19,8 @@ _Leia isto em outros idiomas:_ [_Polski_](README.pl-PL.md), [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Русский_](README.ru-RU.md) ## Estrutura de Dados diff --git a/README.ru-RU.md b/README.ru-RU.md index 5669731dd9..b52a5b4232 100644 --- a/README.ru-RU.md +++ b/README.ru-RU.md @@ -1,14 +1,11 @@ -# Алгоритмы и структуры данных в JavaScript +# Алгоритмы и структуры данных на JavaScript [![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) -В этом репозитории содержатся базовые JavaScript-примеры -многих популярных алгоритмов и структур данных. +В этом репозитории содержатся базовые JavaScript-примеры многих популярных алгоритмов и структур данных. -Для каждого алгоритма и структуры данных есть свой файл README -с соответствующими пояснениями и ссылками на материалы для дальнейшего -изучения (в том числе и ссылки на видеоролики в Ютубе). +Для каждого алгоритма и структуры данных есть свой файл README с соответствующими пояснениями и ссылками на материалы для дальнейшего изучения (в том числе и ссылки на видеоролики в YouTube). _Читать на других языках:_ [_English_](https://github.com/trekhleb/javascript-algorithms/), @@ -21,16 +18,13 @@ _Читать на других языках:_ [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md) -*☝ Замечание: этот репозиторий предназначен только для -учебно-исследовательских целей (**не** для продакшена).* +*☝ Замечание: этот репозиторий предназначен для учебно-исследовательских целей (**не** для использования в продакшн-системах).* ## Структуры данных -Структура данных — определённый способ систематизации и хранения данных в компьютере таким образом, -чтобы они могли быть легко доступны и изменяемы. Структура данных — совокупность коллекции значений -данных, взаимосвязей между ними и функций или операций, которые могут применяться к данным. +Структура данных (англ. data structure) — программная единица, позволяющая хранить и обрабатывать множество однотипных и/или логически связанных данных в вычислительной технике. Для добавления, поиска, изменения и удаления данных структура данных предоставляет некоторый набор функций, составляющих её интерфейс. -`B` - Новичок, `A` - Продвинутый +`B` - Базовый уровень, `A` - Продвинутый уровень * `B` [Связный список](src/data-structures/linked-list) * `B` [Двунаправленный связный список](src/data-structures/doubly-linked-list) @@ -52,12 +46,11 @@ _Читать на других языках:_ ## Алгоритмы -Алгоритм — однозначная спецификация по решению целого ряда задач (иными словами, -это список правил, чётко определяющих ту или иную последовательность операций). +Алгоритм — конечная совокупность точно заданных правил решения некоторого класса задач или набор инструкций, описывающих порядок действий исполнителя для решения некоторой задачи. -`B` — Новичок, `A` — Продвинутый +`B` - Базовый уровень, `A` - Продвинутый уровень -### Тематическое разделение алгоритмов +### Алгоритмы по тематике * **Математика** * `B` [Битовые манипуляции](src/algorithms/math/bits) — получение/запись/сброс/обновление битов, умножение/деление на 2, сделать отрицательным и т.п. @@ -84,11 +77,11 @@ _Читать на других языках:_ * `A` [Сочетания](src/algorithms/sets/combinations) (с повторениями и без повторений) * `A` [Наибольшая общая подпоследовательность](src/algorithms/sets/longest-common-subsequence) * `A` [Наибольшая увеличивающаяся подпоследовательность](src/algorithms/sets/longest-increasing-subsequence) - * `A` [Наименьшая общая суперпоследовательность](src/algorithms/sets/shortest-common-supersequence) + * `A` [Наименьшая общая супер-последовательность](src/algorithms/sets/shortest-common-supersequence) * `A` [Задача о рюкзаке](src/algorithms/sets/knapsack-problem) — "0/1" и "неограниченный" рюкзаки - * `A` [Максимальный подмассив](src/algorithms/sets/maximum-subarray) — метод полного перебора и алгоритм Кадане + * `A` [Максимальный под-массив](src/algorithms/sets/maximum-subarray) — метод полного перебора и алгоритм Кадане * `A` [Комбинации сумм](src/algorithms/sets/combination-sum) — нахождение всех комбинаций, сумма каждой из которых равна заданному числу -* **Алгоритмы на строках** +* **Алгоритмы работы со строками** * `B` [Расстояние Хэмминга](src/algorithms/string/hamming-distance) — число позиций, в которых соответствующие символы различны * `A` [Расстояние Левенштейна](src/algorithms/string/levenshtein-distance) — метрика, измеряющая разность между двумя последовательностями * `A` [Алгоритм Кнута — Морриса — Пратта](src/algorithms/string/knuth-morris-pratt) — поиск подстроки (сопоставление с шаблоном) @@ -101,7 +94,7 @@ _Читать на других языках:_ * `B` [Поиск с перескоком](src/algorithms/search/jump-search) (поиск блоков) — поиск в упорядоченном массиве * `B` [Двоичный поиск](src/algorithms/search/binary-search) — поиск в упорядоченном массиве * `B` [Интерполяционный поиск](src/algorithms/search/interpolation-search) — поиск в равномерно распределённом упорядоченном массиве. -* **Сортировки** +* **Алгоритмы сортировки** * `B` [Сортировка пузырьком](src/algorithms/sorting/bubble-sort) * `B` [Сортировка выбором](src/algorithms/sorting/selection-sort) * `B` [Сортировка вставками](src/algorithms/sorting/insertion-sort) @@ -147,11 +140,9 @@ _Читать на других языках:_ * `A` [Задача об N ферзях](src/algorithms/uncategorized/n-queens) * `A` [Маршрут коня](src/algorithms/uncategorized/knight-tour) -### Парадигмы программирования +### Алгоритмы по парадигме программирования -Парадигма программирования — общий метод или подход, лежащий в основе целого класса алгоритмов. -Понятие "парадигма программирования" является более абстрактным по отношению к понятию "алгоритм", -которое в свою очередь является более абстрактным по отношению к понятию "компьютерная пограмма". +Парадигма программирования — общий метод или подход, лежащий в основе целого класса алгоритмов. Понятие "парадигма программирования" является более абстрактным по отношению к понятию "алгоритм", которое в свою очередь является более абстрактным по отношению к понятию "компьютерная программа". * **Алгоритмы полного перебора** — поиск лучшего решения исчерпыванием всевозможных вариантов * `B` [Линейный поиск](src/algorithms/search/linear-search) @@ -196,9 +187,7 @@ _Читать на других языках:_ * `A` [Алгоритм Беллмана — Форда](src/algorithms/graph/bellman-ford) — поиск кратчайшего пути во взвешенном графе * `A` [Алгоритм Флойда — Уоршелла](src/algorithms/graph/floyd-warshall) — нахождение кратчайших путей от одной из вершин графа до всех остальных * `A` [Разборщик регулярных выражений](src/algorithms/string/regular-expression-matching) -* **Поиск с возвратом (бэктрекинг)** — при поиске решения многократно делается попытка расширить текущее частичное решение. Если расширение -невозможно, то происходит возврат к предыдущему более короткому частичному решению, и делается попытка его расширить другим возможным способом. -Обычно используется обход пространства состояний в глубину. +* **Поиск с возвратом (бэктрекинг)** — при поиске решения многократно делается попытка расширить текущее частичное решение. Если расширение невозможно, то происходит возврат к предыдущему более короткому частичному решению, и делается попытка его расширить другим возможным способом. Обычно используется обход пространства состояний в глубину. * `B` [Прыжки](src/algorithms/uncategorized/jump-game) * `B` [Поиск уникальных путей](src/algorithms/uncategorized/unique-paths) * `B` [Булеан](src/algorithms/sets/power-set) — все подмножества заданного множества @@ -206,38 +195,38 @@ _Читать на других языках:_ * `A` [Задача об N ферзях](src/algorithms/uncategorized/n-queens) * `A` [Маршрут коня](src/algorithms/uncategorized/knight-tour) * `A` [Комбинации сумм](src/algorithms/sets/combination-sum) — нахождение всех комбинаций, сумма каждой из которых равна заданному числу -* **Метод ветвей и границ** — основан на упорядоченном переборе решений и рассмотрении только тех из них, которые являются перспективными -(по тем или иным признакам) и отбрасывании бесперспективных множеств решений. Обычно используется обход в ширину в совокупности с обходом -дерева пространства состояний в глубину. +* **Метод ветвей и границ** — основан на упорядоченном переборе решений и рассмотрении только тех из них, которые являются перспективными (по тем или иным признакам) и отбрасывании бесперспективных множеств решений. Обычно используется обход в ширину в совокупности с обходом дерева пространства состояний в глубину. -## Команды по использованию репозитория +## Как использовать этот репозиторий **Установка всех зависимостей** ``` npm install ``` -**Запустить ESLint** +**Запуск ESLint** -Возможно, эта команда потребуется Вам для проверки качества кода. +Эта команда может потребоваться вам для проверки качества кода. ``` npm run lint ``` -**Запустить все тесты** +**Запуск всех тестов** + ``` npm test ``` -**Запустить определённый тест** +**Запуск определённого теста** + ``` npm test -- 'LinkedList' ``` -**Playground** +**Песочница** -Вы можете поэкспериментировать с алгоритмами и структурами данных в файле `./src/playground/playground.js` +Вы можете экспериментировать с алгоритмами и структурами данных в файле `./src/playground/playground.js` (файл `./src/playground/__test__/playground.test.js` предназначен для написания тестов). Для проверки работоспособности вашего кода используйте команду: @@ -254,8 +243,7 @@ npm test -- 'playground' ### Нотация «О» большое -*Нотация «О» большое* используется для классификации алгоритмов в соответствии с ростом времени выполнения и затрачиваемой памяти при увеличении размера входных данных. -На диаграмме ниже представлены общие порядки роста алгоритмов в соответствии с нотацией «О» большое. +*Нотация «О» большое* используется для классификации алгоритмов в соответствии с ростом времени выполнения и затрачиваемой памяти при увеличении размера входных данных. На диаграмме ниже представлены общие порядки роста алгоритмов в соответствии с нотацией «О» большое. ![Big O graphs](./assets/big-o-graph.png) @@ -286,7 +274,7 @@ npm test -- 'playground' | **B-дерево** | log(n) | log(n) | log(n) | log(n) | | | **Красно-чёрное дерево** | log(n) | log(n) | log(n) | log(n) | | | **АВЛ-дерево** | log(n) | log(n) | log(n) | log(n) | | -| **Фильтр Блума** | - | 1 | 1 | - | Возможно получение ложноположительного срабатывания | +| **Фильтр Блума** | - | 1 | 1 | - | Возможно получение ложно-положительного срабатывания | ### Сложности алгоритмов сортировки diff --git a/README.tr-TR.md b/README.tr-TR.md index c0fc6ee18d..0892e5f4a0 100644 --- a/README.tr-TR.md +++ b/README.tr-TR.md @@ -17,7 +17,8 @@ _Read this in other languages:_ [_Polski_](README.pl-PL.md), [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), -[_Português_](README.pt-BR.md) +[_Português_](README.pt-BR.md), +[_Русский_](README.ru-RU.md) *☝ Not, bu proje araştırma ve öğrenme amacı ile yapılmış olup üretim için **yaplılmamıştır**.* diff --git a/README.zh-CN.md b/README.zh-CN.md index cd95bc5c7b..e4f37ec506 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -16,7 +16,8 @@ _Read this in other languages:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Русский_](README.ru-RU.md) *注意:这个项目仅用于学习和研究,**不是**用于生产环境。* diff --git a/README.zh-TW.md b/README.zh-TW.md index 9d7bcb6314..8e5699cfdc 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -15,7 +15,8 @@ _Read this in other languages:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Русский_](README.ru-RU.md) ## 資料結構 From 1bfbf1e30642f6535d3b61ae848aa604321cb41c Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 9 Dec 2020 08:40:51 +0100 Subject: [PATCH 009/264] Add README in Russian. --- README.es-ES.md | 4 ++-- README.fr-FR.md | 4 ++-- README.ja-JP.md | 4 ++-- README.ko-KR.md | 4 ++-- README.md | 4 ++-- README.pl-PL.md | 4 ++-- README.pt-BR.md | 4 ++-- README.ru-RU.md | 3 ++- README.zh-CN.md | 4 ++-- README.zh-TW.md | 4 ++-- 10 files changed, 20 insertions(+), 19 deletions(-) diff --git a/README.es-ES.md b/README.es-ES.md index a65ca9f096..8a6706ce49 100644 --- a/README.es-ES.md +++ b/README.es-ES.md @@ -18,8 +18,8 @@ _Léelo en otros idiomas:_ [_Polski_](README.pl-PL.md), [_Français_](README.fr-FR.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md), -[_Русский_](README.ru-RU.md) +[_Русский_](README.ru-RU.md), +[_Türk_](README.tr-TR.md) *☝ Nótese que este proyecto está pensado con fines de aprendizaje e investigación, y **no** para ser usado en producción.* diff --git a/README.fr-FR.md b/README.fr-FR.md index 6559542132..a83cce4d01 100644 --- a/README.fr-FR.md +++ b/README.fr-FR.md @@ -19,8 +19,8 @@ _Lisez ceci dans d'autres langues:_ [_Polski_](README.pl-PL.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md), -[_Русский_](README.ru-RU.md) +[_Русский_](README.ru-RU.md), +[_Türk_](README.tr-TR.md) ## Data Structures diff --git a/README.ja-JP.md b/README.ja-JP.md index f166cd2d78..862a0d2bc0 100644 --- a/README.ja-JP.md +++ b/README.ja-JP.md @@ -18,8 +18,8 @@ _Read this in other languages:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md), -[_Русский_](README.ru-RU.md) +[_Русский_](README.ru-RU.md), +[_Türk_](README.tr-TR.md) ## データ構造 diff --git a/README.ko-KR.md b/README.ko-KR.md index 7759e33bca..c5fa8b1804 100644 --- a/README.ko-KR.md +++ b/README.ko-KR.md @@ -17,8 +17,8 @@ _Read this in other languages:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md), -[_Русский_](README.ru-RU.md) +[_Русский_](README.ru-RU.md), +[_Türk_](README.tr-TR.md) ## 자료 구조 diff --git a/README.md b/README.md index f49f578424..9d4d39622b 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,8 @@ _Read this in other languages:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md), -[_Русский_](README.ru-RU.md) +[_Русский_](README.ru-RU.md), +[_Türk_](README.tr-TR.md) *☝ Note that this project is meant to be used for learning and researching purposes only, and it is **not** meant to be used for production.* diff --git a/README.pl-PL.md b/README.pl-PL.md index 8d2faa4b73..26ca99c179 100644 --- a/README.pl-PL.md +++ b/README.pl-PL.md @@ -19,8 +19,8 @@ _Read this in other languages:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md), -[_Русский_](README.ru-RU.md) +[_Русский_](README.ru-RU.md), +[_Türk_](README.tr-TR.md) ## Struktury Danych diff --git a/README.pt-BR.md b/README.pt-BR.md index 74f7709075..626c5f65b7 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -19,8 +19,8 @@ _Leia isto em outros idiomas:_ [_Polski_](README.pl-PL.md), [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), -[_Türk_](README.tr-TR.md), -[_Русский_](README.ru-RU.md) +[_Русский_](README.ru-RU.md), +[_Türk_](README.tr-TR.md) ## Estrutura de Dados diff --git a/README.ru-RU.md b/README.ru-RU.md index b52a5b4232..fcfcf83b9f 100644 --- a/README.ru-RU.md +++ b/README.ru-RU.md @@ -16,7 +16,8 @@ _Читать на других языках:_ [_Polski_](README.pl-PL.md), [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), -[_Português_](README.pt-BR.md) +[_Português_](README.pt-BR.md), +[_Türk_](README.tr-TR.md) *☝ Замечание: этот репозиторий предназначен для учебно-исследовательских целей (**не** для использования в продакшн-системах).* diff --git a/README.zh-CN.md b/README.zh-CN.md index e4f37ec506..f63eab90b4 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -16,8 +16,8 @@ _Read this in other languages:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md), -[_Русский_](README.ru-RU.md) +[_Русский_](README.ru-RU.md), +[_Türk_](README.tr-TR.md) *注意:这个项目仅用于学习和研究,**不是**用于生产环境。* diff --git a/README.zh-TW.md b/README.zh-TW.md index 8e5699cfdc..50050b2786 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -15,8 +15,8 @@ _Read this in other languages:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md), -[_Русский_](README.ru-RU.md) +[_Русский_](README.ru-RU.md), +[_Türk_](README.tr-TR.md) ## 資料結構 From 7608151d9e598c6d7e1d91b092a72c53b8dc83b3 Mon Sep 17 00:00:00 2001 From: Riccardo Amadio Date: Wed, 9 Dec 2020 09:00:53 +0100 Subject: [PATCH 010/264] Italian Implementation (#432) * translating README to italian, middle phase * test * test grafica * finish * review Co-authored-by: Riccardo Amadio --- README.it-IT.md | 294 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 README.it-IT.md diff --git a/README.it-IT.md b/README.it-IT.md new file mode 100644 index 0000000000..8daa4ac62c --- /dev/null +++ b/README.it-IT.md @@ -0,0 +1,294 @@ +# Algoritmi e Strutture Dati in Javascript + +[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) + +Questa repository contiene esempi in Javascript dei più popolari algoritmi e strutture dati . + +Ogni algortimo e struttura dati ha il suo README separato e la relative spiegazioni e i link per ulteriori approfondimenti (compresi quelli su YouTube). + +_Leggilo in altre lingue:_ +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_한국어_](README.ko-KR.md), +[_日本語_](README.ja-JP.md), +[_Polski_](README.pl-PL.md), +[_Français_](README.fr-FR.md), +[_Español_](README.es-ES.md), +[_Português_](README.pt-BR.md), +[_Italian_](README.it-IT.md) + +*☝ Si noti che questo progetto è destinato ad essere utilizzato solo per l'apprendimento e la ricerca e non è destinato ad essere utilizzato per il commercio.* + +## Strutture Dati + +Una struttura dati è un particolare modo di organizzare e memorizzare i dati in un computer che permeta di accedervi e modificarli in modo efficiente. Più precisamente, una struttura dati è una raccolta di dati, le relazioni tra di essi e le funzioni o operazioni che possono essere applicate ai dati. + +`P` - Principiante, `A` - Avanzato + +* `P` [Lista Concatenata](src/data-structures/linked-list) +* `P` [Doppia Lista Concatenata](src/data-structures/doubly-linked-list) +* `P` [Coda](src/data-structures/queue) +* `P` [Pila](src/data-structures/stack) +* `P` [Hash Table](src/data-structures/hash-table) +* `P` [Heap](src/data-structures/heap) - versione massimo e minimo heap +* `P` [Coda di priorità](src/data-structures/priority-queue) +* `A` [Trie](src/data-structures/trie) +* `A` [Albero](src/data-structures/tree) + * `A` [Albero binario di ricerca](src/data-structures/tree/binary-search-tree) + * `A` [Albero AVL](src/data-structures/tree/avl-tree) + * `A` [RB Albero](src/data-structures/tree/red-black-tree) + * `A` [Albero Segmentato](src/data-structures/tree/segment-tree) - con min/max/sum esempi di query + * `A` [Albero di Fenwick](src/data-structures/tree/fenwick-tree) (Albero binario indicizzato) +* `A` [Grafo](src/data-structures/graph) (direzionale e unidirezionale) +* `A` [Set Disgiunto](src/data-structures/disjoint-set) +* `A` [Filtro Bloom](src/data-structures/bloom-filter) + +## Algoritmi + +Un algoritmo è una specifica univoca per risolvere una classe di problemi. È +un insieme di regole che definiscono con precisione una sequenza di operazioni. + +`P` - Principiante, `A` - Avanzato + +### Algoritmi per Topic + +* **Matematica** + * `P` [Manipolazione dei Bit](src/algorithms/math/bits) - set/get/update/clear bits, moltiplicazione/divisione per due, gestire numeri negativi etc. + * `P` [Fattoriale](src/algorithms/math/factorial) + * `P` [Numeri di Fibonacci](src/algorithms/math/fibonacci) - classico e forma chiusa + * `P` [Test di Primalità](src/algorithms/math/primality-test) (metodo del divisore) + * `P` [Algoritmo di Euclide](src/algorithms/math/euclidean-algorithm) - trova il massimo comune divisore (MCD) + * `P` [Minimo Comune Multiplo](src/algorithms/math/least-common-multiple) (MCM) + * `P` [Crivello di Eratostene](src/algorithms/math/sieve-of-eratosthenes) - trova i numeri i primi fino al limite indicato + * `P` [Potenza di due](src/algorithms/math/is-power-of-two) - controlla se il numero è una potenza di due + * `P` [Triangolo di Pascal](src/algorithms/math/pascal-triangle) + * `P` [Numeri Complessi](src/algorithms/math/complex-number) - numeri complessi e operazioni + * `P` [Radiante & Gradi](src/algorithms/math/radian) - conversione da radiante a gradi e viceversa + * `P` [Potenza di un Numero](src/algorithms/math/fast-powering) + * `A` [Partizione di un Intero](src/algorithms/math/integer-partition) + * `A` [Radice Quadrata](src/algorithms/math/square-root) - Metodo di Newton + * `A` [Algoritmo di Liu Hui π](src/algorithms/math/liu-hui) - calcolare π usando un poligono + * `A` [Trasformata Discreta di Fourier ](src/algorithms/math/fourier-transform) -decomporre una funzione di tempo (un segnale) nelle frequenze che lo compongono +* **Set** + * `P` [Prodotto Cartesiano](src/algorithms/sets/cartesian-product) - moltiplicazione multipla di set + * `P` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - permutazione casuale di un sequenza finita + * `A` [Power Set](src/algorithms/sets/power-set) - tutti i sottoinsiemi di un set (soluzioni bitwise e backtracking) + * `A` [Permutazioni](src/algorithms/sets/permutations) (con e senza ripetizioni) + * `A` [Combinazioni](src/algorithms/sets/combinations) (con e senza ripetizioni) + * `A` [Massima Sottosequenza Comune](src/algorithms/sets/longest-common-subsequence) (LCS) + * `A` [Massima Sottosequenza Crescente](src/algorithms/sets/longest-increasing-subsequence) + * `A` [Minima Sottosequenza Diffusa](src/algorithms/sets/shortest-common-supersequence) (SCS) + * `A` [Problema dello Zaino di Knapsack](src/algorithms/sets/knapsack-problem) - "0/1" e "Senza Restrizioni" + * `A` [Massimo SubArray](src/algorithms/sets/maximum-subarray) - "Brute Force" e "Programmazione Dinamica" versione Kadane + * `A` [Somma di Combinazioni](src/algorithms/sets/combination-sum) - ricerca di tutte le combinazioni di una somma +* **String** + * `P` [Distanza di Hamming](src/algorithms/string/hamming-distance) - numero di posizioni in cui i caratteri sono diversi + * `A` [Distanza di Levenshtein](src/algorithms/string/levenshtein-distance) - numero minimo di modifiche per rendere uguali due stringhe + * `A` [Algoritmo di Knuth-Morris-Pratt](src/algorithms/string/knuth-morris-pratt) (KMP) - ricerca nella sottostringa (pattern matching) + * `A` [Algoritmo Z](src/algorithms/string/z-algorithm) - ricerca nella sottostringa (pattern matching) + * `A` [Algoritmo di Rabin Karp ](src/algorithms/string/rabin-karp) - ricerca nella sottostringa + * `A` [Sottostringa Comune più lunga](src/algorithms/string/longest-common-substring) + * `A` [Espressioni Regolari](src/algorithms/string/regular-expression-matching) +* **Searches** + * `P` [Ricerca Sequenziale](src/algorithms/search/linear-search) + * `P` [Ricerca a Salti](src/algorithms/search/jump-search) (o Ricerca a Blocchi) - per la ricerca in array ordinati + * `P` [Ricerca Binari](src/algorithms/search/binary-search) - per la ricerca in array ordinati + * `P` [Ricerca Interpolata](src/algorithms/search/interpolation-search) - per la ricerca in un array ordinato uniformemente distibuito +* **Sorting** + * `P` [Bubble Sort](src/algorithms/sorting/bubble-sort) + * `P` [Selection Sort](src/algorithms/sorting/selection-sort) + * `P` [Insertion Sort](src/algorithms/sorting/insertion-sort) + * `P` [Heap Sort](src/algorithms/sorting/heap-sort) + * `P` [Merge Sort](src/algorithms/sorting/merge-sort) + * `P` [Quicksort](src/algorithms/sorting/quick-sort) - con e senza allocazione di ulteriore memoria + * `P` [Shellsort](src/algorithms/sorting/shell-sort) + * `P` [Counting Sort](src/algorithms/sorting/counting-sort) + * `P` [Radix Sort](src/algorithms/sorting/radix-sort) +* **Lista Concatenatas** + * `P` [Attraversamento Lista Concatenata](src/algorithms/linked-list/traversal) + * `P` [Attraversamento Lista Concatenata nel senso Contrario](src/algorithms/linked-list/reverse-traversal) +* **Alberi** + * `P` [Ricerca in Profondità su Alberi](src/algorithms/tree/depth-first-search) (DFS) + * `P` [Ricerca in Ampiezza su Alberi](src/algorithms/tree/breadth-first-search) (BFS) +* **Grafi** + * `P` [Ricerca in Profondità su Grafi](src/algorithms/graph/depth-first-search) (DFS) + * `P` [Breadth-First Search su Grafi](src/algorithms/graph/breadth-first-search) (BFS) + * `P` [Algoritmo di Kruskal](src/algorithms/graph/kruskal) - ricerca dell'Albero con Minima Distanza (MST) per grafi pesati unidirezionali + * `A` [Algoritmo di Dijkstra](src/algorithms/graph/dijkstra) - ricerca dei percorsi più breve per raggiungere tutti i vertici del grafo da un singolo vertice + * `A` [Algoritmo di Bellman-Ford](src/algorithms/graph/bellman-ford) - ricerca dei percorsi più breve per raggiungere tutti i vertici del grafo da un singolo vertice + * `A` [Algoritmo di Floyd-Warshall](src/algorithms/graph/floyd-warshall) - ricerca dei percorsi più brevi tra tutte le coppie di vertici + * `A` [Rivelamento dei Cicli](src/algorithms/graph/detect-cycle) - per grafici diretti e non diretti (basate su partizioni DFS e Disjoint Set) + * `A` [Algoritmo di Prim](src/algorithms/graph/prim) - ricerca dell'Albero Ricoprente Minimo (MST) per grafi unidirezionali pesati + * `A` [Ordinamento Topologico](src/algorithms/graph/topological-sorting) - metodo DFS + * `A` [Punti di Articolazione](src/algorithms/graph/articulation-points) - Algoritmo di Tarjan (basato su DFS) + * `A` [Bridges](src/algorithms/graph/bridges) - basato su DFS + * `A` [Cammino Euleriano e Circuito Euleriano](src/algorithms/graph/eulerian-path) - Algoritmo di Fleury - Visita ogni margine esattamente una volta + * `A` [Ciclo di Hamiltonian](src/algorithms/graph/hamiltonian-cycle) - Visita ad ogni vertice solo una volta + * `A` [Componenti Fortemente Connessa](src/algorithms/graph/strongly-connected-components) - algoritmo di Kosaraju + * `A` [Problema del Commesso Viaggiatore](src/algorithms/graph/travelling-salesman) - il percorso più breve che visita ogni città e ritorna alla città iniziale +* **Crittografia** + * `P` [Hash Polinomiale](src/algorithms/cryptography/polynomial-hash) - Una funzione hash di rolling basata sul polinomio +* **Senza categoria** + * `P` [Torre di Hanoi](src/algorithms/uncategorized/hanoi-tower) + * `P` [Rotazione Matrice Quadrata](src/algorithms/uncategorized/square-matrix-rotation) - algoritmo in memoria + * `P` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, programmazione dinamica (top-down + bottom-up) ed esempre di greeedy + * `P` [Percorsi Unici](src/algorithms/uncategorized/unique-paths) - backtracking, programmazione dinamica and l'esempio del Triangolo di Pascal + * `P` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - problema dell'acqua piovana in trappola(versione con programmazione dinamica e brute force) + * `P` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - contare il numero di percorsi per arrivare in vetta(4 soluzioni) + * `A` [Rompicapo delle Otto Regine](src/algorithms/uncategorized/n-queens) + * `A` [Percorso del Cavallo](src/algorithms/uncategorized/knight-tour) + +### Modelli di Algoritmi + + Un modello di algoritmo è un generico metodo o approcio che sta alla base della progettazione di una classe di algoritmi. + Si tratta di un'astrazione ancora più alta di un algoritmo, proprio come un algoritmo è un'astrazione di un programma del computer. + +* **Brute Force** - controlla tutte le possibilità e seleziona la migliore + * `P` [Ricerca Lineare](src/algorithms/search/linear-search) + * `P` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - problema dell'acqua piovana in trappola + * `P` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - contare il numero di percorsi per arrivare in vetta + * `A` [Massimo SubArray](src/algorithms/sets/maximum-subarray) + * `A` [Problema del commesso viaggiatore](src/algorithms/graph/travelling-salesman) - il percorso più breve che visita ogni città e ritorna alla città iniziale + * `A` [Trasformata Discreta di Fourier](src/algorithms/math/fourier-transform) - scomporre la funzione (segnale) del tempo in frequenze che la compongono +* **Greedy** - scegliere l'opzione migliore al momento d'eleborazione dell'algoritmo, senza alcuna considerazione per il futuro + * `P` [Jump Game](src/algorithms/uncategorized/jump-game) + * `A` [Problema dello Zaino di Knapsack](src/algorithms/sets/knapsack-problem) + * `A` [Algoritmo di Dijkstra](src/algorithms/graph/dijkstra) - ricerca del percorso più breve tra tutti i vertici del grafo + * `A` [Algoritmo di Prim](src/algorithms/graph/prim) - ricerca del Minimo Albero Ricoprente per grafi pesati e unidirezionali + * `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph +* **Divide e Conquista** - divide il problema in piccole parti e risolve ogni parte + * `P` [Ricerca Binaria](src/algorithms/search/binary-search) + * `P` [Torre di Hanoi](src/algorithms/uncategorized/hanoi-tower) + * `P` [Triangolo di Pascal](src/algorithms/math/pascal-triangle) + * `P` [Algoritmo di Euclide](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD) + * `P` [Merge Sort](src/algorithms/sorting/merge-sort) + * `P` [Quicksort](src/algorithms/sorting/quick-sort) + * `P` [Albero per Ricerca in Profondità](src/algorithms/tree/depth-first-search) (DFS) + * `P` [Grafo per Ricerca in Profondità](src/algorithms/graph/depth-first-search) (DFS) + * `P` [Jump Game](src/algorithms/uncategorized/jump-game) + * `P` [Algoritmo di Elevamento a Potenza](src/algorithms/math/fast-powering) + * `A` [Permutazioni](src/algorithms/sets/permutations) (con o senza ripetizioni) + * `A` [Combinazioni](src/algorithms/sets/combinations) (con o senza ripetizioni) +* **Programmazione Dinamica** - creare una soluzione utilizzando le sub-solution trovate in precedenza + * `P` [Numero di Fibonacci](src/algorithms/math/fibonacci) + * `P` [Jump Game](src/algorithms/uncategorized/jump-game) + * `P` [Percorsi Unici](src/algorithms/uncategorized/unique-paths) + * `P` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - problema dell'acqua piovana in trappola + * `P` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - contare il numero di percorsi per arrivare in vetta + * `A` [Distanza di Levenshtein](src/algorithms/string/levenshtein-distance) - minima variazione tra due sequenze + * `A` [La Più Lunga Frequente SottoSequenza](src/algorithms/sets/longest-common-subsequence) (LCS) + * `A` [La Più Lunga Frequente SubString](src/algorithms/string/longest-common-substring) + * `A` [La Più Lunga SottoSequenza Crescente](src/algorithms/sets/longest-increasing-subsequence) + * `A` [La Più Corta e Frequente SuperSequenza](src/algorithms/sets/shortest-common-supersequence) + * `A` [Problema dello zaino](src/algorithms/sets/knapsack-problem) + * `A` [Partizione di un Intero](src/algorithms/math/integer-partition) + * `A` [Massimo SubArray](src/algorithms/sets/maximum-subarray) + * `A` [Algoritmo di Bellman-Ford](src/algorithms/graph/bellman-ford) - ricerca del percorso più breve per tutti i vertici del grafo + * `A` [Algoritmo di Floyd-Warshall](src/algorithms/graph/floyd-warshall) - ricerca del percorso più breve tra tutte le coppie di vertici + * `A` [Espressioni Regolari](src/algorithms/string/regular-expression-matching) +* **Backtracking** - come la brute force, provate a generare tutte le soluzioni possibili, ma ogni volta che generate la prossima soluzione testate se soddisfa tutte le condizioni e solo allora continuare a generare soluzioni successive. Altrimenti, fate marcia indietro, e andate su un percorso diverso per trovare una soluzione. Normalmente si utilizza l'algoritmo DFS. + * `P` [Jump Game](src/algorithms/uncategorized/jump-game) + * `P` [Percorsi Unici](src/algorithms/uncategorized/unique-paths) + * `P` [Power Set](src/algorithms/sets/power-set) - tutti i subset di un set + * `A` [Ciclo di Hamiltonian](src/algorithms/graph/hamiltonian-cycle) - visita di tutti i vertici solamente una volta + * `A` [Problema di N-Queens](src/algorithms/uncategorized/n-queens) + * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour) + * `A` [Combinazioni di una Somma](src/algorithms/sets/combination-sum) - trovare tutte le combinazioni che compongono una somma +* **Branch & Bound** - ricordatevi che la soluzione meno costosa trovata ad ogni step durante il backtracking e +il costo di usare la soluzione meno costosa trovata fino al limite inferiore al costo minimo della soluzione al problema, +al fine di scartare soluzioni parziali con costi maggiori della soluzione meno costosa trovata . +Di solito si usa BFS trasversale in combinazione con DFS trasversale . + +## Come usare questa repository + +**Installare tutte le dipendenze** +``` +npm install +``` + +**Eseguire ESLint** + +Potresti usarlo per controllare la qualità del codice. + +``` +npm run lint +``` + +**Eseguire tutti i test** +``` +npm test +``` + +**Eseguire un test tramite il nome** +``` +npm test -- 'LinkedList' +``` + +**Playground** + +Se vuoi puoi giocare le strutture dati e gli algoritmi nel file ./src/playground/playground.js` e +scrivere test nel file `./src/playground/__test__/playground.test.js`. + +Poi puoi semplicemente eseguire il seguente comando per testare quello che hai scritto : + +``` +npm test -- 'playground' +``` + +## Informazioni Utili + +### Bibliografia + +[▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) + +### Notazione Big O + +* La notazione Big O* è usata per classificare algoritmi in base al tempo di esecuzione o ai +requisiti di spazio che crescono in base alla crescita dell'input . +Nella grafico qua sotto puoi trovare gli ordini di crescita più comuni degli algoritmi usando la notazione Big O. + +![Grafi Big O ](./assets/big-o-graph.png) + +Riferimento: [Big O Cheat Sheet](http://bigocheatsheet.com/). + +Nella tabella qua sotto ci sono riportate la lista delle notazioni Big O più usate e delle loro prestazioni comparate tra differenti grandezze d'input . + +| Notazione Big O | Computazione con 10 elementi | Computazione con 100 elementi | Computazione con 1000 elementi | +| --------------- | ---------------------------- | ----------------------------- | ------------------------------- | +| **O(1)** | 1 | 1 | 1 | +| **O(log N)** | 3 | 6 | 9 | +| **O(N)** | 10 | 100 | 1000 | +| **O(N log N)** | 30 | 600 | 9000 | +| **O(N^2)** | 100 | 10000 | 1000000 | +| **O(2^N)** | 1024 | 1.26e+29 | 1.07e+301 | +| **O(N!)** | 3628800 | 9.3e+157 | 4.02e+2567 | + +### Complessità delle Operazion sulle Strutture Dati + +| Struttura Dati | Accesso | Ricerca | Inserimento | Rimozione | Commenti | +| ----------------------- | :-------: | :-------: | :--------: | :-------: | :-------- | +| **Array** | 1 | n | n | n | | +| **Pila** | n | n | 1 | 1 | | +| **Coda** | n | n | 1 | 1 | | +| **Lista Concatenata** | n | n | 1 | n | | +| **Tabella Hash** | - | n | n | n | Nel caso di una funzione di hashing perfetta il costo sarebbe O(1)| +| **Binary Search Tree** | n | n | n | n | Nel caso di albero bilanciato il costo sarebbe O(log(n)) | +| **B-Tree** | log(n) | log(n) | log(n) | log(n) | | +| **Red-Black Tree** | log(n) | log(n) | log(n) | log(n) | | +| **Albero AVL** | log(n) | log(n) | log(n) | log(n) | | +| **Bloom Filter** | - | 1 | 1 | - | Falsi positivi sono possibili durante la ricerca | + +### Complessità degli Algoritmi di Ordinamento di Array + +| Nome | Milgiore | Media | Perggiore | Memoria | Stabile | Commenti | +| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | +| **Bubble sort** | n | n2 | n2 | 1 | Yes | | +| **Insertion sort** | n | n2 | n2 | 1 | Yes | | +| **Selection sort** | n2 | n2 | n2 | 1 | No | | +| **Heap sort** | n log(n) | n log(n) | n log(n) | 1 | No | | +| **Merge sort** | n log(n) | n log(n) | n log(n) | n | Yes | | +| **Quick sort** | n log(n) | n log(n) | n2 | log(n) | No | Quicksort viene eseguito in memoria solitamente con una pila di O(log(n)) | +| **Shell sort** | n log(n) | dipende dagli spazi vuoti nella sequenza | n (log(n))2 | 1 | No | | +| **Counting sort** | n + r | n + r | n + r | n + r | Yes | r - numero più grande nell'array | +| **Radix sort** | n * k | n * k | n * k | n + k | Yes | k - lunghezza della chiave più grande | From ea8234b49b426c1ea990d1ece0520059072c67e9 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 9 Dec 2020 09:20:24 +0100 Subject: [PATCH 011/264] Add README in Italian. --- README.es-ES.md | 3 ++- README.fr-FR.md | 3 ++- README.it-IT.md | 3 ++- README.ja-JP.md | 3 ++- README.ko-KR.md | 3 ++- README.md | 3 ++- README.pl-PL.md | 3 ++- README.pt-BR.md | 3 ++- README.ru-RU.md | 3 ++- README.tr-TR.md | 3 ++- README.zh-CN.md | 3 ++- README.zh-TW.md | 3 ++- 12 files changed, 24 insertions(+), 12 deletions(-) diff --git a/README.es-ES.md b/README.es-ES.md index 8a6706ce49..e501de63ca 100644 --- a/README.es-ES.md +++ b/README.es-ES.md @@ -19,7 +19,8 @@ _Léelo en otros idiomas:_ [_Français_](README.fr-FR.md), [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Italiana_](README.it-IT.md) *☝ Nótese que este proyecto está pensado con fines de aprendizaje e investigación, y **no** para ser usado en producción.* diff --git a/README.fr-FR.md b/README.fr-FR.md index a83cce4d01..70b244a301 100644 --- a/README.fr-FR.md +++ b/README.fr-FR.md @@ -20,7 +20,8 @@ _Lisez ceci dans d'autres langues:_ [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Italiana_](README.it-IT.md) ## Data Structures diff --git a/README.it-IT.md b/README.it-IT.md index 8daa4ac62c..d340ece707 100644 --- a/README.it-IT.md +++ b/README.it-IT.md @@ -16,7 +16,8 @@ _Leggilo in altre lingue:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Italian_](README.it-IT.md) +[_Русский_](README.ru-RU.md), +[_Türk_](README.tr-TR.md) *☝ Si noti che questo progetto è destinato ad essere utilizzato solo per l'apprendimento e la ricerca e non è destinato ad essere utilizzato per il commercio.* diff --git a/README.ja-JP.md b/README.ja-JP.md index 862a0d2bc0..687ea124aa 100644 --- a/README.ja-JP.md +++ b/README.ja-JP.md @@ -19,7 +19,8 @@ _Read this in other languages:_ [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Italiana_](README.it-IT.md) ## データ構造 diff --git a/README.ko-KR.md b/README.ko-KR.md index c5fa8b1804..4dcd3fd34b 100644 --- a/README.ko-KR.md +++ b/README.ko-KR.md @@ -18,7 +18,8 @@ _Read this in other languages:_ [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Italiana_](README.it-IT.md) ## 자료 구조 diff --git a/README.md b/README.md index 9d4d39622b..98d5c43c5e 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,8 @@ _Read this in other languages:_ [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Italiana_](README.it-IT.md) *☝ Note that this project is meant to be used for learning and researching purposes only, and it is **not** meant to be used for production.* diff --git a/README.pl-PL.md b/README.pl-PL.md index 26ca99c179..6745307031 100644 --- a/README.pl-PL.md +++ b/README.pl-PL.md @@ -20,7 +20,8 @@ _Read this in other languages:_ [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Italiana_](README.it-IT.md) ## Struktury Danych diff --git a/README.pt-BR.md b/README.pt-BR.md index 626c5f65b7..f02691c179 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -20,7 +20,8 @@ _Leia isto em outros idiomas:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Русский_](README.ru-RU.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Italiana_](README.it-IT.md) ## Estrutura de Dados diff --git a/README.ru-RU.md b/README.ru-RU.md index fcfcf83b9f..6317926cef 100644 --- a/README.ru-RU.md +++ b/README.ru-RU.md @@ -17,7 +17,8 @@ _Читать на других языках:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Italiana_](README.it-IT.md) *☝ Замечание: этот репозиторий предназначен для учебно-исследовательских целей (**не** для использования в продакшн-системах).* diff --git a/README.tr-TR.md b/README.tr-TR.md index 0892e5f4a0..260553780e 100644 --- a/README.tr-TR.md +++ b/README.tr-TR.md @@ -18,7 +18,8 @@ _Read this in other languages:_ [_Français_](README.fr-FR.md), [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), -[_Русский_](README.ru-RU.md) +[_Русский_](README.ru-RU.md), +[_Italiana_](README.it-IT.md) *☝ Not, bu proje araştırma ve öğrenme amacı ile yapılmış olup üretim için **yaplılmamıştır**.* diff --git a/README.zh-CN.md b/README.zh-CN.md index f63eab90b4..8e8c66172e 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -17,7 +17,8 @@ _Read this in other languages:_ [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Italiana_](README.it-IT.md) *注意:这个项目仅用于学习和研究,**不是**用于生产环境。* diff --git a/README.zh-TW.md b/README.zh-TW.md index 50050b2786..1eba73c941 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -16,7 +16,8 @@ _Read this in other languages:_ [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Italiana_](README.it-IT.md) ## 資料結構 From bbe0462b1cdeb323ae5964a69189ec218d261198 Mon Sep 17 00:00:00 2001 From: deepthan Date: Fri, 11 Dec 2020 00:41:22 +0800 Subject: [PATCH 012/264] fix: fix playground part translate error (#587) Co-authored-by: linkun.he --- README.zh-CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.zh-CN.md b/README.zh-CN.md index 8e8c66172e..45a8c8c64f 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -228,7 +228,7 @@ npm test -- 'LinkedList' 你可以在 `./src/playground/playground.js` 文件中操作数据结构与算法,并在 `./src/playground/__test__/playground.test.js` 中编写测试。 -然后,只需运行以下命令来测试你的 Playground 是否按无误: +然后,只需运行以下命令来测试你的 Playground 是否无误: ``` npm test -- 'playground' From 498ab10b1b8eb71a4f6c80a62f84cc9c289a40c8 Mon Sep 17 00:00:00 2001 From: vladimirschneider <42021006+vladimirschneider@users.noreply.github.com> Date: Thu, 10 Dec 2020 23:50:47 +0700 Subject: [PATCH 013/264] Repeated Math operation (#584) Co-authored-by: Oleksii Trekhleb --- src/algorithms/uncategorized/rain-terraces/bfRainTerraces.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/uncategorized/rain-terraces/bfRainTerraces.js b/src/algorithms/uncategorized/rain-terraces/bfRainTerraces.js index f136e6d4c6..0d3443a4aa 100644 --- a/src/algorithms/uncategorized/rain-terraces/bfRainTerraces.js +++ b/src/algorithms/uncategorized/rain-terraces/bfRainTerraces.js @@ -25,7 +25,7 @@ export default function bfRainTerraces(terraces) { if (terraceBoundaryLevel > terraces[terraceIndex]) { // Terrace will be able to store the water if the lowest of two left and right highest // terraces are still higher than the current one. - waterAmount += Math.min(leftHighestLevel, rightHighestLevel) - terraces[terraceIndex]; + waterAmount += terraceBoundaryLevel - terraces[terraceIndex]; } } From 827906c1401a2842575f4d602875b0b4f563507f Mon Sep 17 00:00:00 2001 From: Anmol Gomra <50433033+pineapple45@users.noreply.github.com> Date: Thu, 10 Dec 2020 22:24:11 +0530 Subject: [PATCH 014/264] added prime-factors algo in src/algorithms/math (#532) --- README.md | 1 + src/algorithms/math/prime-factors/README.md | 34 ++++++++++++++ .../__test__/primefactors.test.js | 40 +++++++++++++++++ .../math/prime-factors/primefactors.js | 44 +++++++++++++++++++ 4 files changed, 119 insertions(+) create mode 100644 src/algorithms/math/prime-factors/README.md create mode 100644 src/algorithms/math/prime-factors/__test__/primefactors.test.js create mode 100644 src/algorithms/math/prime-factors/primefactors.js diff --git a/README.md b/README.md index 98d5c43c5e..3008a6abda 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Bit Manipulation](src/algorithms/math/bits) - set/get/update/clear bits, multiplication/division by two, make negative etc. * `B` [Factorial](src/algorithms/math/factorial) * `B` [Fibonacci Number](src/algorithms/math/fibonacci) - classic and closed-form versions + * `B` [Prime Factors](src/algorithms/math/prime-factors) - finding distinct prime-factor count using both accurate & Hardy-Ramanujan's Algorithm * `B` [Primality Test](src/algorithms/math/primality-test) (trial division method) * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD) * `B` [Least Common Multiple](src/algorithms/math/least-common-multiple) (LCM) diff --git a/src/algorithms/math/prime-factors/README.md b/src/algorithms/math/prime-factors/README.md new file mode 100644 index 0000000000..6b855d37d7 --- /dev/null +++ b/src/algorithms/math/prime-factors/README.md @@ -0,0 +1,34 @@ +# Prime Factors + +Prime factors are basically those prime numbers which multiply together to give the orignal number. For ex: 39 will have prime factors as 3 and 13 which are also prime numbers. Another example is 15 whose prime factors are 3 and 5. + +#### Method for finding the prime factors and their count accurately + +The approach is to basically keep on dividing the natural number 'n' by indexes from i = 2 to i = n by prime indexes only. This is ensured by an 'if' check. Then value of 'n' keeps on overriding by (n/i). +The time complexity till now is O(n) in worst case since the loop run from index i = 2 to i = n even when no index 'i' is left to be divided by 'n' other than n itself. This time complexity can be reduced to O(sqrt(n)) from O(n). This optimisation is acheivable when loop is ran from i = 2 to i = sqrt(n). Now, we go only till O(sqrt(n)) because when 'i' becomes greater than sqrt(n), we now have the confirmation there is no index 'i' left which can divide 'n' completely other than n itself. + +##### Optimised Time Complexity: O(sqrt(n)) + + +#### Hardy-Ramanujan formula for approximate calculation of prime-factor count + +In 1917, a theorem was formulated by G.H Hardy and Srinivasa Ramanujan which approximately tells the total count of distinct prime factors of most 'n' natural numbers. +The fomula is given by ln(ln(n)). + +#### Code Explaiation + +There are on 4 functions used: + +- getPrimeFactors : returns array containing all distinct prime factors for given input n. + +- getPrimeFactorsCount: returns accurate total count of distinct prime factors of given input n. + +- hardyRamanujanApprox: returns approximate total count of distinct prime factors of given input n using Hardy-Ramanujan formula. + +- errorPercent : returns %age of error in approximation using formula to that of accurate result. The formula used is: **[Modulus(accurate_val - approximate_val) / accurate_val ] * 100**. This shows deviation from accurate result. + + +## References + +- [Youtube](https://www.youtube.com/watch?v=6PDtgHhpCHo) +- [Wikipedia](https://en.wikipedia.org/wiki/Hardy%E2%80%93Ramanujan_theorem) \ No newline at end of file diff --git a/src/algorithms/math/prime-factors/__test__/primefactors.test.js b/src/algorithms/math/prime-factors/__test__/primefactors.test.js new file mode 100644 index 0000000000..7a1ba96377 --- /dev/null +++ b/src/algorithms/math/prime-factors/__test__/primefactors.test.js @@ -0,0 +1,40 @@ +import primefactors from '../primefactors'; + +describe('prime-factors', () => { + it('should give prime factors', () => { + expect(primefactors.getPrimeFactors(510510)).toEqual([2, 3, 5, 7, 11, 13, 17]); + expect(primefactors.getPrimeFactors(343434)).toEqual([2, 3, 7, 13, 17, 37]); + expect(primefactors.getPrimeFactors(456745)).toEqual([5, 167, 547]); + expect(primefactors.getPrimeFactors(8735463)).toEqual([3, 11, 88237]); + expect(primefactors.getPrimeFactors(873452453)).toEqual([149, 1637, 3581]); + expect(primefactors.getPrimeFactors(52734)).toEqual([2, 3, 11, 17, 47]); + }); + + it('should give prime factors count accurately', () => { + expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(510510))).toEqual(7); + expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(343434))).toEqual(6); + expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(456745))).toEqual(3); + expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(8735463))).toEqual(3); + expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(873452453))).toEqual(3); + expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(52734))).toEqual(5); + }); + + it('should give prime factors count approximately using Hardy-Ramanujan-Approx', () => { + expect(primefactors.hardyRamanujanApprox(510510)).toBeCloseTo(2.5759018900,5); + expect(primefactors.hardyRamanujanApprox(343434)).toBeCloseTo(2.54527635538,5); + expect(primefactors.hardyRamanujanApprox(456745)).toBeCloseTo(2.5673987036,5); + expect(primefactors.hardyRamanujanApprox(8735463)).toBeCloseTo(2.771519494900,5); + expect(primefactors.hardyRamanujanApprox(873452453)).toBeCloseTo(3.0247066455016,5); + expect(primefactors.hardyRamanujanApprox(52734)).toBeCloseTo(2.386284094835,5); + }); + + it('should give error percentage of deviation of Hardy-Ramanujan-Approx prime-factors count from accurate prime-factors count', () => { + expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(510510)),primefactors.hardyRamanujanApprox(510510))).toBeCloseTo(63.20140157059997,5); + expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(343434)),primefactors.hardyRamanujanApprox(343434))).toBeCloseTo(57.5787274,5); + expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(456745)),primefactors.hardyRamanujanApprox(456745))).toBeCloseTo(14.420043212851,5); + expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(8735463)),primefactors.hardyRamanujanApprox(8735463))).toBeCloseTo(7.61601683663378,5); + expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(873452453)),primefactors.hardyRamanujanApprox(873452453))).toBeCloseTo(0.8235548500,5); + expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(52734)),primefactors.hardyRamanujanApprox(52734))).toBeCloseTo(52.27431810328,5); + }); +}); + diff --git a/src/algorithms/math/prime-factors/primefactors.js b/src/algorithms/math/prime-factors/primefactors.js new file mode 100644 index 0000000000..d951a37153 --- /dev/null +++ b/src/algorithms/math/prime-factors/primefactors.js @@ -0,0 +1,44 @@ +export default { + + getPrimeFactors : (n) => { + let factorsArray = []; // an array where all the prime factors will be stored + + //over here optimisation is made by running loop till sqrt(n) instead of n + for (let i = 2 ; i <= Math.sqrt(n); i++){ + if(n % i === 0){ // if check to ensure i completely divides n + let count = 0; // This count keeps track of number of times i divides n + while(n % i === 0){ + n = n/i; // override the value of n + count++; // count value updated + } + factorsArray.push(i); // array gets populated + } + } + if(n !== 1){ // finally we cannot push 1 to array since it cannot be a prime-factor + factorsArray.push(n); + } + + return factorsArray; + }, + + //returns accurate prime-factors count + getPrimeFactorsCount : (factorsArray) => { + return factorsArray.length; + }, + + + //returns Hardy-Ramanujan Approximation of prime-factors count + hardyRamanujanApprox : (n) => { + return Math.log(Math.log(n)); + }, + + //returns %age of error in approximation using formula to that of accurate result. + errorPercent : (exactFactorCount,approximateFactorCount) => { + let diff = exactFactorCount-approximateFactorCount > 0 ? exactFactorCount-approximateFactorCount: -(exactFactorCount-approximateFactorCount); + return (diff/exactFactorCount * 100); + } + + +} + + From 30ef6a30e11b674510669f0c663d255cb96634ae Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Fri, 11 Dec 2020 08:37:06 +0100 Subject: [PATCH 015/264] Add prime factors calculation. --- README.md | 2 +- src/algorithms/math/prime-factors/README.md | 34 ++++---- .../__test__/primeFactors.test.js | 87 +++++++++++++++++++ .../__test__/primefactors.test.js | 40 --------- .../math/prime-factors/primeFactors.js | 42 +++++++++ .../math/prime-factors/primefactors.js | 44 ---------- 6 files changed, 147 insertions(+), 102 deletions(-) create mode 100644 src/algorithms/math/prime-factors/__test__/primeFactors.test.js delete mode 100644 src/algorithms/math/prime-factors/__test__/primefactors.test.js create mode 100644 src/algorithms/math/prime-factors/primeFactors.js delete mode 100644 src/algorithms/math/prime-factors/primefactors.js diff --git a/README.md b/README.md index 3008a6abda..3886d0bba2 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Bit Manipulation](src/algorithms/math/bits) - set/get/update/clear bits, multiplication/division by two, make negative etc. * `B` [Factorial](src/algorithms/math/factorial) * `B` [Fibonacci Number](src/algorithms/math/fibonacci) - classic and closed-form versions - * `B` [Prime Factors](src/algorithms/math/prime-factors) - finding distinct prime-factor count using both accurate & Hardy-Ramanujan's Algorithm + * `B` [Prime Factors](src/algorithms/math/prime-factors) - finding prime factors and counting them using Hardy-Ramanujan's theorem * `B` [Primality Test](src/algorithms/math/primality-test) (trial division method) * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD) * `B` [Least Common Multiple](src/algorithms/math/least-common-multiple) (LCM) diff --git a/src/algorithms/math/prime-factors/README.md b/src/algorithms/math/prime-factors/README.md index 6b855d37d7..a0f1d1535d 100644 --- a/src/algorithms/math/prime-factors/README.md +++ b/src/algorithms/math/prime-factors/README.md @@ -1,34 +1,34 @@ # Prime Factors -Prime factors are basically those prime numbers which multiply together to give the orignal number. For ex: 39 will have prime factors as 3 and 13 which are also prime numbers. Another example is 15 whose prime factors are 3 and 5. +**Prime number** is a whole number greater than `1` that **cannot** be made by multiplying other whole numbers. The first few prime numbers are: `2`, `3`, `5`, `7`, `11`, `13`, `17`, `19` and so on. -#### Method for finding the prime factors and their count accurately +If we **can** make it by multiplying other whole numbers it is a **Composite Number**. -The approach is to basically keep on dividing the natural number 'n' by indexes from i = 2 to i = n by prime indexes only. This is ensured by an 'if' check. Then value of 'n' keeps on overriding by (n/i). -The time complexity till now is O(n) in worst case since the loop run from index i = 2 to i = n even when no index 'i' is left to be divided by 'n' other than n itself. This time complexity can be reduced to O(sqrt(n)) from O(n). This optimisation is acheivable when loop is ran from i = 2 to i = sqrt(n). Now, we go only till O(sqrt(n)) because when 'i' becomes greater than sqrt(n), we now have the confirmation there is no index 'i' left which can divide 'n' completely other than n itself. +![Composite numbers](https://www.mathsisfun.com/numbers/images/prime-composite.svg) -##### Optimised Time Complexity: O(sqrt(n)) +_Image source: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_ +**Prime factors** are those [prime numbers](https://en.wikipedia.org/wiki/Prime_number) which multiply together to give the original number. For example `39` will have prime factors of `3` and `13` which are also prime numbers. Another example is `15` whose prime factors are `3` and `5`. -#### Hardy-Ramanujan formula for approximate calculation of prime-factor count +![Factors](https://www.mathsisfun.com/numbers/images/factor-2x3.svg) -In 1917, a theorem was formulated by G.H Hardy and Srinivasa Ramanujan which approximately tells the total count of distinct prime factors of most 'n' natural numbers. -The fomula is given by ln(ln(n)). +_Image source: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_ -#### Code Explaiation +## Finding the prime factors and their count accurately -There are on 4 functions used: +The approach is to keep on dividing the natural number `n` by indexes from `i = 2` to `i = n` (by prime indexes only). The value of `n` is being overridden by `(n / i)` on each iteration. -- getPrimeFactors : returns array containing all distinct prime factors for given input n. +The time complexity till now is `O(n)` in the worst case scenario since the loop runs from index `i = 2` to `i = n`. This time complexity can be reduced from `O(n)` to `O(sqrt(n))`. The optimisation is achievable when loop runs from `i = 2` to `i = sqrt(n)`. Now, we go only till `O(sqrt(n))` because when `i` becomes greater than `sqrt(n)`, we have the confirmation that there is no index `i` left which can divide `n` completely other than `n` itself. -- getPrimeFactorsCount: returns accurate total count of distinct prime factors of given input n. +## Hardy-Ramanujan formula for approximate calculation of prime-factor count -- hardyRamanujanApprox: returns approximate total count of distinct prime factors of given input n using Hardy-Ramanujan formula. +In 1917, a theorem was formulated by G.H Hardy and Srinivasa Ramanujan which states that the normal order of the number `ω(n)` of distinct prime factors of a number `n` is `log(log(n))`. -- errorPercent : returns %age of error in approximation using formula to that of accurate result. The formula used is: **[Modulus(accurate_val - approximate_val) / accurate_val ] * 100**. This shows deviation from accurate result. - +Roughly speaking, this means that most numbers have about this number of distinct prime factors. ## References -- [Youtube](https://www.youtube.com/watch?v=6PDtgHhpCHo) -- [Wikipedia](https://en.wikipedia.org/wiki/Hardy%E2%80%93Ramanujan_theorem) \ No newline at end of file +- [Prime numbers on Math is Fun](https://www.mathsisfun.com/prime-factorization.html) +- [Prime numbers on Wikipedia](https://en.wikipedia.org/wiki/Prime_number) +- [Hardy–Ramanujan theorem on Wikipedia](https://en.wikipedia.org/wiki/Hardy%E2%80%93Ramanujan_theorem) +- [Prime factorization of a number on Youtube](https://www.youtube.com/watch?v=6PDtgHhpCHo&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=82) diff --git a/src/algorithms/math/prime-factors/__test__/primeFactors.test.js b/src/algorithms/math/prime-factors/__test__/primeFactors.test.js new file mode 100644 index 0000000000..92c94d1f6f --- /dev/null +++ b/src/algorithms/math/prime-factors/__test__/primeFactors.test.js @@ -0,0 +1,87 @@ +import { + primeFactors, + hardyRamanujan, +} from '../primeFactors'; + +/** + * Calculates the error between exact and approximate prime factor counts. + * @param {number} exactCount + * @param {number} approximateCount + * @returns {number} - approximation error (percentage). + */ +function approximationError(exactCount, approximateCount) { + return (Math.abs((exactCount - approximateCount) / exactCount) * 100); +} + +describe('primeFactors', () => { + it('should find prime factors', () => { + expect(primeFactors(1)).toEqual([]); + expect(primeFactors(2)).toEqual([2]); + expect(primeFactors(3)).toEqual([3]); + expect(primeFactors(4)).toEqual([2, 2]); + expect(primeFactors(14)).toEqual([2, 7]); + expect(primeFactors(40)).toEqual([2, 2, 2, 5]); + expect(primeFactors(54)).toEqual([2, 3, 3, 3]); + expect(primeFactors(100)).toEqual([2, 2, 5, 5]); + expect(primeFactors(156)).toEqual([2, 2, 3, 13]); + expect(primeFactors(273)).toEqual([3, 7, 13]); + expect(primeFactors(300)).toEqual([2, 2, 3, 5, 5]); + expect(primeFactors(980)).toEqual([2, 2, 5, 7, 7]); + expect(primeFactors(1000)).toEqual([2, 2, 2, 5, 5, 5]); + expect(primeFactors(52734)).toEqual([2, 3, 11, 17, 47]); + expect(primeFactors(343434)).toEqual([2, 3, 7, 13, 17, 37]); + expect(primeFactors(456745)).toEqual([5, 167, 547]); + expect(primeFactors(510510)).toEqual([2, 3, 5, 7, 11, 13, 17]); + expect(primeFactors(8735463)).toEqual([3, 3, 11, 88237]); + expect(primeFactors(873452453)).toEqual([149, 1637, 3581]); + }); + + it('should give approximate prime factors count using Hardy-Ramanujan theorem', () => { + expect(hardyRamanujan(2)).toBeCloseTo(-0.366, 2); + expect(hardyRamanujan(4)).toBeCloseTo(0.326, 2); + expect(hardyRamanujan(40)).toBeCloseTo(1.305, 2); + expect(hardyRamanujan(156)).toBeCloseTo(1.6193, 2); + expect(hardyRamanujan(980)).toBeCloseTo(1.929, 2); + expect(hardyRamanujan(52734)).toBeCloseTo(2.386, 2); + expect(hardyRamanujan(343434)).toBeCloseTo(2.545, 2); + expect(hardyRamanujan(456745)).toBeCloseTo(2.567, 2); + expect(hardyRamanujan(510510)).toBeCloseTo(2.575, 2); + expect(hardyRamanujan(8735463)).toBeCloseTo(2.771, 2); + expect(hardyRamanujan(873452453)).toBeCloseTo(3.024, 2); + }); + + it('should give correct deviation between exact and approx counts', () => { + expect(approximationError(primeFactors(2).length, hardyRamanujan(2))) + .toBeCloseTo(136.651, 2); + + expect(approximationError(primeFactors(4).length, hardyRamanujan(2))) + .toBeCloseTo(118.325, 2); + + expect(approximationError(primeFactors(40).length, hardyRamanujan(2))) + .toBeCloseTo(109.162, 2); + + expect(approximationError(primeFactors(156).length, hardyRamanujan(2))) + .toBeCloseTo(109.162, 2); + + expect(approximationError(primeFactors(980).length, hardyRamanujan(2))) + .toBeCloseTo(107.330, 2); + + expect(approximationError(primeFactors(52734).length, hardyRamanujan(52734))) + .toBeCloseTo(52.274, 2); + + expect(approximationError(primeFactors(343434).length, hardyRamanujan(343434))) + .toBeCloseTo(57.578, 2); + + expect(approximationError(primeFactors(456745).length, hardyRamanujan(456745))) + .toBeCloseTo(14.420, 2); + + expect(approximationError(primeFactors(510510).length, hardyRamanujan(510510))) + .toBeCloseTo(63.201, 2); + + expect(approximationError(primeFactors(8735463).length, hardyRamanujan(8735463))) + .toBeCloseTo(30.712, 2); + + expect(approximationError(primeFactors(873452453).length, hardyRamanujan(873452453))) + .toBeCloseTo(0.823, 2); + }); +}); diff --git a/src/algorithms/math/prime-factors/__test__/primefactors.test.js b/src/algorithms/math/prime-factors/__test__/primefactors.test.js deleted file mode 100644 index 7a1ba96377..0000000000 --- a/src/algorithms/math/prime-factors/__test__/primefactors.test.js +++ /dev/null @@ -1,40 +0,0 @@ -import primefactors from '../primefactors'; - -describe('prime-factors', () => { - it('should give prime factors', () => { - expect(primefactors.getPrimeFactors(510510)).toEqual([2, 3, 5, 7, 11, 13, 17]); - expect(primefactors.getPrimeFactors(343434)).toEqual([2, 3, 7, 13, 17, 37]); - expect(primefactors.getPrimeFactors(456745)).toEqual([5, 167, 547]); - expect(primefactors.getPrimeFactors(8735463)).toEqual([3, 11, 88237]); - expect(primefactors.getPrimeFactors(873452453)).toEqual([149, 1637, 3581]); - expect(primefactors.getPrimeFactors(52734)).toEqual([2, 3, 11, 17, 47]); - }); - - it('should give prime factors count accurately', () => { - expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(510510))).toEqual(7); - expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(343434))).toEqual(6); - expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(456745))).toEqual(3); - expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(8735463))).toEqual(3); - expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(873452453))).toEqual(3); - expect(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(52734))).toEqual(5); - }); - - it('should give prime factors count approximately using Hardy-Ramanujan-Approx', () => { - expect(primefactors.hardyRamanujanApprox(510510)).toBeCloseTo(2.5759018900,5); - expect(primefactors.hardyRamanujanApprox(343434)).toBeCloseTo(2.54527635538,5); - expect(primefactors.hardyRamanujanApprox(456745)).toBeCloseTo(2.5673987036,5); - expect(primefactors.hardyRamanujanApprox(8735463)).toBeCloseTo(2.771519494900,5); - expect(primefactors.hardyRamanujanApprox(873452453)).toBeCloseTo(3.0247066455016,5); - expect(primefactors.hardyRamanujanApprox(52734)).toBeCloseTo(2.386284094835,5); - }); - - it('should give error percentage of deviation of Hardy-Ramanujan-Approx prime-factors count from accurate prime-factors count', () => { - expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(510510)),primefactors.hardyRamanujanApprox(510510))).toBeCloseTo(63.20140157059997,5); - expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(343434)),primefactors.hardyRamanujanApprox(343434))).toBeCloseTo(57.5787274,5); - expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(456745)),primefactors.hardyRamanujanApprox(456745))).toBeCloseTo(14.420043212851,5); - expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(8735463)),primefactors.hardyRamanujanApprox(8735463))).toBeCloseTo(7.61601683663378,5); - expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(873452453)),primefactors.hardyRamanujanApprox(873452453))).toBeCloseTo(0.8235548500,5); - expect(primefactors.errorPercent(primefactors.getPrimeFactorsCount(primefactors.getPrimeFactors(52734)),primefactors.hardyRamanujanApprox(52734))).toBeCloseTo(52.27431810328,5); - }); -}); - diff --git a/src/algorithms/math/prime-factors/primeFactors.js b/src/algorithms/math/prime-factors/primeFactors.js new file mode 100644 index 0000000000..691436c49e --- /dev/null +++ b/src/algorithms/math/prime-factors/primeFactors.js @@ -0,0 +1,42 @@ +/** + * Finds prime factors of a number. + * + * @param {number} n - the number that is going to be split into prime factors. + * @returns {number[]} - array of prime factors. + */ +export function primeFactors(n) { + // Clone n to avoid function arguments override. + let nn = n; + + // Array that stores the all the prime factors. + const factors = []; + + // Running the loop till sqrt(n) instead of n to optimise time complexity from O(n) to O(sqrt(n)). + for (let factor = 2; factor <= Math.sqrt(nn); factor += 1) { + // Check that factor divides n without a reminder. + while (nn % factor === 0) { + // Overriding the value of n. + nn /= factor; + // Saving the factor. + factors.push(factor); + } + } + + // The ultimate reminder should be a last prime factor, + // unless it is not 1 (since 1 is not a prime number). + if (nn !== 1) { + factors.push(nn); + } + + return factors; +} + +/** + * Hardy-Ramanujan approximation of prime factors count. + * + * @param {number} n + * @returns {number} - approximate number of prime factors. + */ +export function hardyRamanujan(n) { + return Math.log(Math.log(n)); +} diff --git a/src/algorithms/math/prime-factors/primefactors.js b/src/algorithms/math/prime-factors/primefactors.js deleted file mode 100644 index d951a37153..0000000000 --- a/src/algorithms/math/prime-factors/primefactors.js +++ /dev/null @@ -1,44 +0,0 @@ -export default { - - getPrimeFactors : (n) => { - let factorsArray = []; // an array where all the prime factors will be stored - - //over here optimisation is made by running loop till sqrt(n) instead of n - for (let i = 2 ; i <= Math.sqrt(n); i++){ - if(n % i === 0){ // if check to ensure i completely divides n - let count = 0; // This count keeps track of number of times i divides n - while(n % i === 0){ - n = n/i; // override the value of n - count++; // count value updated - } - factorsArray.push(i); // array gets populated - } - } - if(n !== 1){ // finally we cannot push 1 to array since it cannot be a prime-factor - factorsArray.push(n); - } - - return factorsArray; - }, - - //returns accurate prime-factors count - getPrimeFactorsCount : (factorsArray) => { - return factorsArray.length; - }, - - - //returns Hardy-Ramanujan Approximation of prime-factors count - hardyRamanujanApprox : (n) => { - return Math.log(Math.log(n)); - }, - - //returns %age of error in approximation using formula to that of accurate result. - errorPercent : (exactFactorCount,approximateFactorCount) => { - let diff = exactFactorCount-approximateFactorCount > 0 ? exactFactorCount-approximateFactorCount: -(exactFactorCount-approximateFactorCount); - return (diff/exactFactorCount * 100); - } - - -} - - From 97dd96aa7535cb5893ec37e1ec5f4bef91136139 Mon Sep 17 00:00:00 2001 From: Hanseung Yoo Date: Fri, 11 Dec 2020 16:45:54 +0900 Subject: [PATCH 016/264] Add doubly-linked-list doc in Korean (#449) --- .../doubly-linked-list/README.ko-KR.md | 107 ++++++++++++++++++ .../doubly-linked-list/README.md | 1 + 2 files changed, 108 insertions(+) create mode 100644 src/data-structures/doubly-linked-list/README.ko-KR.md diff --git a/src/data-structures/doubly-linked-list/README.ko-KR.md b/src/data-structures/doubly-linked-list/README.ko-KR.md new file mode 100644 index 0000000000..192b189817 --- /dev/null +++ b/src/data-structures/doubly-linked-list/README.ko-KR.md @@ -0,0 +1,107 @@ +# Doubly Linked List + +_Read this in other languages:_ +[_Русский_](README.ru-RU.md), +[_简体中文_](README.zh-CN.md), +[_日本語_](README.ja-JP.md), +[_Português_](README.pt-BR.md) + +컴퓨터공학에서 **이중 연결 리스트**는 순차적으로 링크된 노드라는 레코드 세트로 구성된 링크된 데이터 구조입니다. +각 노드에는 링크라고 하는 두 개의 필드가 있으며, 노드 순서에서 이전 노드와 다음 노드에 대한 참조를 가집니다. +시작 및 종료 노드의 이전 및 다음 링크는 각각 리스트의 순회를 용이하게 하기 위해서 일종의 종결자 (일반적으로 센티넬노드 또는 null)를 나타냅니다. +센티넬 노드가 하나만 있으면, 목록이 센티넬 노드를 통해서 원형으로 연결됩니다. +동일한 데이터 항목으로 구성되어 있지만, 반대 순서로 두 개의 단일 연결 리스트로 개념화 할 수 있습니다. + +![이중 연결 리스트](https://upload.wikimedia.org/wikipedia/commons/5/5e/Doubly-linked-list.svg) + +두 개의 노드 링크를 사용하면 어느 방향으로든 리스트를 순회할 수 있습니다. +이중 연결 리스트에서 노드를 추가하거나 제거하려면, 단일 연결 리스트에서 동일한 작업보다 더 많은 링크를 변경해야 하지만, 첫 번째 노드 이외의 노드인 경우 작업을 추적할 필요가 없으므로 작업이 더 단순해져 잠재적으로 더 효율적입니다. +리스트 순회 중 이전 노드 또는 링크를 수정할 수 있도록 이전 노드를 찾기 위해 리스트를 순회할 필요가 없습니다. + +## 기본 동작을 위한 Pseudocode + +### 삽입 + +```text +Add(value) + Pre: value는 리스트에 추가하고자 하는 값 + Post: value는 목록의 끝에 배치됨 + n ← node(value) + if head = ø + head ← n + tail ← n + else + n.previous ← tail + tail.next ← n + tail ← n + end if +end Add +``` + +### 삭제 + +```text +Remove(head, value) + Pre: head는 리스트의 앞단에 위치 + value는 리스트에서 제거하고자 하는 값 + Post: value가 리스트에서 제거되면 true; 아니라면 false; + if head = ø + return false + end if + if value = head.value + if head = tail + head ← ø + tail ← ø + else + head ← head.next + head.previous ← ø + end if + return true + end if + n ← head.next + while n = ø and value !== n.value + n ← n.next + end while + if n = tail + tail ← tail.previous + tail.next ← ø + return true + else if n = ø + n.previous.next ← n.next + n.next.previous ← n.previous + return true + end if + return false +end Remove +``` + +### 역순회 + +```text +ReverseTraversal(tail) + Pre: tail은 리스트에서 순회하고자 하는 노드 + Post: 리스트가 역순으로 순회됨 + n ← tail + while n = ø + yield n.value + n ← n.previous + end while +end Reverse Traversal +``` + +## 복잡도 + +## 시간 복잡도 + +| Access | Search | Insertion | Deletion | +| :-------: | :-------: | :-------: | :-------: | +| O(n) | O(n) | O(1) | O(n) | + +### 공간 복잡도 + +O(n) + +## 참고 + +- [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list) +- [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) diff --git a/src/data-structures/doubly-linked-list/README.md b/src/data-structures/doubly-linked-list/README.md index ad7f27741c..ec603a8f91 100644 --- a/src/data-structures/doubly-linked-list/README.md +++ b/src/data-structures/doubly-linked-list/README.md @@ -5,6 +5,7 @@ _Read this in other languages:_ [_简体中文_](README.zh-CN.md), [_日本語_](README.ja-JP.md), [_Português_](README.pt-BR.md) +[_한국어_](README.ko-KR.md) In computer science, a **doubly linked list** is a linked data structure that consists of a set of sequentially linked records called nodes. Each node contains From 6e95b0cee743952b3963bdadd1e3ae2c533ecc84 Mon Sep 17 00:00:00 2001 From: Donghoon Song <32301380+donghoon-song@users.noreply.github.com> Date: Fri, 11 Dec 2020 16:48:57 +0900 Subject: [PATCH 017/264] Update README.ko-KR.md (#466) --- .../linked-list/README.ko-KR.md | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 src/data-structures/linked-list/README.ko-KR.md diff --git a/src/data-structures/linked-list/README.ko-KR.md b/src/data-structures/linked-list/README.ko-KR.md new file mode 100644 index 0000000000..dc03327501 --- /dev/null +++ b/src/data-structures/linked-list/README.ko-KR.md @@ -0,0 +1,149 @@ +# 링크드 리스트 + +_Read this in other languages:_ +[_简体中文_](README.zh-CN.md), +[_Русский_](README.ru-RU.md), +[_日本語_](README.ja-JP.md), +[_Português_](README.pt-BR.md) + +컴퓨터과학에서, **링크드 리스트**는 데이터 요소의 선형 집합이며, 이 집합에서 논리적 저장 순서는 메모리의 물리적 저장 순서와 일치하지 않습니다. 그 대신, 각각의 원소들은 자기 자신 다음의 원소를 가리킵니다. **링크드 리스트**는 순서를 표현하는 노드들의 집합으로 이루어져 있습니다. 간단하게, 각각의 노드들은 데이터와 다음 순서의 노드를 가리키는 레퍼런스로 이루어져 있습니다. (링크라고 부릅니다.) 이 자료구조는 순회하는 동안 순서에 상관없이 효율적인 삽입이나 삭제가 가능합니다. 더 복잡한 변형은 추가적인 링크를 더해, 임의의 원소 참조로부터 효율적인 삽입과 삭제를 가능하게 합니다. 링크드 리스트의 단점은 접근 시간이 선형이라는 것이고, 병렬처리도 하지 못합니다. 임의 접근처럼 빠른 접근은 불가능합니다. 링크드 리스트에 비해 배열이 더 나은 캐시 지역성을 가지고 있습니다. + +![링크드 리스트](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) + +## 기본 연산에 대한 수도코드 + +### 삽입 + +```text +Add(value) + Pre: 리스트에 추가할 값 + Post: 리스트의 맨 마지막에 있는 값 + n ← node(value) + if head = ø + head ← n + tail ← n + else + tail.next ← n + tail ← n + end if +end Add +``` + +```text +Prepend(value) + Pre: 리스트에 추가할 값 + Post: 리스트의 맨 앞에 있는 값 + n ← node(value) + n.next ← head + head ← n + if tail = ø + tail ← n + end +end Prepend +``` + +### 탐색 + +```text +Contains(head, value) + Pre: head는 리스트에서 맨 앞 노드 + value는 찾고자 하는 값 + Post: 항목이 링크드 리스트에 있으면 true; + 없으면 false + n ← head + while n != ø and n.value != value + n ← n.next + end while + if n = ø + return false + end if + return true +end Contains +``` + +### 삭제 + +```text +Remove(head, value) + Pre: head는 리스트에서 맨 앞 노드 + value는 삭제하고자 하는 값 + Post: 항목이 링크드 리스트에서 삭제되면 true; + 없으면 false + if head = ø + return false + end if + n ← head + if n.value = value + if head = tail + head ← ø + tail ← ø + else + head ← head.next + end if + return true + end if + while n.next != ø and n.next.value != value + n ← n.next + end while + if n.next != ø + if n.next = tail + tail ← n + end if + n.next ← n.next.next + return true + end if + return false +end Remove +``` + +### 순회 + +```text +Traverse(head) + Pre: head는 리스트에서 맨 앞 노드 + Post: 순회된 항목들 + n ← head + while n != ø + yield n.value + n ← n.next + end while +end Traverse +``` + +### 역순회 + +```text +ReverseTraversal(head, tail) + Pre: 같은 리스트에 들어 있는 맨 앞, 맨 뒤 노드 + Post: 역순회된 항목들 + if tail != ø + curr ← tail + while curr != head + prev ← head + while prev.next != curr + prev ← prev.next + end while + yield curr.value + curr ← prev + end while + yield curr.value + end if +end ReverseTraversal +``` + +## 복잡도 + +### 시간 복잡도 + +| 접근 | 탐색 | 삽입 | 삭제 | +| :---: | :---: | :---: | :---: | +| O(n) | O(n) | O(1) | O(1) | + +### 공간 복잡도 + +O(n) + +## 참조 + +- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list) +- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) From c3d22956b76a8407eec230f5a4f2078d26fed25d Mon Sep 17 00:00:00 2001 From: Eugene Sinitsyn Date: Fri, 11 Dec 2020 10:51:13 +0300 Subject: [PATCH 018/264] Fix typo (#459) --- src/data-structures/trie/README.ru-RU.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data-structures/trie/README.ru-RU.md b/src/data-structures/trie/README.ru-RU.md index 61b7da92d0..f447f8eb0e 100644 --- a/src/data-structures/trie/README.ru-RU.md +++ b/src/data-structures/trie/README.ru-RU.md @@ -2,7 +2,7 @@ **Префиксное дерево** (также бор, луч, нагруженное или суффиксное дерево) в информатике - упорядоченная древовидная структура данных, которая используется для хранения динамических множеств или ассоциативных массивов, где -ключём обычно выступают строки. Дерево называется префиксным, потому что поиск осуществляется по префиксам. +ключом обычно выступают строки. Дерево называется префиксным, потому что поиск осуществляется по префиксам. В отличие от бинарного дерева, узлы не содержат ключи, соответствующие узлу. Представляет собой корневое дерево, каждое ребро которого помечено каким-то символом так, что для любого узла все рёбра, соединяющие этот узел с его сыновьями, From 46daaf51c5feb3e4fae17988fcd40fe9f55c084d Mon Sep 17 00:00:00 2001 From: JD Medina Date: Thu, 10 Dec 2020 23:54:37 -0800 Subject: [PATCH 019/264] Modify HashTable (#447) Add a getValues() method to the HashTable data structure --- src/data-structures/hash-table/HashTable.js | 12 ++++++++++++ .../hash-table/__test__/HashTable.test.js | 10 ++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/data-structures/hash-table/HashTable.js b/src/data-structures/hash-table/HashTable.js index 5e19e7b704..6ac83a5273 100644 --- a/src/data-structures/hash-table/HashTable.js +++ b/src/data-structures/hash-table/HashTable.js @@ -105,4 +105,16 @@ export default class HashTable { getKeys() { return Object.keys(this.keys); } + + /** + * Gets the list of all the stored values in the hash table in the order of + * the keys map. + * + * @return {*[]} + */ + getValues() { + const keys = this.getKeys(); + + return keys.map(key => this.buckets[this.hash(key)].head.value.value); + } } diff --git a/src/data-structures/hash-table/__test__/HashTable.test.js b/src/data-structures/hash-table/__test__/HashTable.test.js index 27d590cf13..cc8d45d5a7 100644 --- a/src/data-structures/hash-table/__test__/HashTable.test.js +++ b/src/data-structures/hash-table/__test__/HashTable.test.js @@ -86,4 +86,14 @@ describe('HashTable', () => { expect(hashTable.has('b')).toBe(true); expect(hashTable.has('x')).toBe(false); }); + + it('should get all the values', () => { + const hashTable = new HashTable(3); + + hashTable.set('a', 'alpha'); + hashTable.set('b', 'beta'); + hashTable.set('c', 'gamma'); + + expect(hashTable.getValues()).toEqual(['alpha', 'beta', 'gamma']); + }); }); From 1b0e27ab86dbae97b99620db3ecacffafd17d98a Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Fri, 11 Dec 2020 09:14:48 +0100 Subject: [PATCH 020/264] Add getValues() method to HashTable and update LinkedList READMEs. --- .../doubly-linked-list/README.md | 2 +- src/data-structures/hash-table/HashTable.js | 11 +++++----- .../hash-table/__test__/HashTable.test.js | 20 ++++++++++++++++++- src/data-structures/linked-list/README.md | 3 ++- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/data-structures/doubly-linked-list/README.md b/src/data-structures/doubly-linked-list/README.md index ec603a8f91..c64b51262d 100644 --- a/src/data-structures/doubly-linked-list/README.md +++ b/src/data-structures/doubly-linked-list/README.md @@ -12,7 +12,7 @@ consists of a set of sequentially linked records called nodes. Each node contain two fields, called links, that are references to the previous and to the next node in the sequence of nodes. The beginning and ending nodes' previous and next links, respectively, point to some kind of terminator, typically a sentinel -node or null, to facilitate traversal of the list. If there is only one +node or null, to facilitate the traversal of the list. If there is only one sentinel node, then the list is circularly linked via the sentinel node. It can be conceptualized as two singly linked lists formed from the same data items, but in opposite sequential orders. diff --git a/src/data-structures/hash-table/HashTable.js b/src/data-structures/hash-table/HashTable.js index 6ac83a5273..b8b523ea85 100644 --- a/src/data-structures/hash-table/HashTable.js +++ b/src/data-structures/hash-table/HashTable.js @@ -107,14 +107,15 @@ export default class HashTable { } /** - * Gets the list of all the stored values in the hash table in the order of - * the keys map. + * Gets the list of all the stored values in the hash table. * * @return {*[]} */ getValues() { - const keys = this.getKeys(); - - return keys.map(key => this.buckets[this.hash(key)].head.value.value); + return this.buckets.reduce((values, bucket) => { + const bucketValues = bucket.toArray() + .map((linkedListNode) => linkedListNode.value.value); + return values.concat(bucketValues); + }, []); } } diff --git a/src/data-structures/hash-table/__test__/HashTable.test.js b/src/data-structures/hash-table/__test__/HashTable.test.js index cc8d45d5a7..86bbf3adbd 100644 --- a/src/data-structures/hash-table/__test__/HashTable.test.js +++ b/src/data-structures/hash-table/__test__/HashTable.test.js @@ -94,6 +94,24 @@ describe('HashTable', () => { hashTable.set('b', 'beta'); hashTable.set('c', 'gamma'); - expect(hashTable.getValues()).toEqual(['alpha', 'beta', 'gamma']); + expect(hashTable.getValues()).toEqual(['gamma', 'alpha', 'beta']); + }); + + it('should get all the values from empty hash table', () => { + const hashTable = new HashTable(); + expect(hashTable.getValues()).toEqual([]); + }); + + it('should get all the values in case of hash collision', () => { + const hashTable = new HashTable(3); + + // Keys `ab` and `ba` in current implementation should result in one hash (one bucket). + // We need to make sure that several items from one bucket will be serialized. + hashTable.set('ab', 'one'); + hashTable.set('ba', 'two'); + + hashTable.set('ac', 'three'); + + expect(hashTable.getValues()).toEqual(['one', 'two', 'three']); }); }); diff --git a/src/data-structures/linked-list/README.md b/src/data-structures/linked-list/README.md index 3fd10e24db..2b8a7507b6 100644 --- a/src/data-structures/linked-list/README.md +++ b/src/data-structures/linked-list/README.md @@ -4,7 +4,8 @@ _Read this in other languages:_ [_简体中文_](README.zh-CN.md), [_Русский_](README.ru-RU.md), [_日本語_](README.ja-JP.md), -[_Português_](README.pt-BR.md) +[_Português_](README.pt-BR.md), +[_한국어_](README.ko-KR.md) In computer science, a **linked list** is a linear collection of data elements, in which linear order is not given by From 40942425151f5fce18c46065bfbfeaa527dcc52f Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Tue, 15 Dec 2020 07:54:58 +0100 Subject: [PATCH 021/264] Add GitHub workflow. --- .github/workflows/node.js.yml | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/node.js.yml diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml new file mode 100644 index 0000000000..f452cecaf9 --- /dev/null +++ b/.github/workflows/node.js.yml @@ -0,0 +1,37 @@ +name: CI + +on: + push: + branches: [ source ] + pull_request: + branches: [ source ] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [14.x] + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: Install dependencies + run: npm i + + - name: Run linting + run: npm run lint + + - name: Run tests + run: npm run coverage + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 From ead275d08f470a381a6880fa0f3197c5966898b9 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Tue, 15 Dec 2020 07:56:29 +0100 Subject: [PATCH 022/264] Delete Travis yml. --- .travis.yml | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index fee3c3cabd..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -os: - - osx -language: node_js -node_js: - - 14 -install: - - npm install -g codecov - - npm install -script: - - npm run ci - - codecov -notifications: - email: false From 39a5fa57581235f7673b92e667ad8a337ce88516 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Tue, 15 Dec 2020 07:57:35 +0100 Subject: [PATCH 023/264] Update the main branch for GitHub actions. --- .github/workflows/node.js.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index f452cecaf9..1499ea368e 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [ source ] + branches: [ master ] pull_request: - branches: [ source ] + branches: [ master ] jobs: build: From d470fa13baa73475a58cecac76cd6a96818fbe46 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Tue, 15 Dec 2020 08:04:46 +0100 Subject: [PATCH 024/264] Update the Build badge to show the info from GitHub actions. --- README.es-ES.md | 2 +- README.fr-FR.md | 2 +- README.it-IT.md | 4 ++-- README.ja-JP.md | 2 +- README.ko-KR.md | 2 +- README.md | 2 +- README.pl-PL.md | 2 +- README.pt-BR.md | 2 +- README.ru-RU.md | 2 +- README.tr-TR.md | 2 +- README.zh-CN.md | 2 +- README.zh-TW.md | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.es-ES.md b/README.es-ES.md index e501de63ca..346c19718d 100644 --- a/README.es-ES.md +++ b/README.es-ES.md @@ -1,6 +1,6 @@ # Algoritmos y Estructuras de Datos en JavaScript -[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) Este repositorio contiene ejemplos basados en JavaScript de muchos diff --git a/README.fr-FR.md b/README.fr-FR.md index 70b244a301..440a854cd3 100644 --- a/README.fr-FR.md +++ b/README.fr-FR.md @@ -1,6 +1,6 @@ # Algorithmes et Structures de Données en JavaScript -[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) Ce dépôt contient des exemples d'implémentation en JavaScript de plusieurs diff --git a/README.it-IT.md b/README.it-IT.md index d340ece707..2f7c7cc66c 100644 --- a/README.it-IT.md +++ b/README.it-IT.md @@ -1,6 +1,6 @@ # Algoritmi e Strutture Dati in Javascript - -[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) + +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) Questa repository contiene esempi in Javascript dei più popolari algoritmi e strutture dati . diff --git a/README.ja-JP.md b/README.ja-JP.md index 687ea124aa..1c145a604e 100644 --- a/README.ja-JP.md +++ b/README.ja-JP.md @@ -1,6 +1,6 @@ # JavaScriptアルゴリズムとデータ構造 -[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) このリポジトリには、JavaScriptベースの一般的なアルゴリズムとデータ構造に関する多数のサンプルが含まれています。 diff --git a/README.ko-KR.md b/README.ko-KR.md index 4dcd3fd34b..b5be09f69e 100644 --- a/README.ko-KR.md +++ b/README.ko-KR.md @@ -1,6 +1,6 @@ # JavaScript 알고리즘 및 자료 구조 -[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) 이 저장소에는 많이 알려진 알고리즘 및 자료 구조의 Javascript 기반 예제를 담고 있습니다. diff --git a/README.md b/README.md index 3886d0bba2..9994971043 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # JavaScript Algorithms and Data Structures -[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) This repository contains JavaScript based examples of many diff --git a/README.pl-PL.md b/README.pl-PL.md index 6745307031..bdac149533 100644 --- a/README.pl-PL.md +++ b/README.pl-PL.md @@ -1,6 +1,6 @@ # JavaScript Algorytmy i Struktury Danych -[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) To repozytorium zawiera wiele przykładów JavaScript opartych na diff --git a/README.pt-BR.md b/README.pt-BR.md index f02691c179..a9fc0d34ce 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -1,6 +1,6 @@ # Estrutura de Dados e Algoritmos em JavaScript -[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) Este repositório contém exemplos baseados em JavaScript de muitos diff --git a/README.ru-RU.md b/README.ru-RU.md index 6317926cef..9365bca163 100644 --- a/README.ru-RU.md +++ b/README.ru-RU.md @@ -1,6 +1,6 @@ # Алгоритмы и структуры данных на JavaScript -[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) В этом репозитории содержатся базовые JavaScript-примеры многих популярных алгоритмов и структур данных. diff --git a/README.tr-TR.md b/README.tr-TR.md index 260553780e..62db14d1d0 100644 --- a/README.tr-TR.md +++ b/README.tr-TR.md @@ -1,6 +1,6 @@ # JavaScript Algoritmalar ve Veri Yapıları -[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) Bu repository JavaScript'e ait popüler diff --git a/README.zh-CN.md b/README.zh-CN.md index 45a8c8c64f..064c0dbe11 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,6 +1,6 @@ # JavaScript 算法与数据结构 -[![build status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) 本仓库包含了多种基于 JavaScript 的算法与数据结构。 diff --git a/README.zh-TW.md b/README.zh-TW.md index 1eba73c941..bb98d2a140 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -1,6 +1,6 @@ # JavaScript 演算法與資料結構 -[![build status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) 這個知識庫包含許多 JavaScript 的資料結構與演算法的基礎範例。 From 94afab0dd95820bc1b150de2fa08120a51573fcd Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Tue, 15 Dec 2020 10:15:37 +0100 Subject: [PATCH 025/264] Add test coverage thresholds. --- jest.config.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/jest.config.js b/jest.config.js index 06e765266f..3fec225237 100644 --- a/jest.config.js +++ b/jest.config.js @@ -25,4 +25,14 @@ module.exports = { // It is reflected in properties such as location.href. // @see: https://github.com/facebook/jest/issues/6769 testURL: 'http://localhost/', + + // @see: https://jestjs.io/docs/en/configuration#coveragethreshold-object + coverageThreshold: { + global: { + statements: 100, + branches: 95, + functions: 100, + lines: 100, + }, + }, }; From ae225741fa64a9b5869f37610e626658e2d80108 Mon Sep 17 00:00:00 2001 From: bhaltair Date: Wed, 16 Dec 2020 01:44:44 +0800 Subject: [PATCH 026/264] Update README.zh-CN.md (#439) --- src/data-structures/doubly-linked-list/README.zh-CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data-structures/doubly-linked-list/README.zh-CN.md b/src/data-structures/doubly-linked-list/README.zh-CN.md index dfe9e593a8..03dd53c11d 100644 --- a/src/data-structures/doubly-linked-list/README.zh-CN.md +++ b/src/data-structures/doubly-linked-list/README.zh-CN.md @@ -51,7 +51,7 @@ Remove(head, value) return true end if n ← head.next - while n = ø and value = n.value + while n = ø and value !== n.value n ← n.next end while if n = tail From 82cf0e6d582c89ed7823025199dd227f9930cb54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Vin=C3=ADcius=20Lacerda=20de=20Arruda?= Date: Tue, 15 Dec 2020 14:52:43 -0300 Subject: [PATCH 027/264] Creating a explanation of Bubblesort in portuguese (#423) Co-authored-by: Oleksii Trekhleb --- .../sorting/bubble-sort/README-ptbr.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/algorithms/sorting/bubble-sort/README-ptbr.md diff --git a/src/algorithms/sorting/bubble-sort/README-ptbr.md b/src/algorithms/sorting/bubble-sort/README-ptbr.md new file mode 100644 index 0000000000..b378d7f5bb --- /dev/null +++ b/src/algorithms/sorting/bubble-sort/README-ptbr.md @@ -0,0 +1,16 @@ +# Bubble Sort + +O bubble sort, ou ordenação por flutuação (literalmente "por bolha"), é um algoritmo de ordenação dos mais simples. A ideia é percorrer o vetor diversas vezes, e a cada passagem fazer flutuar para o topo o maior elemento da sequência. Essa movimentação lembra a forma como as bolhas em um tanque de água procuram seu próprio nível, e disso vem o nome do algoritmo. + +![Algorithm Visualization](https://pt.wikipedia.org/wiki/Ficheiro:Bubble_sort_animation.gif) + +## Complexity + +| Name | Best | Average | Worst | Memory | Stable | Comments | +| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | +| **Bubble sort** | n | n2 | n2 | 1 | Yes | | + +## References + +- [Wikipedia](https://pt.wikipedia.org/wiki/Bubble_sort) + From 802557f1ac83fa299613a9e5332096547712bf6a Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Tue, 15 Dec 2020 18:56:09 +0100 Subject: [PATCH 028/264] Update translation for Bubble Sort. --- src/algorithms/sorting/bubble-sort/README.md | 3 +++ .../sorting/bubble-sort/{README-ptbr.md => README.pt-BR.md} | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) rename src/algorithms/sorting/bubble-sort/{README-ptbr.md => README.pt-BR.md} (79%) diff --git a/src/algorithms/sorting/bubble-sort/README.md b/src/algorithms/sorting/bubble-sort/README.md index ca784fade6..596d4006af 100644 --- a/src/algorithms/sorting/bubble-sort/README.md +++ b/src/algorithms/sorting/bubble-sort/README.md @@ -1,5 +1,8 @@ # Bubble Sort +_Read this in other languages:_ +[_Português_](README.pt-BR.md) + Bubble sort, sometimes referred to as sinking sort, is a simple sorting algorithm that repeatedly steps through the list to be sorted, compares each pair of adjacent diff --git a/src/algorithms/sorting/bubble-sort/README-ptbr.md b/src/algorithms/sorting/bubble-sort/README.pt-BR.md similarity index 79% rename from src/algorithms/sorting/bubble-sort/README-ptbr.md rename to src/algorithms/sorting/bubble-sort/README.pt-BR.md index b378d7f5bb..39a3029500 100644 --- a/src/algorithms/sorting/bubble-sort/README-ptbr.md +++ b/src/algorithms/sorting/bubble-sort/README.pt-BR.md @@ -2,7 +2,7 @@ O bubble sort, ou ordenação por flutuação (literalmente "por bolha"), é um algoritmo de ordenação dos mais simples. A ideia é percorrer o vetor diversas vezes, e a cada passagem fazer flutuar para o topo o maior elemento da sequência. Essa movimentação lembra a forma como as bolhas em um tanque de água procuram seu próprio nível, e disso vem o nome do algoritmo. -![Algorithm Visualization](https://pt.wikipedia.org/wiki/Ficheiro:Bubble_sort_animation.gif) +![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/c/c8/Bubble-sort-example-300px.gif) ## Complexity @@ -13,4 +13,5 @@ O bubble sort, ou ordenação por flutuação (literalmente "por bolha"), é um ## References - [Wikipedia](https://pt.wikipedia.org/wiki/Bubble_sort) +- [YouTube](https://www.youtube.com/watch?v=6Gv8vg0kcHc&index=27&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) From 871d20d8685df552d6f5c57b23f420b62404ef5a Mon Sep 17 00:00:00 2001 From: Avi Agrawal <39293511+avi09@users.noreply.github.com> Date: Wed, 16 Dec 2020 00:44:56 -0500 Subject: [PATCH 029/264] Adding K Nearest Neighbor to ML folder in algorithms with README and tests (#592) * Updated KNN and README * Update README.md * new * new * updated tests * updated knn coverage --- README.md | 13 ++--- src/algorithms/ML/KNN/README.md | 23 +++++++++ src/algorithms/ML/KNN/__test__/knn.test.js | 42 +++++++++++++++ src/algorithms/ML/KNN/knn.js | 60 ++++++++++++++++++++++ 4 files changed, 132 insertions(+), 6 deletions(-) create mode 100644 src/algorithms/ML/KNN/README.md create mode 100644 src/algorithms/ML/KNN/__test__/knn.test.js create mode 100644 src/algorithms/ML/KNN/knn.js diff --git a/README.md b/README.md index 9994971043..2ee72e2268 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ _Read this in other languages:_ [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md) -*☝ Note that this project is meant to be used for learning and researching purposes +*☝ Note that this project is meant to be used for learning and researching purposes only, and it is **not** meant to be used for production.* ## Data Structures @@ -64,7 +64,7 @@ a set of rules that precisely define a sequence of operations. * **Math** * `B` [Bit Manipulation](src/algorithms/math/bits) - set/get/update/clear bits, multiplication/division by two, make negative etc. - * `B` [Factorial](src/algorithms/math/factorial) + * `B` [Factorial](src/algorithms/math/factorial) * `B` [Fibonacci Number](src/algorithms/math/fibonacci) - classic and closed-form versions * `B` [Prime Factors](src/algorithms/math/prime-factors) - finding prime factors and counting them using Hardy-Ramanujan's theorem * `B` [Primality Test](src/algorithms/math/primality-test) (trial division method) @@ -80,7 +80,7 @@ a set of rules that precisely define a sequence of operations. * `A` [Integer Partition](src/algorithms/math/integer-partition) * `A` [Square Root](src/algorithms/math/square-root) - Newton's method * `A` [Liu Hui π Algorithm](src/algorithms/math/liu-hui) - approximate π calculations based on N-gons - * `A` [Discrete Fourier Transform](src/algorithms/math/fourier-transform) - decompose a function of time (a signal) into the frequencies that make it up + * `A` [Discrete Fourier Transform](src/algorithms/math/fourier-transform) - decompose a function of time (a signal) into the frequencies that make it up * **Sets** * `B` [Cartesian Product](src/algorithms/sets/cartesian-product) - product of multiple sets * `B` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - random permutation of a finite sequence @@ -142,12 +142,13 @@ a set of rules that precisely define a sequence of operations. * `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - rolling hash function based on polynomial * `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - simple substitution cipher * **Machine Learning** - * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation) + * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation) + * `B` [KNN](src/algorithms/ML/KNN) - K Nearest Neighbors * **Uncategorized** * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower) * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm - * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, dynamic programming (top-down + bottom-up) and greedy examples - * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples + * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, dynamic programming (top-down + bottom-up) and greedy examples + * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (dynamic programming and brute force versions) * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top (4 solutions) * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens) diff --git a/src/algorithms/ML/KNN/README.md b/src/algorithms/ML/KNN/README.md new file mode 100644 index 0000000000..d9db66ef46 --- /dev/null +++ b/src/algorithms/ML/KNN/README.md @@ -0,0 +1,23 @@ +# KNN Algorithm + +KNN stands for K Nearest Neighbors. KNN is a supervised Machine Learning algorithm. It's a classification algorithm, determining the class of a sample vector using a sample data. + +The idea is to calculate the similarity between two data points on the basis of a distance metric. Euclidean distance is used mostly for this task. The algorithm is as follows - + +1. Check for errors like invalid data/labels. +2. Calculate the euclidean distance of all the data points in training data with the classification point +3. Sort the distances of points along with their classes in ascending order +4. Take the initial "K" classes and find the mode to get the most similar class +5. Report the most similar class + +Here is a visualization for better understanding - + +![KNN Visualization](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png) + +Here, as we can see, the classification of unknown points will be judged by their proximity to other points. + +It is important to note that "K" is preferred to have odd values in order to break ties. Usually "K" is taken as 3 or 5. + +## References + +- [GeeksforGeeks](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png) diff --git a/src/algorithms/ML/KNN/__test__/knn.test.js b/src/algorithms/ML/KNN/__test__/knn.test.js new file mode 100644 index 0000000000..6884598505 --- /dev/null +++ b/src/algorithms/ML/KNN/__test__/knn.test.js @@ -0,0 +1,42 @@ +import KNN from '../knn'; + +describe('KNN', () => { + test('should throw an error on invalid data', () => { + expect(() => { + KNN(); + }).toThrowError(); + }); + test('should throw an error on invalid labels', () => { + const nolabels = () => { + KNN([[1, 1]]); + }; + expect(nolabels).toThrowError(); + }); + it('should throw an error on not giving classification vector', () => { + const noclassification = () => { + KNN([[1, 1]], [1]); + }; + expect(noclassification).toThrowError(); + }); + it('should throw an error on not giving classification vector', () => { + const inconsistent = () => { + KNN([[1, 1]], [1], [1]); + }; + expect(inconsistent).toThrowError(); + }); + it('should find the nearest neighbour', () => { + let dataX = [[1, 1], [2, 2]]; + let dataY = [1, 2]; + expect(KNN(dataX, dataY, [1, 1])).toBe(1); + + dataX = [[1, 1], [6, 2], [3, 3], [4, 5], [9, 2], [2, 4], [8, 7]]; + dataY = [1, 2, 1, 2, 1, 2, 1]; + expect(KNN(dataX, dataY, [1.25, 1.25])) + .toBe(1); + + dataX = [[1, 1], [6, 2], [3, 3], [4, 5], [9, 2], [2, 4], [8, 7]]; + dataY = [1, 2, 1, 2, 1, 2, 1]; + expect(KNN(dataX, dataY, [1.25, 1.25], 5)) + .toBe(2); + }); +}); diff --git a/src/algorithms/ML/KNN/knn.js b/src/algorithms/ML/KNN/knn.js new file mode 100644 index 0000000000..866b6a22e9 --- /dev/null +++ b/src/algorithms/ML/KNN/knn.js @@ -0,0 +1,60 @@ +/** + * @param {object} dataY + * @param {object} dataX + * @param {object} toClassify + * @param {number} k + * @return {number} + */ +export default function KNN(dataX, dataY, toClassify, K) { + let k = -1; + + if (K === undefined) { + k = 3; + } else { + k = K; + } + + // creating function to calculate the euclidean distance between 2 vectors + function euclideanDistance(x1, x2) { + // checking errors + if (x1.length !== x2.length) { + throw new Error('inconsistency between data and classification vector.'); + } + // calculate the euclidean distance between 2 vectors and return + let totalSSE = 0; + for (let j = 0; j < x1.length; j += 1) { + totalSSE += (x1[j] - x2[j]) ** 2; + } + return Number(Math.sqrt(totalSSE).toFixed(2)); + } + + // starting algorithm + + // calculate distance from toClassify to each point for all dimensions in dataX + // store distance and point's class_index into distance_class_list + let distanceList = []; + for (let i = 0; i < dataX.length; i += 1) { + const tmStore = []; + tmStore.push(euclideanDistance(dataX[i], toClassify)); + tmStore.push(dataY[i]); + distanceList[i] = tmStore; + } + + // sort distanceList + // take initial k values, count with class index + distanceList = distanceList.sort().slice(0, k); + + // count the number of instances of each class in top k members + // with that maintain record of highest count class simultanously + const modeK = {}; + const maxm = [-1, -1]; + for (let i = 0; i < Math.min(k, distanceList.length); i += 1) { + if (distanceList[i][1] in modeK) modeK[distanceList[i][1]] += 1; + else modeK[distanceList[i][1]] = 1; + if (modeK[distanceList[i][1]] > maxm[0]) { + [maxm[0], maxm[1]] = [modeK[distanceList[i][1]], distanceList[i][1]]; + } + } + // return the class with highest count from maxm + return maxm[1]; +} From b13291df62dd67f4e150064b636bfa3c1795cdda Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 16 Dec 2020 06:49:10 +0100 Subject: [PATCH 030/264] Trim trailing whitespaces. --- .editorconfig | 2 + README.es-ES.md | 8 ++-- README.it-IT.md | 30 ++++++------- README.ja-JP.md | 4 +- README.ko-KR.md | 10 ++--- README.md | 4 +- README.pl-PL.md | 44 +++++++++---------- README.pt-BR.md | 6 +-- README.ru-RU.md | 10 ++--- README.tr-TR.md | 22 +++++----- src/algorithms/sorting/bubble-sort/README.md | 10 ++--- .../sorting/bubble-sort/README.pt-BR.md | 2 +- 12 files changed, 77 insertions(+), 75 deletions(-) diff --git a/.editorconfig b/.editorconfig index 78c6ddee23..11c2bd2445 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,3 +1,4 @@ +# @see: https://editorconfig.org/ root = true [*] @@ -6,3 +7,4 @@ insert_final_newline = true charset = utf-8 indent_style = space indent_size = 2 +trim_trailing_whitespace = true diff --git a/README.es-ES.md b/README.es-ES.md index 346c19718d..81a3189259 100644 --- a/README.es-ES.md +++ b/README.es-ES.md @@ -6,7 +6,7 @@ Este repositorio contiene ejemplos basados en JavaScript de muchos algoritmos y estructuras de datos populares. -Cada algoritmo y estructura de datos tiene su propio LÉAME con explicaciones relacionadas y +Cada algoritmo y estructura de datos tiene su propio LÉAME con explicaciones relacionadas y enlaces para lecturas adicionales (incluyendo algunas a vídeos de YouTube). _Léelo en otros idiomas:_ @@ -54,7 +54,7 @@ los datos. ## Algoritmos -Un algoritmo es una especificación inequívoca de cómo resolver una clase de problemas. Es un conjunto de reglas que +Un algoritmo es una especificación inequívoca de cómo resolver una clase de problemas. Es un conjunto de reglas que definen con precisión una secuencia de operaciones. `P` - Principiante, `A` - Avanzado @@ -231,7 +231,7 @@ npm test -- 'LinkedList' **Campo de juegos** -Puede jugar con estructuras de datos y algoritmos en el archivo `./src/playground/playground.js` y escribir +Puede jugar con estructuras de datos y algoritmos en el archivo `./src/playground/playground.js` y escribir pruebas para ello en `./src/playground/__test__/playground.test.js`. A continuación, simplemente ejecute el siguiente comando para comprobar si el código funciona como se espera: @@ -254,7 +254,7 @@ Orden de crecimiento de los algoritmos especificados en la notación O grande. Fuente: [Big O Cheat Sheet](http://bigocheatsheet.com/). -A continuación se muestra la lista de algunas de las notaciones de Big O más utilizadas y sus comparaciones de rendimiento +A continuación se muestra la lista de algunas de las notaciones de Big O más utilizadas y sus comparaciones de rendimiento frente a diferentes tamaños de los datos de entrada. | Notación O grande | Cálculos para 10 elementos | Cálculos para 100 elementos | Cálculos para 1000 elementos | diff --git a/README.it-IT.md b/README.it-IT.md index 2f7c7cc66c..57c054df1e 100644 --- a/README.it-IT.md +++ b/README.it-IT.md @@ -56,7 +56,7 @@ un insieme di regole che definiscono con precisione una sequenza di operazioni. * **Matematica** * `P` [Manipolazione dei Bit](src/algorithms/math/bits) - set/get/update/clear bits, moltiplicazione/divisione per due, gestire numeri negativi etc. - * `P` [Fattoriale](src/algorithms/math/factorial) + * `P` [Fattoriale](src/algorithms/math/factorial) * `P` [Numeri di Fibonacci](src/algorithms/math/fibonacci) - classico e forma chiusa * `P` [Test di Primalità](src/algorithms/math/primality-test) (metodo del divisore) * `P` [Algoritmo di Euclide](src/algorithms/math/euclidean-algorithm) - trova il massimo comune divisore (MCD) @@ -64,13 +64,13 @@ un insieme di regole che definiscono con precisione una sequenza di operazioni. * `P` [Crivello di Eratostene](src/algorithms/math/sieve-of-eratosthenes) - trova i numeri i primi fino al limite indicato * `P` [Potenza di due](src/algorithms/math/is-power-of-two) - controlla se il numero è una potenza di due * `P` [Triangolo di Pascal](src/algorithms/math/pascal-triangle) - * `P` [Numeri Complessi](src/algorithms/math/complex-number) - numeri complessi e operazioni + * `P` [Numeri Complessi](src/algorithms/math/complex-number) - numeri complessi e operazioni * `P` [Radiante & Gradi](src/algorithms/math/radian) - conversione da radiante a gradi e viceversa * `P` [Potenza di un Numero](src/algorithms/math/fast-powering) * `A` [Partizione di un Intero](src/algorithms/math/integer-partition) * `A` [Radice Quadrata](src/algorithms/math/square-root) - Metodo di Newton * `A` [Algoritmo di Liu Hui π](src/algorithms/math/liu-hui) - calcolare π usando un poligono - * `A` [Trasformata Discreta di Fourier ](src/algorithms/math/fourier-transform) -decomporre una funzione di tempo (un segnale) nelle frequenze che lo compongono + * `A` [Trasformata Discreta di Fourier ](src/algorithms/math/fourier-transform) -decomporre una funzione di tempo (un segnale) nelle frequenze che lo compongono * **Set** * `P` [Prodotto Cartesiano](src/algorithms/sets/cartesian-product) - moltiplicazione multipla di set * `P` [Fisher–Yates Shuffle](src/algorithms/sets/fisher-yates) - permutazione casuale di un sequenza finita @@ -116,8 +116,8 @@ un insieme di regole che definiscono con precisione una sequenza di operazioni. * `P` [Ricerca in Profondità su Grafi](src/algorithms/graph/depth-first-search) (DFS) * `P` [Breadth-First Search su Grafi](src/algorithms/graph/breadth-first-search) (BFS) * `P` [Algoritmo di Kruskal](src/algorithms/graph/kruskal) - ricerca dell'Albero con Minima Distanza (MST) per grafi pesati unidirezionali - * `A` [Algoritmo di Dijkstra](src/algorithms/graph/dijkstra) - ricerca dei percorsi più breve per raggiungere tutti i vertici del grafo da un singolo vertice - * `A` [Algoritmo di Bellman-Ford](src/algorithms/graph/bellman-ford) - ricerca dei percorsi più breve per raggiungere tutti i vertici del grafo da un singolo vertice + * `A` [Algoritmo di Dijkstra](src/algorithms/graph/dijkstra) - ricerca dei percorsi più breve per raggiungere tutti i vertici del grafo da un singolo vertice + * `A` [Algoritmo di Bellman-Ford](src/algorithms/graph/bellman-ford) - ricerca dei percorsi più breve per raggiungere tutti i vertici del grafo da un singolo vertice * `A` [Algoritmo di Floyd-Warshall](src/algorithms/graph/floyd-warshall) - ricerca dei percorsi più brevi tra tutte le coppie di vertici * `A` [Rivelamento dei Cicli](src/algorithms/graph/detect-cycle) - per grafici diretti e non diretti (basate su partizioni DFS e Disjoint Set) * `A` [Algoritmo di Prim](src/algorithms/graph/prim) - ricerca dell'Albero Ricoprente Minimo (MST) per grafi unidirezionali pesati @@ -129,12 +129,12 @@ un insieme di regole che definiscono con precisione una sequenza di operazioni. * `A` [Componenti Fortemente Connessa](src/algorithms/graph/strongly-connected-components) - algoritmo di Kosaraju * `A` [Problema del Commesso Viaggiatore](src/algorithms/graph/travelling-salesman) - il percorso più breve che visita ogni città e ritorna alla città iniziale * **Crittografia** - * `P` [Hash Polinomiale](src/algorithms/cryptography/polynomial-hash) - Una funzione hash di rolling basata sul polinomio + * `P` [Hash Polinomiale](src/algorithms/cryptography/polynomial-hash) - Una funzione hash di rolling basata sul polinomio * **Senza categoria** * `P` [Torre di Hanoi](src/algorithms/uncategorized/hanoi-tower) * `P` [Rotazione Matrice Quadrata](src/algorithms/uncategorized/square-matrix-rotation) - algoritmo in memoria * `P` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, programmazione dinamica (top-down + bottom-up) ed esempre di greeedy - * `P` [Percorsi Unici](src/algorithms/uncategorized/unique-paths) - backtracking, programmazione dinamica and l'esempio del Triangolo di Pascal + * `P` [Percorsi Unici](src/algorithms/uncategorized/unique-paths) - backtracking, programmazione dinamica and l'esempio del Triangolo di Pascal * `P` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - problema dell'acqua piovana in trappola(versione con programmazione dinamica e brute force) * `P` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - contare il numero di percorsi per arrivare in vetta(4 soluzioni) * `A` [Rompicapo delle Otto Regine](src/algorithms/uncategorized/n-queens) @@ -151,14 +151,14 @@ un insieme di regole che definiscono con precisione una sequenza di operazioni. * `P` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - contare il numero di percorsi per arrivare in vetta * `A` [Massimo SubArray](src/algorithms/sets/maximum-subarray) * `A` [Problema del commesso viaggiatore](src/algorithms/graph/travelling-salesman) - il percorso più breve che visita ogni città e ritorna alla città iniziale - * `A` [Trasformata Discreta di Fourier](src/algorithms/math/fourier-transform) - scomporre la funzione (segnale) del tempo in frequenze che la compongono + * `A` [Trasformata Discreta di Fourier](src/algorithms/math/fourier-transform) - scomporre la funzione (segnale) del tempo in frequenze che la compongono * **Greedy** - scegliere l'opzione migliore al momento d'eleborazione dell'algoritmo, senza alcuna considerazione per il futuro * `P` [Jump Game](src/algorithms/uncategorized/jump-game) * `A` [Problema dello Zaino di Knapsack](src/algorithms/sets/knapsack-problem) * `A` [Algoritmo di Dijkstra](src/algorithms/graph/dijkstra) - ricerca del percorso più breve tra tutti i vertici del grafo - * `A` [Algoritmo di Prim](src/algorithms/graph/prim) - ricerca del Minimo Albero Ricoprente per grafi pesati e unidirezionali + * `A` [Algoritmo di Prim](src/algorithms/graph/prim) - ricerca del Minimo Albero Ricoprente per grafi pesati e unidirezionali * `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph -* **Divide e Conquista** - divide il problema in piccole parti e risolve ogni parte +* **Divide e Conquista** - divide il problema in piccole parti e risolve ogni parte * `P` [Ricerca Binaria](src/algorithms/search/binary-search) * `P` [Torre di Hanoi](src/algorithms/uncategorized/hanoi-tower) * `P` [Triangolo di Pascal](src/algorithms/math/pascal-triangle) @@ -186,7 +186,7 @@ un insieme di regole che definiscono con precisione una sequenza di operazioni. * `A` [Partizione di un Intero](src/algorithms/math/integer-partition) * `A` [Massimo SubArray](src/algorithms/sets/maximum-subarray) * `A` [Algoritmo di Bellman-Ford](src/algorithms/graph/bellman-ford) - ricerca del percorso più breve per tutti i vertici del grafo - * `A` [Algoritmo di Floyd-Warshall](src/algorithms/graph/floyd-warshall) - ricerca del percorso più breve tra tutte le coppie di vertici + * `A` [Algoritmo di Floyd-Warshall](src/algorithms/graph/floyd-warshall) - ricerca del percorso più breve tra tutte le coppie di vertici * `A` [Espressioni Regolari](src/algorithms/string/regular-expression-matching) * **Backtracking** - come la brute force, provate a generare tutte le soluzioni possibili, ma ogni volta che generate la prossima soluzione testate se soddisfa tutte le condizioni e solo allora continuare a generare soluzioni successive. Altrimenti, fate marcia indietro, e andate su un percorso diverso per trovare una soluzione. Normalmente si utilizza l'algoritmo DFS. * `P` [Jump Game](src/algorithms/uncategorized/jump-game) @@ -228,10 +228,10 @@ npm test -- 'LinkedList' **Playground** -Se vuoi puoi giocare le strutture dati e gli algoritmi nel file ./src/playground/playground.js` e +Se vuoi puoi giocare le strutture dati e gli algoritmi nel file ./src/playground/playground.js` e scrivere test nel file `./src/playground/__test__/playground.test.js`. -Poi puoi semplicemente eseguire il seguente comando per testare quello che hai scritto : +Poi puoi semplicemente eseguire il seguente comando per testare quello che hai scritto : ``` npm test -- 'playground' @@ -243,9 +243,9 @@ npm test -- 'playground' [▶ Data Structures and Algorithms on YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) -### Notazione Big O +### Notazione Big O -* La notazione Big O* è usata per classificare algoritmi in base al tempo di esecuzione o ai +* La notazione Big O* è usata per classificare algoritmi in base al tempo di esecuzione o ai requisiti di spazio che crescono in base alla crescita dell'input . Nella grafico qua sotto puoi trovare gli ordini di crescita più comuni degli algoritmi usando la notazione Big O. diff --git a/README.ja-JP.md b/README.ja-JP.md index 1c145a604e..7ec49e4eeb 100644 --- a/README.ja-JP.md +++ b/README.ja-JP.md @@ -60,7 +60,7 @@ _Read this in other languages:_ * **数学** * `B` [ビット操作](src/algorithms/math/bits) - set/get/update/clear bits, 2つの乗算/除算, 否定的にする. 等 - * `B` [因果関係](src/algorithms/math/factorial) + * `B` [因果関係](src/algorithms/math/factorial) * `B` [フィボナッチ数](src/algorithms/math/fibonacci) - クラシックとクローズドフォームのバージョン * `B` [素数性テスト](src/algorithms/math/primality-test) (trial division 方法) * `B` [ユークリッドアルゴリズム](src/algorithms/math/euclidean-algorithm) - 最大公約数を計算する (GCD) @@ -118,7 +118,7 @@ _Read this in other languages:_ * **グラフ** * `B` [深度優先検索](src/algorithms/graph/depth-first-search) (DFS) * `B` [幅優先検索](src/algorithms/graph/breadth-first-search) (BFS) - * `B` [Kruskalのアルゴリズム](src/algorithms/graph/kruskal) - 重み付き無向グラフの最小スパニングツリー(MST)の発見 + * `B` [Kruskalのアルゴリズム](src/algorithms/graph/kruskal) - 重み付き無向グラフの最小スパニングツリー(MST)の発見 * `A` [Dijkstraアルゴリズム](src/algorithms/graph/dijkstra) - 単一の頂点からすべてのグラフ頂点への最短経路を見つける * `A` [Bellman-Fordアルゴリズム](src/algorithms/graph/bellman-ford) - 単一の頂点からすべてのグラフ頂点への最短経路を見つける * `A` [Floyd-Warshallアルゴリズム](src/algorithms/graph/floyd-warshall) - すべての頂点ペア間の最短経路を見つける diff --git a/README.ko-KR.md b/README.ko-KR.md index b5be09f69e..8a31e81101 100644 --- a/README.ko-KR.md +++ b/README.ko-KR.md @@ -25,7 +25,7 @@ _Read this in other languages:_ 자료 구조는 데이터를 특정 방식으로 구성하고 저장함으로써 더 효율적으로 접근하고 수정할 수 있게 해줍니다. 간단히 말해, 자료 구조는 데이터 값들, -데이터 간의 관계, 그리고 데이터를 다룰 수 있는 함수와 작업의 모임입니다. +데이터 간의 관계, 그리고 데이터를 다룰 수 있는 함수와 작업의 모임입니다. `B` - 입문자, `A` - 숙련자 @@ -50,8 +50,8 @@ _Read this in other languages:_ ## 알고리즘 -알고리즘은 어떤 종류의 문제를 풀 수 있는 정확한 방법이며, -일련의 작업을 정확하게 정의해 놓은 규칙들입니다. +알고리즘은 어떤 종류의 문제를 풀 수 있는 정확한 방법이며, +일련의 작업을 정확하게 정의해 놓은 규칙들입니다. `B` - 입문자, `A` - 숙련자 @@ -59,7 +59,7 @@ _Read this in other languages:_ * **Math** * `B` [Bit Manipulation](src/algorithms/math/bits) - set/get/update/clear bits, 2의 곱 / 나누기, 음수로 만들기 etc. - * `B` [팩토리얼](src/algorithms/math/factorial) + * `B` [팩토리얼](src/algorithms/math/factorial) * `B` [피보나치 수](src/algorithms/math/fibonacci) * `B` [소수 판별](src/algorithms/math/primality-test) (trial division 방식) * `B` [유클리드 호제법](src/algorithms/math/euclidean-algorithm) - 최대공약수 (GCD) @@ -126,7 +126,7 @@ _Read this in other languages:_ * **Uncategorized** * `B` [하노이 탑](src/algorithms/uncategorized/hanoi-tower) * `B` [정방 행렬 회전](src/algorithms/uncategorized/square-matrix-rotation) - 제자리(in-place) 알고리즘 - * `B` [점프 게임](src/algorithms/uncategorized/jump-game) - 백트래킹, 동적계획법 (top-down + bottom-up), 탐욕 알고리즘 예제 + * `B` [점프 게임](src/algorithms/uncategorized/jump-game) - 백트래킹, 동적계획법 (top-down + bottom-up), 탐욕 알고리즘 예제 * `B` [Unique 경로](src/algorithms/uncategorized/unique-paths) - 백트래킹, 동적계획법, 파스칼 삼각형에 기반한 예제 * `B` [빗물 담기 문제](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (동적계획법, 브루트포스 버전) * `A` [N-Queens 문제](src/algorithms/uncategorized/n-queens) diff --git a/README.md b/README.md index 2ee72e2268..e108671a22 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Bit Manipulation](src/algorithms/math/bits) - set/get/update/clear bits, multiplication/division by two, make negative etc. * `B` [Factorial](src/algorithms/math/factorial) * `B` [Fibonacci Number](src/algorithms/math/fibonacci) - classic and closed-form versions - * `B` [Prime Factors](src/algorithms/math/prime-factors) - finding prime factors and counting them using Hardy-Ramanujan's theorem + * `B` [Prime Factors](src/algorithms/math/prime-factors) - finding prime factors and counting them using Hardy-Ramanujan's theorem * `B` [Primality Test](src/algorithms/math/primality-test) (trial division method) * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD) * `B` [Least Common Multiple](src/algorithms/math/least-common-multiple) (LCM) @@ -142,7 +142,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - rolling hash function based on polynomial * `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - simple substitution cipher * **Machine Learning** - * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation) + * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation) * `B` [KNN](src/algorithms/ML/KNN) - K Nearest Neighbors * **Uncategorized** * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower) diff --git a/README.pl-PL.md b/README.pl-PL.md index bdac149533..98fe798913 100644 --- a/README.pl-PL.md +++ b/README.pl-PL.md @@ -3,11 +3,11 @@ [![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) -To repozytorium zawiera wiele przykładów JavaScript opartych na +To repozytorium zawiera wiele przykładów JavaScript opartych na znanych algorytmach i strukturach danych. Każdy algorytm i struktura danych zawiera osobny plik README -wraz z powiązanymi wyjaśnieniami i odnośnikami do dalszego czytania +wraz z powiązanymi wyjaśnieniami i odnośnikami do dalszego czytania (włącznie z tymi do YouTube videos). _Read this in other languages:_ @@ -25,10 +25,10 @@ _Read this in other languages:_ ## Struktury Danych -Struktura danych to sposób uporządkowania i przechowywania informacji w +Struktura danych to sposób uporządkowania i przechowywania informacji w komputerze żeby mogłaby być sprawnie dostępna i efektywnie zmodyfikowana. -Dokładniej, struktura danych jest zbiorem wartości danych, relacjami -pomiędzy nimi, zadaniami lub działaniami, które mogą dotyczyć danych. +Dokładniej, struktura danych jest zbiorem wartości danych, relacjami +pomiędzy nimi, zadaniami lub działaniami, które mogą dotyczyć danych. `B` - Początkujący, `A` - Zaawansowany @@ -52,8 +52,8 @@ pomiędzy nimi, zadaniami lub działaniami, które mogą dotyczyć danych. ## Algorytmy -Algorytm jest to skończony ciąg jasno zdefiniowanych czynności, koniecznych -do wykonania pewnego rodzaju zadań. Sposób postępowania prowadzący do +Algorytm jest to skończony ciąg jasno zdefiniowanych czynności, koniecznych +do wykonania pewnego rodzaju zadań. Sposób postępowania prowadzący do rozwiązania problemu. `B` - Początkujący, `A` - Zaawansowany @@ -62,7 +62,7 @@ rozwiązania problemu. * **Matematyka** * `B` [Manipulacja Bitami](src/algorithms/math/bits) - ustaw / uzyskaj / aktualizuj / usuwaj bity, mnożenie / dzielenie przez dwa, tworzenie negatywów itp. - * `B` [Silna](src/algorithms/math/factorial) + * `B` [Silna](src/algorithms/math/factorial) * `B` [Ciąg Fibonacciego](src/algorithms/math/fibonacci) * `B` [Test Pierwszorzędności](src/algorithms/math/primality-test) (metoda podziału na próby) * `B` [Algorytm Euclideana](src/algorithms/math/euclidean-algorithm) - obliczyć Największy Wspólny Dzielnik (GCD) @@ -81,9 +81,9 @@ rozwiązania problemu. * `A` [Najdłuższa Wspólna Podsekwencja](src/algorithms/sets/longest-common-subsequence) (LCS) * `A` [Najdłuższa Wzrostająca Podsekwencja](src/algorithms/sets/longest-increasing-subsequence) * `A` [Najkrótsza Wspólna Supersekwencja](src/algorithms/sets/shortest-common-supersequence) (SCS) - * `A` [Problem Knapsacka](src/algorithms/sets/knapsack-problem) - "0/1" i "Rozwiązany" + * `A` [Problem Knapsacka](src/algorithms/sets/knapsack-problem) - "0/1" i "Rozwiązany" * `A` [Maksymalna Podtablica](src/algorithms/sets/maximum-subarray) - "Metoda Siłowa" i "Dynamiczne Programowanie" (Kadane-a) wersje - * `A` [Suma Kombinacji](src/algorithms/sets/combination-sum) - + * `A` [Suma Kombinacji](src/algorithms/sets/combination-sum) - znajdź wszystkie kombinacje, które tworzą określoną sumę * **Łańcuchy** * `B` [Odległość Hamminga](src/algorithms/string/hamming-distance) - liczba pozycji, w których symbole są różne @@ -120,26 +120,26 @@ znajdź wszystkie kombinacje, które tworzą określoną sumę * `A` [Algorytm Floyd-Warshalla](src/algorithms/graph/floyd-warshall) - znajdź najkrótsze ścieżki między wszystkimi parami wierzchołków * `A` [Detect Cycle](src/algorithms/graph/detect-cycle) - zarówno dla wykresów skierowanych, jak i nieukierunkowanych(wersje oparte na DFS i Rozłączny Zestaw) * `A` [Algorytm Prima](src/algorithms/graph/prim) - znalezienie Minimalnego Drzewa Opinającego (MST) dla ważonego nieukierunkowanego wykresu - * `A` [Sortowanie Topologiczne](src/algorithms/graph/topological-sorting) - metoda DFS + * `A` [Sortowanie Topologiczne](src/algorithms/graph/topological-sorting) - metoda DFS * `A` [Punkty Artykulacji](src/algorithms/graph/articulation-points) - Algorytm Tarjana (oparty o DFS) - * `A` [Mosty](src/algorithms/graph/bridges) - Oparty na algorytmie DFS + * `A` [Mosty](src/algorithms/graph/bridges) - Oparty na algorytmie DFS * `A` [Ścieżka Euleriana i Obwód Euleriana](src/algorithms/graph/eulerian-path) - Algorytm Fleurya - Odwiedź każdą krawędź dokładnie raz * `A` [Cykl Hamiltoniana](src/algorithms/graph/hamiltonian-cycle) - Odwiedź każdy wierzchołek dokładnie raz - * `A` [Silnie Połączone Komponenty](src/algorithms/graph/strongly-connected-components) - Algorytm Kosaraja + * `A` [Silnie Połączone Komponenty](src/algorithms/graph/strongly-connected-components) - Algorytm Kosaraja * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - najkrótsza ścieżka która odwiedza każde miasto i wraca miasta początkującego * **Niezkategorizowane** * `B` [Wieża Hanoi](src/algorithms/uncategorized/hanoi-tower) * `B` [Kwadratowa Matryca Obrotu](src/algorithms/uncategorized/square-matrix-rotation) - algorytm w miejscu - * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - cofanie, dynamiczne programowanie (od góry do dołu + od dołu do góry) i przykłady chciwego + * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - cofanie, dynamiczne programowanie (od góry do dołu + od dołu do góry) i przykłady chciwego * `B` [Unikatowe Ścieżki](src/algorithms/uncategorized/unique-paths) - cofanie, dynamiczne programowanie i przykłady oparte na Trójkącie Pascala * `A` [Problem N-Queens](src/algorithms/uncategorized/n-queens) * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour) ### Algorytmy według paradygmatu -Paradygmat algorytmiczny jest ogólną metodą lub podejściem, które jest -podstawą projektowania klasy algorytmów. Jest abstrakcją wyższą niż -pojęcie algorytmu, podobnie jak algorytm jest abstrakcją wyższą niż +Paradygmat algorytmiczny jest ogólną metodą lub podejściem, które jest +podstawą projektowania klasy algorytmów. Jest abstrakcją wyższą niż +pojęcie algorytmu, podobnie jak algorytm jest abstrakcją wyższą niż program komputerowy. * **Metoda Siłowa** - Sprawdza wszystkie możliwosci i wybiera najlepsze rozwiązanie. @@ -149,7 +149,7 @@ program komputerowy. * **Chciwy** - wybierz najlepszą opcję w obecnym czasie, bez względu na przyszłość * `B` [Jump Game](src/algorithms/uncategorized/jump-game) * `A` [Niezwiązany Problem Knapsacka ](src/algorithms/sets/knapsack-problem) - * `A` [Algorytm Dijkstry](src/algorithms/graph/dijkstra) - + * `A` [Algorytm Dijkstry](src/algorithms/graph/dijkstra) - znalezienie najkrótszej ścieżki do wszystkich wierzchołków grafu * `A` [Algorytm Prima](src/algorithms/graph/prim) - znalezienie Minimalnego Drzewa Opinającego (MST) dla ważonego nieukierunkowanego wykresu * `A` [Algorytm Kruskala](src/algorithms/graph/kruskal) - znalezienie Minimalnego Drzewa Opinającego (MST) dla ważonego nieukierunkowanego wykresu @@ -178,7 +178,7 @@ znalezienie najkrótszej ścieżki do wszystkich wierzchołków grafu * `A` [Partycja Całkowita](src/algorithms/math/integer-partition) * `A` [Maksymalne Podtablice](src/algorithms/sets/maximum-subarray) * `A` [Algorytm Bellman-Forda](src/algorithms/graph/bellman-ford) - znalezienie najkrótszej ścieżki wszystkich wierzchołków wykresu - * `A` [Algorytm Floyd-Warshalla](src/algorithms/graph/floyd-warshall) - + * `A` [Algorytm Floyd-Warshalla](src/algorithms/graph/floyd-warshall) - znajdź najkrótsze ścieżki między wszystkimi parami wierzchołków * `A` [Dopasowanie Wyrażeń Regularnych](src/algorithms/string/regular-expression-matching) * **Algorytm z nawrotami** - podobny do metody siłowej, próbuje wygenerować wszystkie możliwe rozwiązania, jednak za każdym razem generujesz następne rozwiązanie które testujesz @@ -192,7 +192,7 @@ jeżeli zaspokaja wszystkie warunki, tylko wtedy generuje kolejne rozwiązania. * **Metoda Podziału i Ograniczeń** - Pamięta o niskonakładowym rozwiązaniu znalezionym na każdym etapie szukania nawrotu, używa kosztu niskonakładowego kosztu, które dotychczas zostało znalezione jako niska granica najmniejszego kosztu do rozwiązanie problemu, aby odrzucić cząstkowe rozwiązania o kosztach większych niż niskonakładowe -rozwiązanie znalezione do tej pory. +rozwiązanie znalezione do tej pory. Zazwyczan trajektoria BFS, w połączeniu z trajektorią Przeszukiwania W Głąb (DFS) drzewa przestrzeni stanów jest użyte. ## Jak używać repozytorium @@ -225,7 +225,7 @@ npm test -- 'LinkedList' Możesz pociwiczyć ze strukturą danych i algorytmami w `./src/playground/playground.js` zakartotekuj i napisz testy do tego w `./src/playground/__test__/playground.test.js`. -Następnie uruchom następującą komendę w celu przetestowania czy twoje kod działa według oczekiwań: +Następnie uruchom następującą komendę w celu przetestowania czy twoje kod działa według oczekiwań: ``` npm test -- 'playground' @@ -239,7 +239,7 @@ npm test -- 'playground' ### Big O Notacja -Kolejność wzrastania algorytmów według Big O notacji. +Kolejność wzrastania algorytmów według Big O notacji. ![Big O grafy](./assets/big-o-graph.png) diff --git a/README.pt-BR.md b/README.pt-BR.md index a9fc0d34ce..e95477ed15 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -4,7 +4,7 @@ [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) Este repositório contém exemplos baseados em JavaScript de muitos -algoritmos e estruturas de dados populares. +algoritmos e estruturas de dados populares. Cada algoritmo e estrutura de dado possui seu próprio README com explicações relacionadas e links para leitura adicional (incluindo @@ -61,7 +61,7 @@ um conjunto de regras que define precisamente uma sequência de operações. * **Matemática** * `B` [Manipulação Bit](src/algorithms/math/bits) - set/get/update/clear bits, multiplicação / divisão por dois, tornar negativo etc. - * `B` [Fatorial](src/algorithms/math/factorial) + * `B` [Fatorial](src/algorithms/math/factorial) * `B` [Número de Fibonacci](src/algorithms/math/fibonacci) * `B` [Teste de Primalidade](src/algorithms/math/primality-test) (método de divisão experimental) * `B` [Algoritmo Euclidiano](src/algorithms/math/euclidean-algorithm) - calcular o maior divisor comum (GCD) @@ -119,7 +119,7 @@ um conjunto de regras que define precisamente uma sequência de operações. * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - encontrar caminhos mais curtos entre todos os pares de vértices * `A` [Detect Cycle](src/algorithms/graph/detect-cycle) - para gráficos direcionados e não direcionados (versões baseadas em DFS e Conjunto Disjuntivo) * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - encontrando Árvore Mínima de Abrangência (MST) para grafo não direcionado ponderado - * `A` [Topological Sorting](src/algorithms/graph/topological-sorting) - Métodos DFS + * `A` [Topological Sorting](src/algorithms/graph/topological-sorting) - Métodos DFS * `A` [Articulation Points](src/algorithms/graph/articulation-points) -O algoritmo de Tarjan (baseado em DFS) * `A` [Bridges](src/algorithms/graph/bridges) - Algoritmo baseado em DFS * `A` [Eulerian Path and Eulerian Circuit](src/algorithms/graph/eulerian-path) - Algoritmo de Fleury - Visite todas as bordas exatamente uma vez diff --git a/README.ru-RU.md b/README.ru-RU.md index 9365bca163..e1bdb49454 100644 --- a/README.ru-RU.md +++ b/README.ru-RU.md @@ -56,7 +56,7 @@ _Читать на других языках:_ * **Математика** * `B` [Битовые манипуляции](src/algorithms/math/bits) — получение/запись/сброс/обновление битов, умножение/деление на 2, сделать отрицательным и т.п. - * `B` [Факториал](src/algorithms/math/factorial) + * `B` [Факториал](src/algorithms/math/factorial) * `B` [Числа Фибоначчи](src/algorithms/math/fibonacci) — классическое решение, решение в замкнутой форме * `B` [Тест простоты](src/algorithms/math/primality-test) (метод пробного деления) * `B` [Алгоритм Евклида](src/algorithms/math/euclidean-algorithm) — нахождение наибольшего общего делителя (НОД) @@ -70,7 +70,7 @@ _Читать на других языках:_ * `A` [Разбиение числа](src/algorithms/math/integer-partition) * `A` [Квадратный корень](src/algorithms/math/square-root) — метод Ньютона * `A` [Алгоритм Лю Хуэя](src/algorithms/math/liu-hui) — расчёт числа π с заданной точностью методом вписанных правильных многоугольников - * `A` [Дискретное преобразование Фурье](src/algorithms/math/fourier-transform) — разложение временной функции (сигнала) на частотные составляющие + * `A` [Дискретное преобразование Фурье](src/algorithms/math/fourier-transform) — разложение временной функции (сигнала) на частотные составляющие * **Множества** * `B` [Декартово произведение](src/algorithms/sets/cartesian-product) — результат перемножения множеств * `B` [Тасование Фишера — Йетса](src/algorithms/sets/fisher-yates) — создание случайных перестановок конечного множества @@ -135,7 +135,7 @@ _Читать на других языках:_ * **Прочие алгоритмы** * `B` [Ханойская башня](src/algorithms/uncategorized/hanoi-tower) * `B` [Поворот квадратной матрицы](src/algorithms/uncategorized/square-matrix-rotation) — используется дополнительная память - * `B` [Прыжки](src/algorithms/uncategorized/jump-game) — на основе бэктрекинга, динамического программирования (сверху-вниз + снизу-вверх) и жадных алгоритмов + * `B` [Прыжки](src/algorithms/uncategorized/jump-game) — на основе бэктрекинга, динамического программирования (сверху-вниз + снизу-вверх) и жадных алгоритмов * `B` [Поиск уникальных путей](src/algorithms/uncategorized/unique-paths) — на основе бэктрекинга, динамического программирования и треугольника Паскаля * `B` [Подсчёт дождевой воды](src/algorithms/uncategorized/rain-terraces) — на основе перебора и динамического программирования * `B` [Задача о рекурсивной лестнице](src/algorithms/uncategorized/recursive-staircase) — подсчёт количества путей, по которым можно достичь верха лестницы (4 способа) @@ -153,7 +153,7 @@ _Читать на других языках:_ * `A` [Максимальный подмассив](src/algorithms/sets/maximum-subarray) * `A` [Задача коммивояжёра](src/algorithms/graph/travelling-salesman) — кратчайший маршрут, проходящий через указанные города с последующим возвратом в исходный город * `A` [Дискретное преобразование Фурье](src/algorithms/math/fourier-transform) — разложение временной функции (сигнала) на частотные составляющие -* **Жадные алгоритмы** — принятие локально оптимальных решений с учётом допущения об оптимальности конечного решения +* **Жадные алгоритмы** — принятие локально оптимальных решений с учётом допущения об оптимальности конечного решения * `B` [Прыжки](src/algorithms/uncategorized/jump-game) * `A` [Задача о неограниченном рюкзаке](src/algorithms/sets/knapsack-problem) * `A` [Алгоритм Дейкстры](src/algorithms/graph/dijkstra) — нахождение кратчайших путей от одной из вершин графа до всех остальных @@ -228,7 +228,7 @@ npm test -- 'LinkedList' **Песочница** -Вы можете экспериментировать с алгоритмами и структурами данных в файле `./src/playground/playground.js` +Вы можете экспериментировать с алгоритмами и структурами данных в файле `./src/playground/playground.js` (файл `./src/playground/__test__/playground.test.js` предназначен для написания тестов). Для проверки работоспособности вашего кода используйте команду: diff --git a/README.tr-TR.md b/README.tr-TR.md index 62db14d1d0..7d2cc7919f 100644 --- a/README.tr-TR.md +++ b/README.tr-TR.md @@ -6,8 +6,8 @@ Bu repository JavaScript'e ait popüler algoritma ve veri yapılarını içermektedir. -Her bir algoritma ve veri yapısı kendine -ait açıklama ve videoya sahip README dosyası içerir. +Her bir algoritma ve veri yapısı kendine +ait açıklama ve videoya sahip README dosyası içerir. _Read this in other languages:_ [_简体中文_](README.zh-CN.md), @@ -21,7 +21,7 @@ _Read this in other languages:_ [_Русский_](README.ru-RU.md), [_Italiana_](README.it-IT.md) -*☝ Not, bu proje araştırma ve öğrenme amacı ile yapılmış +*☝ Not, bu proje araştırma ve öğrenme amacı ile yapılmış olup üretim için **yaplılmamıştır**.* ## Veri Yapıları @@ -63,7 +63,7 @@ bir işlem dizisini kesin olarak tanımlayan bir dizi kural. * **Matematik** * `B` [Bit Manipülasyonu](src/algorithms/math/bits) - set/get/update/clear bits, multiplication/division by two, make negative etc. - * `B` [Faktöriyel](src/algorithms/math/factorial) + * `B` [Faktöriyel](src/algorithms/math/factorial) * `B` [Fibonacci Sayısı](src/algorithms/math/fibonacci) - klasik ve kapalı-form versiyonları * `B` [Asallık Testi](src/algorithms/math/primality-test) (trial division method) * `B` [Öklid Algoritması](src/algorithms/math/euclidean-algorithm) - En büyük ortak bölen hesaplama (EBOB) @@ -143,8 +143,8 @@ bir işlem dizisini kesin olarak tanımlayan bir dizi kural. * **Kategoriye Ayrılmayanlar** * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower) * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm - * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, dynamic programming (top-down + bottom-up) and greedy examples - * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples + * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - backtracking, dynamic programming (top-down + bottom-up) and greedy examples + * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (dynamic programming and brute force versions) * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - tepeye ulaşmanın yollarını sayma (4 çözüm) * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens) @@ -152,8 +152,8 @@ bir işlem dizisini kesin olarak tanımlayan bir dizi kural. ### Algoritmik Paradigma -Algoritmik paradigma, bir sınıfın tasarımının altında yatan genel bir yöntem veya yaklaşımdır. -Algoritma dizayn tekniği olarak düşünülebilir. Her bir altproblemi (subproblem) asıl problemle +Algoritmik paradigma, bir sınıfın tasarımının altında yatan genel bir yöntem veya yaklaşımdır. +Algoritma dizayn tekniği olarak düşünülebilir. Her bir altproblemi (subproblem) asıl problemle benzerlik gösteren problemlere uygulanabilir. * **Brute Force** - mümkün olan tüm çözümleri tara ve en iyisini seç @@ -198,7 +198,7 @@ benzerlik gösteren problemlere uygulanabilir. * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray) * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - tüm grafik köşelerine giden en kısa yolu bulmak * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - tüm köşe çiftleri arasındaki en kısa yolları bulun - * `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching) + * `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching) * **Backtracking** - brute forceye benzer, mümkün tüm sonuçları tara, ancak bir sonraki çözümü her ürettiğinizde test edersiniz tüm koşulları karşılıyorsa ve ancak o zaman sonraki çözümleri üretmeye devam edin. Aksi takdirde, geri dönün ve farklı bir çözüm arayın(?). Normally the DFS traversal of state-space is being used. @@ -242,7 +242,7 @@ npm test -- 'LinkedList' **Deneme Alanı** -data-structures ve algorithms içerisinde `./src/playground/playground.js` +data-structures ve algorithms içerisinde `./src/playground/playground.js` yazarak `./src/playground/__test__/playground.test.js` için test edebilirsin. @@ -310,4 +310,4 @@ Altta Big O notations ve farklı input boyutlarına karşın yapılmış perform ## Projeyi Destekleme -Bu projeyi buradan destekleyebilirsiniz ❤️️ [GitHub](https://github.com/sponsors/trekhleb) veya ❤️️ [Patreon](https://www.patreon.com/trekhleb). +Bu projeyi buradan destekleyebilirsiniz ❤️️ [GitHub](https://github.com/sponsors/trekhleb) veya ❤️️ [Patreon](https://www.patreon.com/trekhleb). diff --git a/src/algorithms/sorting/bubble-sort/README.md b/src/algorithms/sorting/bubble-sort/README.md index 596d4006af..66347d86c7 100644 --- a/src/algorithms/sorting/bubble-sort/README.md +++ b/src/algorithms/sorting/bubble-sort/README.md @@ -3,12 +3,12 @@ _Read this in other languages:_ [_Português_](README.pt-BR.md) -Bubble sort, sometimes referred to as sinking sort, is a -simple sorting algorithm that repeatedly steps through -the list to be sorted, compares each pair of adjacent -items and swaps them if they are in the wrong order +Bubble sort, sometimes referred to as sinking sort, is a +simple sorting algorithm that repeatedly steps through +the list to be sorted, compares each pair of adjacent +items and swaps them if they are in the wrong order (ascending or descending arrangement). The pass through -the list is repeated until no swaps are needed, which +the list is repeated until no swaps are needed, which indicates that the list is sorted. ![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/c/c8/Bubble-sort-example-300px.gif) diff --git a/src/algorithms/sorting/bubble-sort/README.pt-BR.md b/src/algorithms/sorting/bubble-sort/README.pt-BR.md index 39a3029500..c7862bb957 100644 --- a/src/algorithms/sorting/bubble-sort/README.pt-BR.md +++ b/src/algorithms/sorting/bubble-sort/README.pt-BR.md @@ -1,6 +1,6 @@ # Bubble Sort -O bubble sort, ou ordenação por flutuação (literalmente "por bolha"), é um algoritmo de ordenação dos mais simples. A ideia é percorrer o vetor diversas vezes, e a cada passagem fazer flutuar para o topo o maior elemento da sequência. Essa movimentação lembra a forma como as bolhas em um tanque de água procuram seu próprio nível, e disso vem o nome do algoritmo. +O bubble sort, ou ordenação por flutuação (literalmente "por bolha"), é um algoritmo de ordenação dos mais simples. A ideia é percorrer o vetor diversas vezes, e a cada passagem fazer flutuar para o topo o maior elemento da sequência. Essa movimentação lembra a forma como as bolhas em um tanque de água procuram seu próprio nível, e disso vem o nome do algoritmo. ![Algorithm Visualization](https://upload.wikimedia.org/wikipedia/commons/c/c8/Bubble-sort-example-300px.gif) From 4623bb906f6ba6dee85e304cdac660dd08b79175 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 16 Dec 2020 08:07:08 +0100 Subject: [PATCH 031/264] Add k-nearest neighbors algorithm. --- README.md | 2 +- src/algorithms/ML/KNN/README.md | 23 ------- src/algorithms/ML/KNN/__test__/knn.test.js | 42 ------------ src/algorithms/ML/KNN/knn.js | 60 ----------------- src/algorithms/ml/knn/README.md | 41 ++++++++++++ src/algorithms/ml/knn/__test__/knn.test.js | 71 ++++++++++++++++++++ src/algorithms/ml/knn/kNN.js | 77 ++++++++++++++++++++++ 7 files changed, 190 insertions(+), 126 deletions(-) delete mode 100644 src/algorithms/ML/KNN/README.md delete mode 100644 src/algorithms/ML/KNN/__test__/knn.test.js delete mode 100644 src/algorithms/ML/KNN/knn.js create mode 100644 src/algorithms/ml/knn/README.md create mode 100644 src/algorithms/ml/knn/__test__/knn.test.js create mode 100644 src/algorithms/ml/knn/kNN.js diff --git a/README.md b/README.md index e108671a22..58fdab3eaa 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - simple substitution cipher * **Machine Learning** * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation) - * `B` [KNN](src/algorithms/ML/KNN) - K Nearest Neighbors + * `B` [k-NN](src/algorithms/ml/knn) - k-nearest neighbors classification algorithm * **Uncategorized** * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower) * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm diff --git a/src/algorithms/ML/KNN/README.md b/src/algorithms/ML/KNN/README.md deleted file mode 100644 index d9db66ef46..0000000000 --- a/src/algorithms/ML/KNN/README.md +++ /dev/null @@ -1,23 +0,0 @@ -# KNN Algorithm - -KNN stands for K Nearest Neighbors. KNN is a supervised Machine Learning algorithm. It's a classification algorithm, determining the class of a sample vector using a sample data. - -The idea is to calculate the similarity between two data points on the basis of a distance metric. Euclidean distance is used mostly for this task. The algorithm is as follows - - -1. Check for errors like invalid data/labels. -2. Calculate the euclidean distance of all the data points in training data with the classification point -3. Sort the distances of points along with their classes in ascending order -4. Take the initial "K" classes and find the mode to get the most similar class -5. Report the most similar class - -Here is a visualization for better understanding - - -![KNN Visualization](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png) - -Here, as we can see, the classification of unknown points will be judged by their proximity to other points. - -It is important to note that "K" is preferred to have odd values in order to break ties. Usually "K" is taken as 3 or 5. - -## References - -- [GeeksforGeeks](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png) diff --git a/src/algorithms/ML/KNN/__test__/knn.test.js b/src/algorithms/ML/KNN/__test__/knn.test.js deleted file mode 100644 index 6884598505..0000000000 --- a/src/algorithms/ML/KNN/__test__/knn.test.js +++ /dev/null @@ -1,42 +0,0 @@ -import KNN from '../knn'; - -describe('KNN', () => { - test('should throw an error on invalid data', () => { - expect(() => { - KNN(); - }).toThrowError(); - }); - test('should throw an error on invalid labels', () => { - const nolabels = () => { - KNN([[1, 1]]); - }; - expect(nolabels).toThrowError(); - }); - it('should throw an error on not giving classification vector', () => { - const noclassification = () => { - KNN([[1, 1]], [1]); - }; - expect(noclassification).toThrowError(); - }); - it('should throw an error on not giving classification vector', () => { - const inconsistent = () => { - KNN([[1, 1]], [1], [1]); - }; - expect(inconsistent).toThrowError(); - }); - it('should find the nearest neighbour', () => { - let dataX = [[1, 1], [2, 2]]; - let dataY = [1, 2]; - expect(KNN(dataX, dataY, [1, 1])).toBe(1); - - dataX = [[1, 1], [6, 2], [3, 3], [4, 5], [9, 2], [2, 4], [8, 7]]; - dataY = [1, 2, 1, 2, 1, 2, 1]; - expect(KNN(dataX, dataY, [1.25, 1.25])) - .toBe(1); - - dataX = [[1, 1], [6, 2], [3, 3], [4, 5], [9, 2], [2, 4], [8, 7]]; - dataY = [1, 2, 1, 2, 1, 2, 1]; - expect(KNN(dataX, dataY, [1.25, 1.25], 5)) - .toBe(2); - }); -}); diff --git a/src/algorithms/ML/KNN/knn.js b/src/algorithms/ML/KNN/knn.js deleted file mode 100644 index 866b6a22e9..0000000000 --- a/src/algorithms/ML/KNN/knn.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @param {object} dataY - * @param {object} dataX - * @param {object} toClassify - * @param {number} k - * @return {number} - */ -export default function KNN(dataX, dataY, toClassify, K) { - let k = -1; - - if (K === undefined) { - k = 3; - } else { - k = K; - } - - // creating function to calculate the euclidean distance between 2 vectors - function euclideanDistance(x1, x2) { - // checking errors - if (x1.length !== x2.length) { - throw new Error('inconsistency between data and classification vector.'); - } - // calculate the euclidean distance between 2 vectors and return - let totalSSE = 0; - for (let j = 0; j < x1.length; j += 1) { - totalSSE += (x1[j] - x2[j]) ** 2; - } - return Number(Math.sqrt(totalSSE).toFixed(2)); - } - - // starting algorithm - - // calculate distance from toClassify to each point for all dimensions in dataX - // store distance and point's class_index into distance_class_list - let distanceList = []; - for (let i = 0; i < dataX.length; i += 1) { - const tmStore = []; - tmStore.push(euclideanDistance(dataX[i], toClassify)); - tmStore.push(dataY[i]); - distanceList[i] = tmStore; - } - - // sort distanceList - // take initial k values, count with class index - distanceList = distanceList.sort().slice(0, k); - - // count the number of instances of each class in top k members - // with that maintain record of highest count class simultanously - const modeK = {}; - const maxm = [-1, -1]; - for (let i = 0; i < Math.min(k, distanceList.length); i += 1) { - if (distanceList[i][1] in modeK) modeK[distanceList[i][1]] += 1; - else modeK[distanceList[i][1]] = 1; - if (modeK[distanceList[i][1]] > maxm[0]) { - [maxm[0], maxm[1]] = [modeK[distanceList[i][1]], distanceList[i][1]]; - } - } - // return the class with highest count from maxm - return maxm[1]; -} diff --git a/src/algorithms/ml/knn/README.md b/src/algorithms/ml/knn/README.md new file mode 100644 index 0000000000..0d61c14fb7 --- /dev/null +++ b/src/algorithms/ml/knn/README.md @@ -0,0 +1,41 @@ +# k-Nearest Neighbors Algorithm + +The **k-nearest neighbors algorithm (k-NN)** is a supervised Machine Learning algorithm. It's a classification algorithm, determining the class of a sample vector using a sample data. + +In k-NN classification, the output is a class membership. An object is classified by a plurality vote of its neighbors, with the object being assigned to the class most common among its `k` nearest neighbors (`k` is a positive integer, typically small). If `k = 1`, then the object is simply assigned to the class of that single nearest neighbor. + +The idea is to calculate the similarity between two data points on the basis of a distance metric. [Euclidean distance](https://en.wikipedia.org/wiki/Euclidean_distance) is used mostly for this task. + +![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg) + +_Image source: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_ + +The algorithm is as follows: + +1. Check for errors like invalid data/labels. +2. Calculate the euclidean distance of all the data points in training data with the classification point +3. Sort the distances of points along with their classes in ascending order +4. Take the initial `K` classes and find the mode to get the most similar class +5. Report the most similar class + +Here is a visualization of k-NN classification for better understanding: + +![KNN Visualization 1](https://upload.wikimedia.org/wikipedia/commons/e/e7/KnnClassification.svg) + +_Image source: [Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)_ + +The test sample (green dot) should be classified either to blue squares or to red triangles. If `k = 3` (solid line circle) it is assigned to the red triangles because there are `2` triangles and only `1` square inside the inner circle. If `k = 5` (dashed line circle) it is assigned to the blue squares (`3` squares vs. `2` triangles inside the outer circle). + +Another k-NN classification example: + +![KNN Visualization 2](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png) + +_Image source: [GeeksForGeeks](https://media.geeksforgeeks.org/wp-content/uploads/graph2-2.png)_ + +Here, as we can see, the classification of unknown points will be judged by their proximity to other points. + +It is important to note that `K` is preferred to have odd values in order to break ties. Usually `K` is taken as `3` or `5`. + +## References + +- [k-nearest neighbors algorithm on Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm) diff --git a/src/algorithms/ml/knn/__test__/knn.test.js b/src/algorithms/ml/knn/__test__/knn.test.js new file mode 100644 index 0000000000..ccd69cd706 --- /dev/null +++ b/src/algorithms/ml/knn/__test__/knn.test.js @@ -0,0 +1,71 @@ +import kNN from '../kNN'; + +describe('kNN', () => { + it('should throw an error on invalid data', () => { + expect(() => { + kNN(); + }).toThrowError('Either dataSet or labels or toClassify were not set'); + }); + + it('should throw an error on invalid labels', () => { + const noLabels = () => { + kNN([[1, 1]]); + }; + expect(noLabels).toThrowError('Either dataSet or labels or toClassify were not set'); + }); + + it('should throw an error on not giving classification vector', () => { + const noClassification = () => { + kNN([[1, 1]], [1]); + }; + expect(noClassification).toThrowError('Either dataSet or labels or toClassify were not set'); + }); + + it('should throw an error on not giving classification vector', () => { + const inconsistent = () => { + kNN([[1, 1]], [1], [1]); + }; + expect(inconsistent).toThrowError('Inconsistent vector lengths'); + }); + + it('should find the nearest neighbour', () => { + let dataSet; + let labels; + let toClassify; + let expectedClass; + + dataSet = [[1, 1], [2, 2]]; + labels = [1, 2]; + toClassify = [1, 1]; + expectedClass = 1; + expect(kNN(dataSet, labels, toClassify)).toBe(expectedClass); + + dataSet = [[1, 1], [6, 2], [3, 3], [4, 5], [9, 2], [2, 4], [8, 7]]; + labels = [1, 2, 1, 2, 1, 2, 1]; + toClassify = [1.25, 1.25]; + expectedClass = 1; + expect(kNN(dataSet, labels, toClassify)).toBe(expectedClass); + + dataSet = [[1, 1], [6, 2], [3, 3], [4, 5], [9, 2], [2, 4], [8, 7]]; + labels = [1, 2, 1, 2, 1, 2, 1]; + toClassify = [1.25, 1.25]; + expectedClass = 2; + expect(kNN(dataSet, labels, toClassify, 5)).toBe(expectedClass); + }); + + it('should find the nearest neighbour with equal distances', () => { + const dataSet = [[0, 0], [1, 1], [0, 2]]; + const labels = [1, 3, 3]; + const toClassify = [0, 1]; + const expectedClass = 3; + expect(kNN(dataSet, labels, toClassify)).toBe(expectedClass); + }); + + it('should find the nearest neighbour in 3D space', () => { + const dataSet = [[0, 0, 0], [0, 1, 1], [0, 0, 2]]; + const labels = [1, 3, 3]; + const toClassify = [0, 0, 1]; + const expectedClass = 3; + expect(kNN(dataSet, labels, toClassify)).toBe(expectedClass); + }); +}); diff --git a/src/algorithms/ml/knn/kNN.js b/src/algorithms/ml/knn/kNN.js new file mode 100644 index 0000000000..24709af6f2 --- /dev/null +++ b/src/algorithms/ml/knn/kNN.js @@ -0,0 +1,77 @@ +/** + * Calculates calculate the euclidean distance between 2 vectors. + * + * @param {number[]} x1 + * @param {number[]} x2 + * @returns {number} + */ +function euclideanDistance(x1, x2) { + // Checking for errors. + if (x1.length !== x2.length) { + throw new Error('Inconsistent vector lengths'); + } + // Calculate the euclidean distance between 2 vectors and return. + let squaresTotal = 0; + for (let i = 0; i < x1.length; i += 1) { + squaresTotal += (x1[i] - x2[i]) ** 2; + } + return Number(Math.sqrt(squaresTotal).toFixed(2)); +} + +/** + * Classifies the point in space based on k-nearest neighbors algorithm. + * + * @param {number[][]} dataSet - array of data points, i.e. [[0, 1], [3, 4], [5, 7]] + * @param {number[]} labels - array of classes (labels), i.e. [1, 1, 2] + * @param {number[]} toClassify - the point in space that needs to be classified, i.e. [5, 4] + * @param {number} k - number of nearest neighbors which will be taken into account (preferably odd) + * @return {number} - the class of the point + */ +export default function kNN( + dataSet, + labels, + toClassify, + k = 3, +) { + if (!dataSet || !labels || !toClassify) { + throw new Error('Either dataSet or labels or toClassify were not set'); + } + + // Calculate distance from toClassify to each point for all dimensions in dataSet. + // Store distance and point's label into distances list. + const distances = []; + for (let i = 0; i < dataSet.length; i += 1) { + distances.push({ + dist: euclideanDistance(dataSet[i], toClassify), + label: labels[i], + }); + } + + // Sort distances list (from closer point to further ones). + // Take initial k values, count with class index + const kNearest = distances.sort((a, b) => { + if (a.dist === b.dist) { + return 0; + } + return a.dist < b.dist ? -1 : 1; + }).slice(0, k); + + // Count the number of instances of each class in top k members. + const labelsCounter = {}; + let topClass = 0; + let topClassCount = 0; + for (let i = 0; i < kNearest.length; i += 1) { + if (kNearest[i].label in labelsCounter) { + labelsCounter[kNearest[i].label] += 1; + } else { + labelsCounter[kNearest[i].label] = 1; + } + if (labelsCounter[kNearest[i].label] > topClassCount) { + topClassCount = labelsCounter[kNearest[i].label]; + topClass = kNearest[i].label; + } + } + + // Return the class with highest count. + return topClass; +} From e105460cd6c868c2a38f7a4c8416c34b4eb6ea83 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 16 Dec 2020 17:56:57 +0100 Subject: [PATCH 032/264] Update CI badge to point to the master branch status. --- README.es-ES.md | 2 +- README.fr-FR.md | 2 +- README.it-IT.md | 2 +- README.ja-JP.md | 2 +- README.ko-KR.md | 2 +- README.md | 2 +- README.pl-PL.md | 2 +- README.pt-BR.md | 2 +- README.ru-RU.md | 2 +- README.tr-TR.md | 2 +- README.zh-CN.md | 2 +- README.zh-TW.md | 2 +- 12 files changed, 12 insertions(+), 12 deletions(-) diff --git a/README.es-ES.md b/README.es-ES.md index 81a3189259..b6337a1c3d 100644 --- a/README.es-ES.md +++ b/README.es-ES.md @@ -1,6 +1,6 @@ # Algoritmos y Estructuras de Datos en JavaScript -[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) Este repositorio contiene ejemplos basados en JavaScript de muchos diff --git a/README.fr-FR.md b/README.fr-FR.md index 440a854cd3..7b3705544b 100644 --- a/README.fr-FR.md +++ b/README.fr-FR.md @@ -1,6 +1,6 @@ # Algorithmes et Structures de Données en JavaScript -[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) Ce dépôt contient des exemples d'implémentation en JavaScript de plusieurs diff --git a/README.it-IT.md b/README.it-IT.md index 57c054df1e..9598324058 100644 --- a/README.it-IT.md +++ b/README.it-IT.md @@ -1,6 +1,6 @@ # Algoritmi e Strutture Dati in Javascript -[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) Questa repository contiene esempi in Javascript dei più popolari algoritmi e strutture dati . diff --git a/README.ja-JP.md b/README.ja-JP.md index 7ec49e4eeb..93321556c4 100644 --- a/README.ja-JP.md +++ b/README.ja-JP.md @@ -1,6 +1,6 @@ # JavaScriptアルゴリズムとデータ構造 -[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) このリポジトリには、JavaScriptベースの一般的なアルゴリズムとデータ構造に関する多数のサンプルが含まれています。 diff --git a/README.ko-KR.md b/README.ko-KR.md index 8a31e81101..0fa189d106 100644 --- a/README.ko-KR.md +++ b/README.ko-KR.md @@ -1,6 +1,6 @@ # JavaScript 알고리즘 및 자료 구조 -[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) 이 저장소에는 많이 알려진 알고리즘 및 자료 구조의 Javascript 기반 예제를 담고 있습니다. diff --git a/README.md b/README.md index 58fdab3eaa..e805a7a3cc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # JavaScript Algorithms and Data Structures -[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) This repository contains JavaScript based examples of many diff --git a/README.pl-PL.md b/README.pl-PL.md index 98fe798913..d1ad0ec224 100644 --- a/README.pl-PL.md +++ b/README.pl-PL.md @@ -1,6 +1,6 @@ # JavaScript Algorytmy i Struktury Danych -[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) To repozytorium zawiera wiele przykładów JavaScript opartych na diff --git a/README.pt-BR.md b/README.pt-BR.md index e95477ed15..66894582e1 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -1,6 +1,6 @@ # Estrutura de Dados e Algoritmos em JavaScript -[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) Este repositório contém exemplos baseados em JavaScript de muitos diff --git a/README.ru-RU.md b/README.ru-RU.md index e1bdb49454..e85446d31f 100644 --- a/README.ru-RU.md +++ b/README.ru-RU.md @@ -1,6 +1,6 @@ # Алгоритмы и структуры данных на JavaScript -[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) В этом репозитории содержатся базовые JavaScript-примеры многих популярных алгоритмов и структур данных. diff --git a/README.tr-TR.md b/README.tr-TR.md index 7d2cc7919f..c65061e454 100644 --- a/README.tr-TR.md +++ b/README.tr-TR.md @@ -1,6 +1,6 @@ # JavaScript Algoritmalar ve Veri Yapıları -[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) Bu repository JavaScript'e ait popüler diff --git a/README.zh-CN.md b/README.zh-CN.md index 064c0dbe11..05f580817f 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,6 +1,6 @@ # JavaScript 算法与数据结构 -[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) 本仓库包含了多种基于 JavaScript 的算法与数据结构。 diff --git a/README.zh-TW.md b/README.zh-TW.md index bb98d2a140..1a091720bb 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -1,6 +1,6 @@ # JavaScript 演算法與資料結構 -[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) 這個知識庫包含許多 JavaScript 的資料結構與演算法的基礎範例。 From 9929ab7fc14fae9e5d685f689583939895ab68a8 Mon Sep 17 00:00:00 2001 From: Sherlyn <31661914+rollingcomma@users.noreply.github.com> Date: Wed, 16 Dec 2020 22:26:21 -0800 Subject: [PATCH 033/264] add hillCipher at cryptography section (#424) * add hillCipher.js and its test case first commit * add README.md * update style Co-authored-by: Oleksii Trekhleb --- .../cryptography/hillCipher/README.md | 27 ++++++++ .../hillCipher/_test_/hillCipher.test.js | 25 +++++++ .../cryptography/hillCipher/hillCipher.js | 68 +++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 src/algorithms/cryptography/hillCipher/README.md create mode 100644 src/algorithms/cryptography/hillCipher/_test_/hillCipher.test.js create mode 100644 src/algorithms/cryptography/hillCipher/hillCipher.js diff --git a/src/algorithms/cryptography/hillCipher/README.md b/src/algorithms/cryptography/hillCipher/README.md new file mode 100644 index 0000000000..99e73fa1fd --- /dev/null +++ b/src/algorithms/cryptography/hillCipher/README.md @@ -0,0 +1,27 @@ +# Hill Cipher + +* The Hill cipher is a polygraphic substitution cipher based on linear algebra. +Each letter is represented by a number modulo 26. + +* Encryption: to encrypt a message, each block of n letters (considered as an n-component vector) is multiplied by an invertible n × n matrix, against modulus 26. +Consider the message 'ACT', and the key below (or GYB/NQK/URP in letters): + | 6 24 1 | + | 13 16 10| + | 20 17 15| +The message is the vector: + | 0 | + | 2 | + | 19 | +Thus the enciphered vector is given by + | 6 24 1 | | 0 | | 67 | | 15 | + | 13 16 10| | 2 | = | 222 | ≡ | 14 | (mod 26) + | 20 17 15| | 19 | | 319 | | 7 | +which corresponds to a ciphertext of 'POH'. + +* Decryption: to decrypt the message, each block is multiplied by the inverse of the matrix used for encryption. + + +## Reference +- [Wikipedia] https://en.wikipedia.org/wiki/Hill_cipher +- [GeeksforGeeks]https://www.geeksforgeeks.org/hill-cipher/ + diff --git a/src/algorithms/cryptography/hillCipher/_test_/hillCipher.test.js b/src/algorithms/cryptography/hillCipher/_test_/hillCipher.test.js new file mode 100644 index 0000000000..7c50f91361 --- /dev/null +++ b/src/algorithms/cryptography/hillCipher/_test_/hillCipher.test.js @@ -0,0 +1,25 @@ +import hillCipherEncrypt from '../hillCipher'; + +describe('hillCipher', () => { + it('should throw an error when the length of the keyString does not equal to the power of length of the message ', () => { + const invalidLenghOfkeyString = () => { + hillCipherEncrypt('hello', 'helloworld'); + }; + + expect(invalidLenghOfkeyString).toThrowError(); + }); + it('should throw an error when message or keyString contains none letter character', () => { + const invalidCharacterInMessage = () => { + hillCipherEncrypt('hell3', 'helloworld'); + }; + const invalidCharacterInKeyString = () => { + hillCipherEncrypt('hello', 'hel12world'); + }; + expect(invalidCharacterInMessage).toThrowError(); + expect(invalidCharacterInKeyString).toThrowError(); + }); + it('should encrypt passed message using Hill Cipher', () => { + expect(hillCipherEncrypt('ACT', 'GYBNQKURP')).toBe('POH'); + expect(hillCipherEncrypt('GFG', 'HILLMAGIC')).toBe('SWK'); + }); +}); diff --git a/src/algorithms/cryptography/hillCipher/hillCipher.js b/src/algorithms/cryptography/hillCipher/hillCipher.js new file mode 100644 index 0000000000..ac497a41a0 --- /dev/null +++ b/src/algorithms/cryptography/hillCipher/hillCipher.js @@ -0,0 +1,68 @@ + +/** + * generate key matrix from given keyString + * + * @param {integer} length + * @param {string} keyString + * @return {Array[][]} keyMatrix + */ +const generateKeyMatrix = (length, keyString) => { + const keyMatrix = []; + let keyStringIndex = 0; + for (let i = 0; i < length; i += 1) { + const keyMatrixRow = []; + for (let j = 0; j < length; j += 1) { + keyMatrixRow.push((keyString.codePointAt(keyStringIndex)) % 65); + keyStringIndex += 1; + } + keyMatrix.push(keyMatrixRow); + } + return keyMatrix; +}; + +/** + * generate message vector from given message + * + * @param {*} message + * @return {Array} messageVector + */ +const generateMessageVector = (message) => { + const messageVector = []; + for (let i = 0; i < message.length; i += 1) { + messageVector.push(message.codePointAt(i) % 65); + } + return messageVector; +}; + +/** + * validate data and encrypt message from given message and keyString + * + * @param {string} message plaintext + * @param {string} keyString + * @return {string} cipherString + * + */ + +export default function hillCipherEncrypt(message, keyString) { + const length = keyString.length ** (0.5); + // keyString.length must equal to square of message.length + if (!Number.isInteger(length) && length !== message.length) { + throw new Error('invalid key string length'); + } + // keyString and messange can only contain letters + if (!(/^[a-zA-Z]+$/.test(message)) || !(/^[A-Za-z]+$/.test(keyString))) { + throw new Error('messange and key string can only contain letters'); + } + + const keyMatrix = generateKeyMatrix(length, keyString); + const messageVector = generateMessageVector(message); + let ciperString = ''; + for (let row = 0; row < length; row += 1) { + let item = 0; + for (let column = 0; column < length; column += 1) { + item += keyMatrix[row][column] * messageVector[column]; + } + ciperString += String.fromCharCode((item % 26) + 65); + } + return ciperString; +} From d899ae1484262999273d7a86c440a2f7e10da850 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Thu, 17 Dec 2020 08:07:26 +0100 Subject: [PATCH 034/264] Add more details and example to Hill cipher README. --- .../cryptography/hill-cipher/README.md | 96 +++++++++++++++++++ .../_test_/hillCipher.test.js | 0 .../{hillCipher => hill-cipher}/hillCipher.js | 0 .../cryptography/hillCipher/README.md | 27 ------ 4 files changed, 96 insertions(+), 27 deletions(-) create mode 100644 src/algorithms/cryptography/hill-cipher/README.md rename src/algorithms/cryptography/{hillCipher => hill-cipher}/_test_/hillCipher.test.js (100%) rename src/algorithms/cryptography/{hillCipher => hill-cipher}/hillCipher.js (100%) delete mode 100644 src/algorithms/cryptography/hillCipher/README.md diff --git a/src/algorithms/cryptography/hill-cipher/README.md b/src/algorithms/cryptography/hill-cipher/README.md new file mode 100644 index 0000000000..bf496e2be9 --- /dev/null +++ b/src/algorithms/cryptography/hill-cipher/README.md @@ -0,0 +1,96 @@ +# Hill Cipher + +The **Hill cipher** is a [polygraphic substitution](https://en.wikipedia.org/wiki/Polygraphic_substitution) cipher based on linear algebra. + +Each letter is represented by a number [modulo](https://en.wikipedia.org/wiki/Modular_arithmetic) `26`. Though this is not an essential feature of the cipher, this simple scheme is often used: + +| **Letter** | A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W | X | Y | Z | +| ------ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| **Number** | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | + +## Encryption + +To encrypt a message, each block of `n` letters (considered as an `n`-component vector) is multiplied by an invertible `n × n` matrix, against modulus `26`. + +The matrix used for encryption is the _cipher key_, and it should be chosen randomly from the set of invertible `n × n` matrices (modulo `26`). The cipher can, of course, be adapted to an alphabet with any number of letters; all arithmetic just needs to be done modulo the number of letters instead of modulo `26`. + +Consider the message `ACT`, and the key below (or `GYB/NQK/URP` in letters): + +``` +| 6 24 1 | +| 13 16 10 | +| 20 17 15 | +``` + +Since `A` is`0`, `C` is `2` and `T` is `19`, the message is the vector: + +``` +| 0 | +| 2 | +| 19 | +``` + +Thus, the enciphered vector is given by: + +``` +| 6 24 1 | | 0 | | 67 | | 15 | +| 13 16 10 | | 2 | = | 222 | ≡ | 14 | (mod 26) +| 20 17 15 | | 19 | | 319 | | 7 | +``` + +which corresponds to a ciphertext of `POH`. + +Now, suppose that our message is instead `CAT` (notice how we're using the same letters as in `ACT` here), or: + +``` +| 2 | +| 0 | +| 19 | +``` + +This time, the enciphered vector is given by: + +``` +| 6 24 1 | | 2 | | 31 | | 5 | +| 13 16 10 | | 0 | = | 216 | ≡ | 8 | (mod 26) +| 20 17 15 | | 19 | | 325 | | 13 | +``` + +which corresponds to a ciphertext of `FIN`. Every letter has changed. + +## Decryption + +To decrypt the message, each block is multiplied by the inverse of the matrix used for encryption. We turn the ciphertext back into a vector, then simply multiply by the inverse matrix of the key matrix (`IFK/VIV/VMI` in letters). (See [matrix inversion](https://en.wikipedia.org/wiki/Matrix_inversion) for methods to calculate the inverse matrix.) We find that, modulo 26, the inverse of the matrix used in the previous example is: + +``` + -1 +| 6 24 1 | | 8 5 10 | +| 13 16 10 | (mod 26) ≡ | 21 8 21 | +| 20 17 15 | | 21 12 8 | +``` + +Taking the previous example ciphertext of `POH`, we get: + +``` +| 8 5 10 | | 15 | | 260 | | 0 | +| 21 8 21 | | 14 | = | 574 | ≡ | 2 | (mod 26) +| 21 12 8 | | 7 | | 539 | | 19 | +``` + +which gets us back to `ACT`, as expected. + +## Defining the encrypting matrix + +Two complications exist in picking the encrypting matrix: + +1. Not all matrices have an inverse. The matrix will have an inverse if and only if its [determinant](https://en.wikipedia.org/wiki/Determinant) is not zero. +2. The determinant of the encrypting matrix must not have any common factors with the modular base. + +Thus, if we work modulo `26` as above, the determinant must be nonzero, and must not be divisible by `2` or `13`. If the determinant is `0`, or has common factors with the modular base, then the matrix cannot be used in the Hill cipher, and another matrix must be chosen (otherwise it will not be possible to decrypt). Fortunately, matrices which satisfy the conditions to be used in the Hill cipher are fairly common. + +## References + +- [Hill cipher on Wikipedia](https://en.wikipedia.org/wiki/Hill_cipher) +- [Matrix inversion on MathIsFun](https://www.mathsisfun.com/algebra/matrix-inverse.html) +- [GeeksForGeeks](https://www.geeksforgeeks.org/hill-cipher/) + diff --git a/src/algorithms/cryptography/hillCipher/_test_/hillCipher.test.js b/src/algorithms/cryptography/hill-cipher/_test_/hillCipher.test.js similarity index 100% rename from src/algorithms/cryptography/hillCipher/_test_/hillCipher.test.js rename to src/algorithms/cryptography/hill-cipher/_test_/hillCipher.test.js diff --git a/src/algorithms/cryptography/hillCipher/hillCipher.js b/src/algorithms/cryptography/hill-cipher/hillCipher.js similarity index 100% rename from src/algorithms/cryptography/hillCipher/hillCipher.js rename to src/algorithms/cryptography/hill-cipher/hillCipher.js diff --git a/src/algorithms/cryptography/hillCipher/README.md b/src/algorithms/cryptography/hillCipher/README.md deleted file mode 100644 index 99e73fa1fd..0000000000 --- a/src/algorithms/cryptography/hillCipher/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Hill Cipher - -* The Hill cipher is a polygraphic substitution cipher based on linear algebra. -Each letter is represented by a number modulo 26. - -* Encryption: to encrypt a message, each block of n letters (considered as an n-component vector) is multiplied by an invertible n × n matrix, against modulus 26. -Consider the message 'ACT', and the key below (or GYB/NQK/URP in letters): - | 6 24 1 | - | 13 16 10| - | 20 17 15| -The message is the vector: - | 0 | - | 2 | - | 19 | -Thus the enciphered vector is given by - | 6 24 1 | | 0 | | 67 | | 15 | - | 13 16 10| | 2 | = | 222 | ≡ | 14 | (mod 26) - | 20 17 15| | 19 | | 319 | | 7 | -which corresponds to a ciphertext of 'POH'. - -* Decryption: to decrypt the message, each block is multiplied by the inverse of the matrix used for encryption. - - -## Reference -- [Wikipedia] https://en.wikipedia.org/wiki/Hill_cipher -- [GeeksforGeeks]https://www.geeksforgeeks.org/hill-cipher/ - From 52fbc8a80f67c420b2c50bad71351bc5732e4a04 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Thu, 17 Dec 2020 08:58:26 +0100 Subject: [PATCH 035/264] Add Hill Cipher. --- README.md | 1 + .../hill-cipher/_test_/hillCipher.test.js | 39 +++++++--- .../cryptography/hill-cipher/hillCipher.js | 72 +++++++++++-------- 3 files changed, 75 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index e805a7a3cc..b470aeeffd 100644 --- a/README.md +++ b/README.md @@ -141,6 +141,7 @@ a set of rules that precisely define a sequence of operations. * **Cryptography** * `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - rolling hash function based on polynomial * `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - simple substitution cipher + * `B` [Hill Cipher](src/algorithms/cryptography/hill-cipher) - polygraphic substitution cipher * **Machine Learning** * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation) * `B` [k-NN](src/algorithms/ml/knn) - k-nearest neighbors classification algorithm diff --git a/src/algorithms/cryptography/hill-cipher/_test_/hillCipher.test.js b/src/algorithms/cryptography/hill-cipher/_test_/hillCipher.test.js index 7c50f91361..f540ae9ff1 100644 --- a/src/algorithms/cryptography/hill-cipher/_test_/hillCipher.test.js +++ b/src/algorithms/cryptography/hill-cipher/_test_/hillCipher.test.js @@ -1,13 +1,10 @@ -import hillCipherEncrypt from '../hillCipher'; +import { hillCipherEncrypt, hillCipherDecrypt } from '../hillCipher'; describe('hillCipher', () => { - it('should throw an error when the length of the keyString does not equal to the power of length of the message ', () => { - const invalidLenghOfkeyString = () => { - hillCipherEncrypt('hello', 'helloworld'); - }; - - expect(invalidLenghOfkeyString).toThrowError(); + it('should throw an exception when trying to decipher', () => { + expect(hillCipherDecrypt).toThrowError('This method is not implemented yet'); }); + it('should throw an error when message or keyString contains none letter character', () => { const invalidCharacterInMessage = () => { hillCipherEncrypt('hell3', 'helloworld'); @@ -15,11 +12,35 @@ describe('hillCipher', () => { const invalidCharacterInKeyString = () => { hillCipherEncrypt('hello', 'hel12world'); }; - expect(invalidCharacterInMessage).toThrowError(); - expect(invalidCharacterInKeyString).toThrowError(); + expect(invalidCharacterInMessage).toThrowError( + 'The message and key string can only contain letters', + ); + expect(invalidCharacterInKeyString).toThrowError( + 'The message and key string can only contain letters', + ); + }); + + it('should throw an error when the length of the keyString has a square root which is not integer', () => { + const invalidLengthOfKeyString = () => { + hillCipherEncrypt('ab', 'ab'); + }; + expect(invalidLengthOfKeyString).toThrowError( + 'Invalid key string length. The square root of the key string must be an integer', + ); }); + + it('should throw an error when the length of the keyString does not equal to the power of length of the message', () => { + const invalidLengthOfKeyString = () => { + hillCipherEncrypt('ab', 'aaabbbccc'); + }; + expect(invalidLengthOfKeyString).toThrowError( + 'Invalid key string length. The key length must be a square of message length', + ); + }); + it('should encrypt passed message using Hill Cipher', () => { expect(hillCipherEncrypt('ACT', 'GYBNQKURP')).toBe('POH'); + expect(hillCipherEncrypt('CAT', 'GYBNQKURP')).toBe('FIN'); expect(hillCipherEncrypt('GFG', 'HILLMAGIC')).toBe('SWK'); }); }); diff --git a/src/algorithms/cryptography/hill-cipher/hillCipher.js b/src/algorithms/cryptography/hill-cipher/hillCipher.js index ac497a41a0..f776db6224 100644 --- a/src/algorithms/cryptography/hill-cipher/hillCipher.js +++ b/src/algorithms/cryptography/hill-cipher/hillCipher.js @@ -1,18 +1,28 @@ +// The code of an 'A' character (equals to 65). +const alphabetCodeShift = 'A'.codePointAt(0); +const englishAlphabetSize = 26; /** - * generate key matrix from given keyString + * Generates key matrix from given keyString. * - * @param {integer} length - * @param {string} keyString - * @return {Array[][]} keyMatrix + * @param {string} keyString - a string to build a key matrix (must be of matrixSize^2 length). + * @return {number[][]} keyMatrix */ -const generateKeyMatrix = (length, keyString) => { +const generateKeyMatrix = (keyString) => { + const matrixSize = Math.sqrt(keyString.length); + if (!Number.isInteger(matrixSize)) { + throw new Error( + 'Invalid key string length. The square root of the key string must be an integer', + ); + } const keyMatrix = []; let keyStringIndex = 0; - for (let i = 0; i < length; i += 1) { + for (let i = 0; i < matrixSize; i += 1) { const keyMatrixRow = []; - for (let j = 0; j < length; j += 1) { - keyMatrixRow.push((keyString.codePointAt(keyStringIndex)) % 65); + for (let j = 0; j < matrixSize; j += 1) { + // A → 0, B → 1, ..., a → 32, b → 33, ... + const charCodeShifted = (keyString.codePointAt(keyStringIndex)) % alphabetCodeShift; + keyMatrixRow.push(charCodeShifted); keyStringIndex += 1; } keyMatrix.push(keyMatrixRow); @@ -21,48 +31,54 @@ const generateKeyMatrix = (length, keyString) => { }; /** - * generate message vector from given message + * Generates a message vector from a given message. * - * @param {*} message - * @return {Array} messageVector + * @param {string} message - the message to encrypt. + * @return {number[]} messageVector */ const generateMessageVector = (message) => { const messageVector = []; for (let i = 0; i < message.length; i += 1) { - messageVector.push(message.codePointAt(i) % 65); + messageVector.push(message.codePointAt(i) % alphabetCodeShift); } return messageVector; }; /** - * validate data and encrypt message from given message and keyString + * Encrypts the given message using Hill Cipher. * * @param {string} message plaintext * @param {string} keyString * @return {string} cipherString - * */ +export function hillCipherEncrypt(message, keyString) { + // The keyString and message can only contain letters. + const onlyLettersRegExp = /^[a-zA-Z]+$/; + if (!onlyLettersRegExp.test(message) || !onlyLettersRegExp.test(keyString)) { + throw new Error('The message and key string can only contain letters'); + } + + const keyMatrix = generateKeyMatrix(keyString); -export default function hillCipherEncrypt(message, keyString) { - const length = keyString.length ** (0.5); // keyString.length must equal to square of message.length - if (!Number.isInteger(length) && length !== message.length) { - throw new Error('invalid key string length'); - } - // keyString and messange can only contain letters - if (!(/^[a-zA-Z]+$/.test(message)) || !(/^[A-Za-z]+$/.test(keyString))) { - throw new Error('messange and key string can only contain letters'); + if (keyMatrix.length !== message.length) { + throw new Error('Invalid key string length. The key length must be a square of message length'); } - const keyMatrix = generateKeyMatrix(length, keyString); const messageVector = generateMessageVector(message); - let ciperString = ''; - for (let row = 0; row < length; row += 1) { + let cipherString = ''; + for (let row = 0; row < keyMatrix.length; row += 1) { let item = 0; - for (let column = 0; column < length; column += 1) { + for (let column = 0; column < keyMatrix.length; column += 1) { item += keyMatrix[row][column] * messageVector[column]; } - ciperString += String.fromCharCode((item % 26) + 65); + cipherString += String.fromCharCode((item % englishAlphabetSize) + alphabetCodeShift); } - return ciperString; + + return cipherString; } + +// @TODO: Implement this method. +export const hillCipherDecrypt = () => { + throw new Error('This method is not implemented yet'); +}; From 38b2b977cd8804e52c1f85ebe7f8a28d407f9b8c Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Thu, 17 Dec 2020 09:27:32 +0100 Subject: [PATCH 036/264] Add Hill Cipher. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b470aeeffd..784dcd7ca6 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ a set of rules that precisely define a sequence of operations. * **Cryptography** * `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - rolling hash function based on polynomial * `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - simple substitution cipher - * `B` [Hill Cipher](src/algorithms/cryptography/hill-cipher) - polygraphic substitution cipher + * `B` [Hill Cipher](src/algorithms/cryptography/hill-cipher) - substitution cipher based on linear algebra * **Machine Learning** * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation) * `B` [k-NN](src/algorithms/ml/knn) - k-nearest neighbors classification algorithm From 07c21083d61ff7784b15158430056fa843cdb635 Mon Sep 17 00:00:00 2001 From: Oleg Maslov Date: Thu, 17 Dec 2020 11:36:00 +0300 Subject: [PATCH 037/264] Add missing LinkedList tests (#151) Co-authored-by: Oleksii Trekhleb --- .../linked-list/__test__/LinkedList.test.js | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/data-structures/linked-list/__test__/LinkedList.test.js b/src/data-structures/linked-list/__test__/LinkedList.test.js index f80187a730..bce06f727e 100644 --- a/src/data-structures/linked-list/__test__/LinkedList.test.js +++ b/src/data-structures/linked-list/__test__/LinkedList.test.js @@ -218,6 +218,29 @@ describe('LinkedList', () => { expect(linkedList.find({ value: 2, customValue: 'test5' })).toBeNull(); }); + it('should find preferring callback over compare function', () => { + const greaterThan = (value, compareTo) => (value > compareTo ? 0 : 1); + + const linkedList = new LinkedList(greaterThan); + linkedList.fromArray([1, 2, 3, 4, 5]); + + let node = linkedList.find({ value: 3 }); + expect(node.value).toBe(4); + + node = linkedList.find({ callback: value => value < 3 }); + expect(node.value).toBe(1); + }); + + it('should convert to array', () => { + const linkedList = new LinkedList(); + + linkedList.append(1); + linkedList.append(2); + linkedList.append(3); + + expect(linkedList.toArray().join(',')).toBe('1,2,3'); + }); + it('should reverse linked list', () => { const linkedList = new LinkedList(); From 431560a4e50040e9927e60bece01f0276e2d1683 Mon Sep 17 00:00:00 2001 From: Askhat Arslanov Date: Thu, 17 Dec 2020 11:40:05 +0300 Subject: [PATCH 038/264] Translate Linked List Traversal to Russian (#283) Co-authored-by: Askhat --- .../linked-list/traversal/README.md | 5 ++++- .../linked-list/traversal/README.ru-RU.md | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 src/algorithms/linked-list/traversal/README.ru-RU.md diff --git a/src/algorithms/linked-list/traversal/README.md b/src/algorithms/linked-list/traversal/README.md index 25609518f8..2416323dd8 100644 --- a/src/algorithms/linked-list/traversal/README.md +++ b/src/algorithms/linked-list/traversal/README.md @@ -1,8 +1,11 @@ # Linked List Traversal +_Read this in other languages:_ +[_Русский_](README.ru-RU.md) + The task is to traverse the given linked list in straight order. -For example for the following linked list: +For example for the following linked list: ![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) diff --git a/src/algorithms/linked-list/traversal/README.ru-RU.md b/src/algorithms/linked-list/traversal/README.ru-RU.md new file mode 100644 index 0000000000..e4587bf6af --- /dev/null +++ b/src/algorithms/linked-list/traversal/README.ru-RU.md @@ -0,0 +1,19 @@ +# Обход связного списка + +Задача состоит в том, чтобы обойти связный список в прямом порядке. + +Например, для следующего связного списка: + +![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) + +Порядок обхода будет такой: + +```text +12 → 99 → 37 +``` + +Временная сложность - `O(n)`, потому что мы посещаем каждый узел только один раз. + +## Ссылки + +- [Wikipedia](https://ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%8F%D0%B7%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D0%B8%D1%81%D0%BE%D0%BA) From 536f75a52fde251d98bd52bdc764e79694acdfb3 Mon Sep 17 00:00:00 2001 From: lvzhenbang Date: Thu, 17 Dec 2020 16:48:19 +0800 Subject: [PATCH 039/264] update desc (#371) * update desc * text error --- src/data-structures/queue/README.zh-CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data-structures/queue/README.zh-CN.md b/src/data-structures/queue/README.zh-CN.md index df8d38c75d..d61a2c7dac 100644 --- a/src/data-structures/queue/README.zh-CN.md +++ b/src/data-structures/queue/README.zh-CN.md @@ -2,7 +2,7 @@ 在计算机科学中, 一个 **队列(queue)** 是一种特殊类型的抽象数据类型或集合。集合中的实体按顺序保存。 -队列基本操作有两种: 向队列的后端位置添加实体,称为入队,并从队列的前端位置移除实体,称为出队。 +队列基本操作有两种:入队和出队。从队列的后端位置添加实体,称为入队;从队列的前端位置移除实体,称为出队。 队列中元素先进先出 FIFO (first in, first out)的示意 From d87502b5fd155b116ce0bc17b18e6b43ed3f27aa Mon Sep 17 00:00:00 2001 From: Alexander Belov Date: Thu, 17 Dec 2020 11:48:43 +0300 Subject: [PATCH 040/264] Update README.md (#385) Co-authored-by: Oleksii Trekhleb From de1cc0b0479b5e7dd2e28d2487eea6d3d207e5e4 Mon Sep 17 00:00:00 2001 From: Luan Caldas Date: Thu, 17 Dec 2020 05:49:11 -0300 Subject: [PATCH 041/264] Translate pt-BR (#386) Co-authored-by: Oleksii Trekhleb --- README.pt-BR.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.pt-BR.md b/README.pt-BR.md index 66894582e1..17899af1d9 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -35,7 +35,7 @@ os dados. * `B` [Lista Encadeada (Linked List)](src/data-structures/linked-list/README.pt-BR.md) * `B` [Lista Duplamente Ligada (Doubly Linked List)](src/data-structures/doubly-linked-list/README.pt-BR.md) * `B` [Fila (Queue)](src/data-structures/queue/README.pt-BR.md) -* `B` [Stack](src/data-structures/stack/README.pt-BR.md) +* `B` [Pilha (Stack)](src/data-structures/stack/README.pt-BR.md) * `B` [Tabela de Hash (Hash Table)](src/data-structures/hash-table/README.pt-BR.md) * `B` [Heap](src/data-structures/heap/README.pt-BR.md) * `B` [Fila de Prioridade (Priority Queue)](src/data-structures/priority-queue/README.pt-BR.md) @@ -46,7 +46,7 @@ os dados. * `A` [Árvore Vermelha-Preta (Red-Black Tree)](src/data-structures/tree/red-black-tree/README.pt-BR.md) * `A` [Árvore de Segmento (Segment Tree)](src/data-structures/tree/segment-tree/README.pt-BR.md) - com exemplos de consultas min / max / sum range * `A` [Árvore Fenwick (Fenwick Tree)](src/data-structures/tree/fenwick-tree/README.pt-BR.md) (Árvore indexada binária) -* `A` [Gráfico (Graph)](src/data-structures/graph/README.pt-BR.md) (ambos dirigidos e não direcionados) +* `A` [Grafo (Graph)](src/data-structures/graph/README.pt-BR.md) (ambos dirigidos e não direcionados) * `A` [Conjunto Disjuntor (Disjoint Set)](src/data-structures/disjoint-set/README.pt-BR.md) * `A` [Filtro Bloom (Bloom Filter)](src/data-structures/bloom-filter/README.pt-BR.md) @@ -110,7 +110,7 @@ um conjunto de regras que define precisamente uma sequência de operações. * **Arvóres** * `B` [Depth-First Search](src/algorithms/tree/depth-first-search) (DFS) * `B` [Breadth-First Search](src/algorithms/tree/breadth-first-search) (BFS) -* **Gráficos** +* **Grafos** * `B` [Depth-First Search](src/algorithms/graph/depth-first-search) (DFS) * `B` [Breadth-First Search](src/algorithms/graph/breadth-first-search) (BFS) * `B` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - encontrando Árvore Mínima de Abrangência (MST) para grafo não direcionado ponderado @@ -154,8 +154,8 @@ algoritmo é uma abstração maior que um programa de computador. * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding shortest path to all graph vertices * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - encontrando Árvore Mínima de Abrangência (MST) para grafo não direcionado ponderado * `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - encontrando Árvore Mínima de Abrangência (MST) para grafo não direcionado ponderado -* **Divide and Conquer** - dividir o problema em partes menores e depois resolver essas partes - * `B` [Binary Search](src/algorithms/search/binary-search) +* **Dividir p/ Conquistar** - dividir o problema em partes menores e depois resolver essas partes + * `B` [Busca binária (Binary Search)](src/algorithms/search/binary-search) * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower) * `B` [Pascal's Triangle](src/algorithms/math/pascal-triangle) * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD) @@ -166,7 +166,7 @@ algoritmo é uma abstração maior que um programa de computador. * `B` [Jump Game](src/algorithms/uncategorized/jump-game) * `A` [Permutations](src/algorithms/sets/permutations) (com e sem repetições) * `A` [Combinations](src/algorithms/sets/combinations) (com e sem repetições) -* **Dynamic Programming** - criar uma solução usando sub-soluções encontradas anteriormente +* **Programação Dinâmica** - criar uma solução usando sub-soluções encontradas anteriormente * `B` [Fibonacci Number](src/algorithms/math/fibonacci) * `B` [Jump Game](src/algorithms/uncategorized/jump-game) * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) From e220450d7d35bd59b344a9ed640100c370dca79c Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Thu, 17 Dec 2020 09:49:57 +0100 Subject: [PATCH 042/264] Code style fixes. --- src/algorithms/linked-list/traversal/README.md | 2 +- src/algorithms/linked-list/traversal/README.ru-RU.md | 2 +- src/data-structures/linked-list/__test__/LinkedList.test.js | 6 ++---- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/algorithms/linked-list/traversal/README.md b/src/algorithms/linked-list/traversal/README.md index 2416323dd8..79e7b43626 100644 --- a/src/algorithms/linked-list/traversal/README.md +++ b/src/algorithms/linked-list/traversal/README.md @@ -7,7 +7,7 @@ The task is to traverse the given linked list in straight order. For example for the following linked list: -![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) +![Singly linked list](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) The order of traversal should be: diff --git a/src/algorithms/linked-list/traversal/README.ru-RU.md b/src/algorithms/linked-list/traversal/README.ru-RU.md index e4587bf6af..fa3cfb2fb1 100644 --- a/src/algorithms/linked-list/traversal/README.ru-RU.md +++ b/src/algorithms/linked-list/traversal/README.ru-RU.md @@ -4,7 +4,7 @@ Например, для следующего связного списка: -![](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) +![Singly linked list](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) Порядок обхода будет такой: diff --git a/src/data-structures/linked-list/__test__/LinkedList.test.js b/src/data-structures/linked-list/__test__/LinkedList.test.js index bce06f727e..f4eb83e2bd 100644 --- a/src/data-structures/linked-list/__test__/LinkedList.test.js +++ b/src/data-structures/linked-list/__test__/LinkedList.test.js @@ -227,20 +227,18 @@ describe('LinkedList', () => { let node = linkedList.find({ value: 3 }); expect(node.value).toBe(4); - node = linkedList.find({ callback: value => value < 3 }); + node = linkedList.find({ callback: (value) => value < 3 }); expect(node.value).toBe(1); }); it('should convert to array', () => { const linkedList = new LinkedList(); - linkedList.append(1); linkedList.append(2); linkedList.append(3); - expect(linkedList.toArray().join(',')).toBe('1,2,3'); }); - + it('should reverse linked list', () => { const linkedList = new LinkedList(); From 2c81debb477744d5bb28d0290c16ebf4b3d0197c Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sat, 19 Dec 2020 18:45:14 +0100 Subject: [PATCH 043/264] Add Matrices section with basic Matrix operations (multiplication, transposition, etc.) --- README.md | 1 + .../cryptography/hill-cipher/hillCipher.js | 45 +- src/algorithms/math/matrix/Matrix.js | 309 ++++++++++++ src/algorithms/math/matrix/README.md | 63 +++ .../math/matrix/__tests__/Matrix.test.js | 455 ++++++++++++++++++ 5 files changed, 852 insertions(+), 21 deletions(-) create mode 100644 src/algorithms/math/matrix/Matrix.js create mode 100644 src/algorithms/math/matrix/README.md create mode 100644 src/algorithms/math/matrix/__tests__/Matrix.test.js diff --git a/README.md b/README.md index 784dcd7ca6..454d70ff61 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Radian & Degree](src/algorithms/math/radian) - radians to degree and backwards conversion * `B` [Fast Powering](src/algorithms/math/fast-powering) * `B` [Horner's method](src/algorithms/math/horner-method) - polynomial evaluation + * `B` [Matrices](src/algorithms/math/matrix) - matrices and basic matrix operations (multiplication, transposition, etc.) * `A` [Integer Partition](src/algorithms/math/integer-partition) * `A` [Square Root](src/algorithms/math/square-root) - Newton's method * `A` [Liu Hui π Algorithm](src/algorithms/math/liu-hui) - approximate π calculations based on N-gons diff --git a/src/algorithms/cryptography/hill-cipher/hillCipher.js b/src/algorithms/cryptography/hill-cipher/hillCipher.js index f776db6224..1fe3033860 100644 --- a/src/algorithms/cryptography/hill-cipher/hillCipher.js +++ b/src/algorithms/cryptography/hill-cipher/hillCipher.js @@ -1,3 +1,5 @@ +import * as mtrx from '../../math/matrix/Matrix'; + // The code of an 'A' character (equals to 65). const alphabetCodeShift = 'A'.codePointAt(0); const englishAlphabetSize = 26; @@ -15,33 +17,36 @@ const generateKeyMatrix = (keyString) => { 'Invalid key string length. The square root of the key string must be an integer', ); } - const keyMatrix = []; let keyStringIndex = 0; - for (let i = 0; i < matrixSize; i += 1) { - const keyMatrixRow = []; - for (let j = 0; j < matrixSize; j += 1) { + return mtrx.generate( + [matrixSize, matrixSize], + // Callback to get a value of each matrix cell. + // The order the matrix is being filled in is from left to right, from top to bottom. + () => { // A → 0, B → 1, ..., a → 32, b → 33, ... const charCodeShifted = (keyString.codePointAt(keyStringIndex)) % alphabetCodeShift; - keyMatrixRow.push(charCodeShifted); keyStringIndex += 1; - } - keyMatrix.push(keyMatrixRow); - } - return keyMatrix; + return charCodeShifted; + }, + ); }; /** * Generates a message vector from a given message. * * @param {string} message - the message to encrypt. - * @return {number[]} messageVector + * @return {number[][]} messageVector */ const generateMessageVector = (message) => { - const messageVector = []; - for (let i = 0; i < message.length; i += 1) { - messageVector.push(message.codePointAt(i) % alphabetCodeShift); - } - return messageVector; + return mtrx.generate( + [message.length, 1], + // Callback to get a value of each matrix cell. + // The order the matrix is being filled in is from left to right, from top to bottom. + (cellIndices) => { + const rowIndex = cellIndices[0]; + return message.codePointAt(rowIndex) % alphabetCodeShift; + }, + ); }; /** @@ -59,19 +64,17 @@ export function hillCipherEncrypt(message, keyString) { } const keyMatrix = generateKeyMatrix(keyString); + const messageVector = generateMessageVector(message); // keyString.length must equal to square of message.length if (keyMatrix.length !== message.length) { throw new Error('Invalid key string length. The key length must be a square of message length'); } - const messageVector = generateMessageVector(message); + const cipherVector = mtrx.dot(keyMatrix, messageVector); let cipherString = ''; - for (let row = 0; row < keyMatrix.length; row += 1) { - let item = 0; - for (let column = 0; column < keyMatrix.length; column += 1) { - item += keyMatrix[row][column] * messageVector[column]; - } + for (let row = 0; row < cipherVector.length; row += 1) { + const item = cipherVector[row]; cipherString += String.fromCharCode((item % englishAlphabetSize) + alphabetCodeShift); } diff --git a/src/algorithms/math/matrix/Matrix.js b/src/algorithms/math/matrix/Matrix.js new file mode 100644 index 0000000000..2470eb3913 --- /dev/null +++ b/src/algorithms/math/matrix/Matrix.js @@ -0,0 +1,309 @@ +/** + * @typedef {number} Cell + * @typedef {Cell[][]|Cell[][][]} Matrix + * @typedef {number[]} Shape + * @typedef {number[]} CellIndices + */ + +/** + * Gets the matrix's shape. + * + * @param {Matrix} m + * @returns {Shape} + */ +export const shape = (m) => { + const shapes = []; + let dimension = m; + while (dimension && Array.isArray(dimension)) { + shapes.push(dimension.length); + dimension = (dimension.length && [...dimension][0]) || null; + } + return shapes; +}; + +/** + * Checks if matrix has a correct type. + * + * @param {Matrix} m + * @throws {Error} + */ +const validateType = (m) => { + if ( + !m + || !Array.isArray(m) + || !Array.isArray(m[0]) + ) { + throw new Error('Invalid matrix format'); + } +}; + +/** + * Checks if matrix is two dimensional. + * + * @param {Matrix} m + * @throws {Error} + */ +const validate2D = (m) => { + validateType(m); + const aShape = shape(m); + if (aShape.length !== 2) { + throw new Error('Matrix is not of 2D shape'); + } +}; + +/** + * Validates that matrices are of the same shape. + * + * @param {Matrix} a + * @param {Matrix} b + * @trows {Error} + */ +const validateSameShape = (a, b) => { + validateType(a); + validateType(b); + + const aShape = shape(a); + const bShape = shape(b); + + if (aShape.length !== bShape.length) { + throw new Error('Matrices have different dimensions'); + } + + while (aShape.length && bShape.length) { + if (aShape.pop() !== bShape.pop()) { + throw new Error('Matrices have different shapes'); + } + } +}; + +/** + * Generates the matrix of specific shape with specific values. + * + * @param {Shape} mShape - the shape of the matrix to generate + * @param {function({CellIndex}): Cell} fill - cell values of a generated matrix. + * @returns {Matrix} + */ +export const generate = (mShape, fill) => { + /** + * Generates the matrix recursively. + * + * @param {Shape} recShape - the shape of the matrix to generate + * @param {CellIndices} recIndices + * @returns {Matrix} + */ + const generateRecursively = (recShape, recIndices) => { + if (recShape.length === 1) { + return Array(recShape[0]) + .fill(null) + .map((cellValue, cellIndex) => fill([...recIndices, cellIndex])); + } + const m = []; + for (let i = 0; i < recShape[0]; i += 1) { + m.push(generateRecursively(recShape.slice(1), [...recIndices, i])); + } + return m; + }; + + return generateRecursively(mShape, []); +}; + +/** + * Generates the matrix of zeros of specified shape. + * + * @param {Shape} mShape - shape of the matrix + * @returns {Matrix} + */ +export const zeros = (mShape) => { + return generate(mShape, () => 0); +}; + +/** + * @param {Matrix} a + * @param {Matrix} b + * @return Matrix + * @throws {Error} + */ +export const dot = (a, b) => { + // Validate inputs. + validate2D(a); + validate2D(b); + + // Check dimensions. + const aShape = shape(a); + const bShape = shape(b); + if (aShape[1] !== bShape[0]) { + throw new Error('Matrices have incompatible shape for multiplication'); + } + + // Perform matrix multiplication. + const outputShape = [aShape[0], bShape[1]]; + const c = zeros(outputShape); + + for (let bCol = 0; bCol < b[0].length; bCol += 1) { + for (let aRow = 0; aRow < a.length; aRow += 1) { + let cellSum = 0; + for (let aCol = 0; aCol < a[aRow].length; aCol += 1) { + cellSum += a[aRow][aCol] * b[aCol][bCol]; + } + c[aRow][bCol] = cellSum; + } + } + + return c; +}; + +/** + * Transposes the matrix. + * + * @param {Matrix} m + * @returns Matrix + * @throws {Error} + */ +export const t = (m) => { + validate2D(m); + const mShape = shape(m); + const transposed = zeros([mShape[1], mShape[0]]); + for (let row = 0; row < m.length; row += 1) { + for (let col = 0; col < m[0].length; col += 1) { + transposed[col][row] = m[row][col]; + } + } + return transposed; +}; + +/** + * Traverses the matrix. + * + * @param {Matrix} m + * @param {function(indices: CellIndices, c: Cell)} visit + */ +const walk = (m, visit) => { + /** + * Traverses the matrix recursively. + * + * @param {Matrix} recM + * @param {CellIndices} cellIndices + * @return {Matrix} + */ + const recWalk = (recM, cellIndices) => { + const recMShape = shape(recM); + + if (recMShape.length === 1) { + for (let i = 0; i < recM.length; i += 1) { + visit([...cellIndices, i], recM[i]); + } + } + for (let i = 0; i < recM.length; i += 1) { + recWalk(recM[i], [...cellIndices, i]); + } + }; + + recWalk(m, []); +}; + +/** + * Gets the matrix cell value at specific index. + * + * @param {Matrix} m - Matrix that contains the cell that needs to be updated + * @param {CellIndices} cellIndices - Array of cell indices + * @return {Cell} + */ +const getCellAtIndex = (m, cellIndices) => { + // We start from the row at specific index. + let cell = m[cellIndices[0]]; + // Going deeper into the next dimensions but not to the last one to preserve + // the pointer to the last dimension array. + for (let dimIdx = 1; dimIdx < cellIndices.length - 1; dimIdx += 1) { + cell = cell[cellIndices[dimIdx]]; + } + // At this moment the cell variable points to the array at the last needed dimension. + return cell[cellIndices[cellIndices.length - 1]]; +}; + +/** + * Update the matrix cell at specific index. + * + * @param {Matrix} m - Matrix that contains the cell that needs to be updated + * @param {CellIndices} cellIndices - Array of cell indices + * @param {Cell} cellValue - New cell value + */ +const updateCellAtIndex = (m, cellIndices, cellValue) => { + // We start from the row at specific index. + let cell = m[cellIndices[0]]; + // Going deeper into the next dimensions but not to the last one to preserve + // the pointer to the last dimension array. + for (let dimIdx = 1; dimIdx < cellIndices.length - 1; dimIdx += 1) { + cell = cell[cellIndices[dimIdx]]; + } + // At this moment the cell variable points to the array at the last needed dimension. + cell[cellIndices[cellIndices.length - 1]] = cellValue; +}; + +/** + * Adds two matrices element-wise. + * + * @param {Matrix} a + * @param {Matrix} b + * @return {Matrix} + */ +export const add = (a, b) => { + validateSameShape(a, b); + const result = zeros(shape(a)); + + walk(a, (cellIndices, cellValue) => { + updateCellAtIndex(result, cellIndices, cellValue); + }); + + walk(b, (cellIndices, cellValue) => { + const currentCellValue = getCellAtIndex(result, cellIndices); + updateCellAtIndex(result, cellIndices, currentCellValue + cellValue); + }); + + return result; +}; + +/** + * Multiplies two matrices element-wise. + * + * @param {Matrix} a + * @param {Matrix} b + * @return {Matrix} + */ +export const mul = (a, b) => { + validateSameShape(a, b); + const result = zeros(shape(a)); + + walk(a, (cellIndices, cellValue) => { + updateCellAtIndex(result, cellIndices, cellValue); + }); + + walk(b, (cellIndices, cellValue) => { + const currentCellValue = getCellAtIndex(result, cellIndices); + updateCellAtIndex(result, cellIndices, currentCellValue * cellValue); + }); + + return result; +}; + +/** + * Subtract two matrices element-wise. + * + * @param {Matrix} a + * @param {Matrix} b + * @return {Matrix} + */ +export const sub = (a, b) => { + validateSameShape(a, b); + const result = zeros(shape(a)); + + walk(a, (cellIndices, cellValue) => { + updateCellAtIndex(result, cellIndices, cellValue); + }); + + walk(b, (cellIndices, cellValue) => { + const currentCellValue = getCellAtIndex(result, cellIndices); + updateCellAtIndex(result, cellIndices, currentCellValue - cellValue); + }); + + return result; +}; diff --git a/src/algorithms/math/matrix/README.md b/src/algorithms/math/matrix/README.md new file mode 100644 index 0000000000..8e084403b0 --- /dev/null +++ b/src/algorithms/math/matrix/README.md @@ -0,0 +1,63 @@ +# Matrices + +In mathematics, a **matrix** (plural **matrices**) is a rectangular array or table of numbers, symbols, or expressions, arranged in rows and columns. For example, the dimension of the matrix below is `2 × 3` (read "two by three"), because there are two rows and three columns: + +``` +| 1 9 -13 | +| 20 5 -6 | +``` + +![An `m × n` matrix](https://upload.wikimedia.org/wikipedia/commons/b/bf/Matris.png) + +An `m × n` matrix: the `m` rows are horizontal, and the `n` columns are vertical. Each element of a matrix is often denoted by a variable with two subscripts. For example, a2,1 represents the element at the second row and first column of the matrix + +## Operations on matrices + +### Addition + +To add two matrices: add the numbers in the matching positions: + +![Matrices addition](https://www.mathsisfun.com/algebra/images/matrix-addition.gif) + +The two matrices must be the same size, i.e. the rows must match in size, and the columns must match in size. + +### Subtracting + +To subtract two matrices: subtract the numbers in the matching positions: + +![Matrices subtraction](https://www.mathsisfun.com/algebra/images/matrix-subtraction.gif) + +### Multiply by a Constant + +We can multiply a matrix by a constant (the value 2 in this case): + +![Matrices multiplication be a constant](https://www.mathsisfun.com/algebra/images/matrix-multiply-constant.gif) + +### Multiplying by Another Matrix + +To multiply a matrix by another matrix we need to do the [dot product](https://www.mathsisfun.com/algebra/vectors-dot-product.html) of rows and columns. + +To work out the answer for the **1st row** and **1st column**: + +![Matrices multiplication - 1st step](https://www.mathsisfun.com/algebra/images/matrix-multiply-a.svg) + +Here it is for the 1st row and 2nd column: + +![Matrices multiplication - 2st step](https://www.mathsisfun.com/algebra/images/matrix-multiply-b.svg) + +If we'll do the same for the rest of the rows and columns we'll get the following resulting matrix: + +![Matrices multiplication - Result](https://www.mathsisfun.com/algebra/images/matrix-multiply-c.svg) + +### Transposing + +To "transpose" a matrix, swap the rows and columns. + +We put a "T" in the top right-hand corner to mean transpose: + +![Transposing](https://www.mathsisfun.com/algebra/images/matrix-transpose.gif) + +## References + +- [Matrices on MathIsFun](https://www.mathsisfun.com/algebra/matrix-introduction.html) +- [Matrix on Wikipedia](https://en.wikipedia.org/wiki/Matrix_(mathematics)) diff --git a/src/algorithms/math/matrix/__tests__/Matrix.test.js b/src/algorithms/math/matrix/__tests__/Matrix.test.js new file mode 100644 index 0000000000..37dc892b0a --- /dev/null +++ b/src/algorithms/math/matrix/__tests__/Matrix.test.js @@ -0,0 +1,455 @@ +import * as mtrx from '../Matrix'; + +describe('Matrix', () => { + it('should throw when trying to add matrices of invalid shapes', () => { + expect( + () => mtrx.dot([0], [1]), + ).toThrowError('Invalid matrix format'); + expect( + () => mtrx.dot([[0]], [1]), + ).toThrowError('Invalid matrix format'); + expect( + () => mtrx.dot([[[0]]], [[1]]), + ).toThrowError('Matrix is not of 2D shape'); + expect( + () => mtrx.dot([[0]], [[1], [2]]), + ).toThrowError('Matrices have incompatible shape for multiplication'); + }); + + it('should calculate matrices dimensions', () => { + expect(mtrx.shape([])).toEqual([0]); + + expect(mtrx.shape([ + [], + ])).toEqual([1, 0]); + + expect(mtrx.shape([ + [0], + ])).toEqual([1, 1]); + + expect(mtrx.shape([ + [0, 0], + ])).toEqual([1, 2]); + + expect(mtrx.shape([ + [0, 0], + [0, 0], + ])).toEqual([2, 2]); + + expect(mtrx.shape([ + [0, 0, 0], + [0, 0, 0], + ])).toEqual([2, 3]); + + expect(mtrx.shape([ + [0, 0], + [0, 0], + [0, 0], + ])).toEqual([3, 2]); + + expect(mtrx.shape([ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + ])).toEqual([3, 3]); + + expect(mtrx.shape([ + [0], + [0], + [0], + ])).toEqual([3, 1]); + + expect(mtrx.shape([ + [[0], [0], [0]], + [[0], [0], [0]], + [[0], [0], [0]], + ])).toEqual([3, 3, 1]); + + expect(mtrx.shape([ + [[0, 0, 0], [0, 0, 0], [0, 0, 0]], + [[0, 0, 0], [0, 0, 0], [0, 0, 0]], + [[0, 0, 0], [0, 0, 0], [0, 0, 0]], + ])).toEqual([3, 3, 3]); + }); + + it('should generate the matrix of zeros', () => { + expect(mtrx.zeros([1, 0])).toEqual([ + [], + ]); + + expect(mtrx.zeros([1, 1])).toEqual([ + [0], + ]); + + expect(mtrx.zeros([1, 3])).toEqual([ + [0, 0, 0], + ]); + + expect(mtrx.zeros([3, 3])).toEqual([ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + ]); + + expect(mtrx.zeros([3, 3, 1])).toEqual([ + [[0], [0], [0]], + [[0], [0], [0]], + [[0], [0], [0]], + ]); + }); + + it('should generate the matrix with custom values', () => { + expect(mtrx.generate([1, 0], () => 1)).toEqual([ + [], + ]); + + expect(mtrx.generate([1, 1], () => 1)).toEqual([ + [1], + ]); + + expect(mtrx.generate([1, 3], () => 1)).toEqual([ + [1, 1, 1], + ]); + + expect(mtrx.generate([3, 3], () => 1)).toEqual([ + [1, 1, 1], + [1, 1, 1], + [1, 1, 1], + ]); + + expect(mtrx.generate([3, 3, 1], () => 1)).toEqual([ + [[1], [1], [1]], + [[1], [1], [1]], + [[1], [1], [1]], + ]); + }); + + it('should generate a custom matrix based on specific cell indices', () => { + const indicesCallback = jest.fn((indices) => { + return indices[0] * 10 + indices[1]; + }); + const m = mtrx.generate([3, 3], indicesCallback); + + expect(indicesCallback).toHaveBeenCalledTimes(3 * 3); + expect(indicesCallback.mock.calls[0][0]).toEqual([0, 0]); + expect(indicesCallback.mock.calls[1][0]).toEqual([0, 1]); + expect(indicesCallback.mock.calls[2][0]).toEqual([0, 2]); + expect(indicesCallback.mock.calls[3][0]).toEqual([1, 0]); + expect(indicesCallback.mock.calls[4][0]).toEqual([1, 1]); + expect(indicesCallback.mock.calls[5][0]).toEqual([1, 2]); + expect(indicesCallback.mock.calls[6][0]).toEqual([2, 0]); + expect(indicesCallback.mock.calls[7][0]).toEqual([2, 1]); + expect(indicesCallback.mock.calls[8][0]).toEqual([2, 2]); + expect(m).toEqual([ + [0, 1, 2], + [10, 11, 12], + [20, 21, 22], + ]); + }); + + it('should multiply two matrices', () => { + let c; + c = mtrx.dot( + [ + [1, 2], + [3, 4], + ], + [ + [5, 6], + [7, 8], + ], + ); + expect(mtrx.shape(c)).toEqual([2, 2]); + expect(c).toEqual([ + [19, 22], + [43, 50], + ]); + + c = mtrx.dot( + [ + [1, 2], + [3, 4], + ], + [ + [5], + [6], + ], + ); + expect(mtrx.shape(c)).toEqual([2, 1]); + expect(c).toEqual([ + [17], + [39], + ]); + + c = mtrx.dot( + [ + [1, 2, 3], + [4, 5, 6], + ], + [ + [7, 8], + [9, 10], + [11, 12], + ], + ); + expect(mtrx.shape(c)).toEqual([2, 2]); + expect(c).toEqual([ + [58, 64], + [139, 154], + ]); + + c = mtrx.dot( + [ + [3, 4, 2], + ], + [ + [13, 9, 7, 5], + [8, 7, 4, 6], + [6, 4, 0, 3], + ], + ); + expect(mtrx.shape(c)).toEqual([1, 4]); + expect(c).toEqual([ + [83, 63, 37, 45], + ]); + }); + + it('should transpose matrices', () => { + expect(mtrx.t([[1, 2, 3]])).toEqual([ + [1], + [2], + [3], + ]); + + expect(mtrx.t([ + [1], + [2], + [3], + ])).toEqual([ + [1, 2, 3], + ]); + + expect(mtrx.t([ + [1, 2, 3], + [4, 5, 6], + ])).toEqual([ + [1, 4], + [2, 5], + [3, 6], + ]); + + expect(mtrx.t([ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ])).toEqual([ + [1, 4, 7], + [2, 5, 8], + [3, 6, 9], + ]); + }); + + it('should throw when trying to transpose non 2D matrix', () => { + expect(() => { + mtrx.t([[[1]]]); + }).toThrowError('Matrix is not of 2D shape'); + }); + + it('should add two matrices', () => { + expect(mtrx.add([[1]], [[2]])).toEqual([[3]]); + + expect(mtrx.add( + [[1, 2, 3]], + [[4, 5, 6]], + )) + .toEqual( + [[5, 7, 9]], + ); + + expect(mtrx.add( + [[1], [2], [3]], + [[4], [5], [6]], + )) + .toEqual( + [[5], [7], [9]], + ); + + expect(mtrx.add( + [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ], + [ + [10, 11, 12], + [13, 14, 15], + [16, 17, 18], + ], + )) + .toEqual( + [ + [11, 13, 15], + [17, 19, 21], + [23, 25, 27], + ], + ); + + expect(mtrx.add( + [ + [[1], [2], [3]], + [[4], [5], [6]], + [[7], [8], [9]], + ], + [ + [[10], [11], [12]], + [[13], [14], [15]], + [[16], [17], [18]], + ], + )) + .toEqual( + [ + [[11], [13], [15]], + [[17], [19], [21]], + [[23], [25], [27]], + ], + ); + }); + + it('should throw when trying to add matrices of different shape', () => { + expect(() => mtrx.add([[0]], [[[0]]])).toThrowError( + 'Matrices have different dimensions', + ); + + expect(() => mtrx.add([[0]], [[0, 0]])).toThrowError( + 'Matrices have different shapes', + ); + }); + + it('should do element wise multiplication two matrices', () => { + expect(mtrx.mul([[2]], [[3]])).toEqual([[6]]); + + expect(mtrx.mul( + [[1, 2, 3]], + [[4, 5, 6]], + )) + .toEqual( + [[4, 10, 18]], + ); + + expect(mtrx.mul( + [[1], [2], [3]], + [[4], [5], [6]], + )) + .toEqual( + [[4], [10], [18]], + ); + + expect(mtrx.mul( + [ + [1, 2], + [3, 4], + ], + [ + [5, 6], + [7, 8], + ], + )) + .toEqual( + [ + [5, 12], + [21, 32], + ], + ); + + expect(mtrx.mul( + [ + [[1], [2]], + [[3], [4]], + ], + [ + [[5], [6]], + [[7], [8]], + ], + )) + .toEqual( + [ + [[5], [12]], + [[21], [32]], + ], + ); + }); + + it('should throw when trying to multiply matrices element-wise of different shape', () => { + expect(() => mtrx.mul([[0]], [[[0]]])).toThrowError( + 'Matrices have different dimensions', + ); + + expect(() => mtrx.mul([[0]], [[0, 0]])).toThrowError( + 'Matrices have different shapes', + ); + }); + + it('should do element wise subtraction two matrices', () => { + expect(mtrx.sub([[3]], [[2]])).toEqual([[1]]); + + expect(mtrx.sub( + [[10, 12, 14]], + [[4, 5, 6]], + )) + .toEqual( + [[6, 7, 8]], + ); + + expect(mtrx.sub( + [[[10], [12], [14]]], + [[[4], [5], [6]]], + )) + .toEqual( + [[[6], [7], [8]]], + ); + + expect(mtrx.sub( + [ + [10, 20], + [30, 40], + ], + [ + [5, 6], + [7, 8], + ], + )) + .toEqual( + [ + [5, 14], + [23, 32], + ], + ); + + expect(mtrx.sub( + [ + [[10], [20]], + [[30], [40]], + ], + [ + [[5], [6]], + [[7], [8]], + ], + )) + .toEqual( + [ + [[5], [14]], + [[23], [32]], + ], + ); + }); + + it('should throw when trying to subtract matrices element-wise of different shape', () => { + expect(() => mtrx.sub([[0]], [[[0]]])).toThrowError( + 'Matrices have different dimensions', + ); + + expect(() => mtrx.sub([[0]], [[0, 0]])).toThrowError( + 'Matrices have different shapes', + ); + }); +}); From 8d52ae5d03fec152c715ef2a018d5d4b502c1488 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sat, 19 Dec 2020 18:48:10 +0100 Subject: [PATCH 044/264] Add Matrices section with basic Matrix operations (multiplication, transposition, etc.) (#600) --- README.md | 1 + .../cryptography/hill-cipher/hillCipher.js | 45 +- src/algorithms/math/matrix/Matrix.js | 309 ++++++++++++ src/algorithms/math/matrix/README.md | 63 +++ .../math/matrix/__tests__/Matrix.test.js | 455 ++++++++++++++++++ 5 files changed, 852 insertions(+), 21 deletions(-) create mode 100644 src/algorithms/math/matrix/Matrix.js create mode 100644 src/algorithms/math/matrix/README.md create mode 100644 src/algorithms/math/matrix/__tests__/Matrix.test.js diff --git a/README.md b/README.md index 784dcd7ca6..454d70ff61 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Radian & Degree](src/algorithms/math/radian) - radians to degree and backwards conversion * `B` [Fast Powering](src/algorithms/math/fast-powering) * `B` [Horner's method](src/algorithms/math/horner-method) - polynomial evaluation + * `B` [Matrices](src/algorithms/math/matrix) - matrices and basic matrix operations (multiplication, transposition, etc.) * `A` [Integer Partition](src/algorithms/math/integer-partition) * `A` [Square Root](src/algorithms/math/square-root) - Newton's method * `A` [Liu Hui π Algorithm](src/algorithms/math/liu-hui) - approximate π calculations based on N-gons diff --git a/src/algorithms/cryptography/hill-cipher/hillCipher.js b/src/algorithms/cryptography/hill-cipher/hillCipher.js index f776db6224..1fe3033860 100644 --- a/src/algorithms/cryptography/hill-cipher/hillCipher.js +++ b/src/algorithms/cryptography/hill-cipher/hillCipher.js @@ -1,3 +1,5 @@ +import * as mtrx from '../../math/matrix/Matrix'; + // The code of an 'A' character (equals to 65). const alphabetCodeShift = 'A'.codePointAt(0); const englishAlphabetSize = 26; @@ -15,33 +17,36 @@ const generateKeyMatrix = (keyString) => { 'Invalid key string length. The square root of the key string must be an integer', ); } - const keyMatrix = []; let keyStringIndex = 0; - for (let i = 0; i < matrixSize; i += 1) { - const keyMatrixRow = []; - for (let j = 0; j < matrixSize; j += 1) { + return mtrx.generate( + [matrixSize, matrixSize], + // Callback to get a value of each matrix cell. + // The order the matrix is being filled in is from left to right, from top to bottom. + () => { // A → 0, B → 1, ..., a → 32, b → 33, ... const charCodeShifted = (keyString.codePointAt(keyStringIndex)) % alphabetCodeShift; - keyMatrixRow.push(charCodeShifted); keyStringIndex += 1; - } - keyMatrix.push(keyMatrixRow); - } - return keyMatrix; + return charCodeShifted; + }, + ); }; /** * Generates a message vector from a given message. * * @param {string} message - the message to encrypt. - * @return {number[]} messageVector + * @return {number[][]} messageVector */ const generateMessageVector = (message) => { - const messageVector = []; - for (let i = 0; i < message.length; i += 1) { - messageVector.push(message.codePointAt(i) % alphabetCodeShift); - } - return messageVector; + return mtrx.generate( + [message.length, 1], + // Callback to get a value of each matrix cell. + // The order the matrix is being filled in is from left to right, from top to bottom. + (cellIndices) => { + const rowIndex = cellIndices[0]; + return message.codePointAt(rowIndex) % alphabetCodeShift; + }, + ); }; /** @@ -59,19 +64,17 @@ export function hillCipherEncrypt(message, keyString) { } const keyMatrix = generateKeyMatrix(keyString); + const messageVector = generateMessageVector(message); // keyString.length must equal to square of message.length if (keyMatrix.length !== message.length) { throw new Error('Invalid key string length. The key length must be a square of message length'); } - const messageVector = generateMessageVector(message); + const cipherVector = mtrx.dot(keyMatrix, messageVector); let cipherString = ''; - for (let row = 0; row < keyMatrix.length; row += 1) { - let item = 0; - for (let column = 0; column < keyMatrix.length; column += 1) { - item += keyMatrix[row][column] * messageVector[column]; - } + for (let row = 0; row < cipherVector.length; row += 1) { + const item = cipherVector[row]; cipherString += String.fromCharCode((item % englishAlphabetSize) + alphabetCodeShift); } diff --git a/src/algorithms/math/matrix/Matrix.js b/src/algorithms/math/matrix/Matrix.js new file mode 100644 index 0000000000..2470eb3913 --- /dev/null +++ b/src/algorithms/math/matrix/Matrix.js @@ -0,0 +1,309 @@ +/** + * @typedef {number} Cell + * @typedef {Cell[][]|Cell[][][]} Matrix + * @typedef {number[]} Shape + * @typedef {number[]} CellIndices + */ + +/** + * Gets the matrix's shape. + * + * @param {Matrix} m + * @returns {Shape} + */ +export const shape = (m) => { + const shapes = []; + let dimension = m; + while (dimension && Array.isArray(dimension)) { + shapes.push(dimension.length); + dimension = (dimension.length && [...dimension][0]) || null; + } + return shapes; +}; + +/** + * Checks if matrix has a correct type. + * + * @param {Matrix} m + * @throws {Error} + */ +const validateType = (m) => { + if ( + !m + || !Array.isArray(m) + || !Array.isArray(m[0]) + ) { + throw new Error('Invalid matrix format'); + } +}; + +/** + * Checks if matrix is two dimensional. + * + * @param {Matrix} m + * @throws {Error} + */ +const validate2D = (m) => { + validateType(m); + const aShape = shape(m); + if (aShape.length !== 2) { + throw new Error('Matrix is not of 2D shape'); + } +}; + +/** + * Validates that matrices are of the same shape. + * + * @param {Matrix} a + * @param {Matrix} b + * @trows {Error} + */ +const validateSameShape = (a, b) => { + validateType(a); + validateType(b); + + const aShape = shape(a); + const bShape = shape(b); + + if (aShape.length !== bShape.length) { + throw new Error('Matrices have different dimensions'); + } + + while (aShape.length && bShape.length) { + if (aShape.pop() !== bShape.pop()) { + throw new Error('Matrices have different shapes'); + } + } +}; + +/** + * Generates the matrix of specific shape with specific values. + * + * @param {Shape} mShape - the shape of the matrix to generate + * @param {function({CellIndex}): Cell} fill - cell values of a generated matrix. + * @returns {Matrix} + */ +export const generate = (mShape, fill) => { + /** + * Generates the matrix recursively. + * + * @param {Shape} recShape - the shape of the matrix to generate + * @param {CellIndices} recIndices + * @returns {Matrix} + */ + const generateRecursively = (recShape, recIndices) => { + if (recShape.length === 1) { + return Array(recShape[0]) + .fill(null) + .map((cellValue, cellIndex) => fill([...recIndices, cellIndex])); + } + const m = []; + for (let i = 0; i < recShape[0]; i += 1) { + m.push(generateRecursively(recShape.slice(1), [...recIndices, i])); + } + return m; + }; + + return generateRecursively(mShape, []); +}; + +/** + * Generates the matrix of zeros of specified shape. + * + * @param {Shape} mShape - shape of the matrix + * @returns {Matrix} + */ +export const zeros = (mShape) => { + return generate(mShape, () => 0); +}; + +/** + * @param {Matrix} a + * @param {Matrix} b + * @return Matrix + * @throws {Error} + */ +export const dot = (a, b) => { + // Validate inputs. + validate2D(a); + validate2D(b); + + // Check dimensions. + const aShape = shape(a); + const bShape = shape(b); + if (aShape[1] !== bShape[0]) { + throw new Error('Matrices have incompatible shape for multiplication'); + } + + // Perform matrix multiplication. + const outputShape = [aShape[0], bShape[1]]; + const c = zeros(outputShape); + + for (let bCol = 0; bCol < b[0].length; bCol += 1) { + for (let aRow = 0; aRow < a.length; aRow += 1) { + let cellSum = 0; + for (let aCol = 0; aCol < a[aRow].length; aCol += 1) { + cellSum += a[aRow][aCol] * b[aCol][bCol]; + } + c[aRow][bCol] = cellSum; + } + } + + return c; +}; + +/** + * Transposes the matrix. + * + * @param {Matrix} m + * @returns Matrix + * @throws {Error} + */ +export const t = (m) => { + validate2D(m); + const mShape = shape(m); + const transposed = zeros([mShape[1], mShape[0]]); + for (let row = 0; row < m.length; row += 1) { + for (let col = 0; col < m[0].length; col += 1) { + transposed[col][row] = m[row][col]; + } + } + return transposed; +}; + +/** + * Traverses the matrix. + * + * @param {Matrix} m + * @param {function(indices: CellIndices, c: Cell)} visit + */ +const walk = (m, visit) => { + /** + * Traverses the matrix recursively. + * + * @param {Matrix} recM + * @param {CellIndices} cellIndices + * @return {Matrix} + */ + const recWalk = (recM, cellIndices) => { + const recMShape = shape(recM); + + if (recMShape.length === 1) { + for (let i = 0; i < recM.length; i += 1) { + visit([...cellIndices, i], recM[i]); + } + } + for (let i = 0; i < recM.length; i += 1) { + recWalk(recM[i], [...cellIndices, i]); + } + }; + + recWalk(m, []); +}; + +/** + * Gets the matrix cell value at specific index. + * + * @param {Matrix} m - Matrix that contains the cell that needs to be updated + * @param {CellIndices} cellIndices - Array of cell indices + * @return {Cell} + */ +const getCellAtIndex = (m, cellIndices) => { + // We start from the row at specific index. + let cell = m[cellIndices[0]]; + // Going deeper into the next dimensions but not to the last one to preserve + // the pointer to the last dimension array. + for (let dimIdx = 1; dimIdx < cellIndices.length - 1; dimIdx += 1) { + cell = cell[cellIndices[dimIdx]]; + } + // At this moment the cell variable points to the array at the last needed dimension. + return cell[cellIndices[cellIndices.length - 1]]; +}; + +/** + * Update the matrix cell at specific index. + * + * @param {Matrix} m - Matrix that contains the cell that needs to be updated + * @param {CellIndices} cellIndices - Array of cell indices + * @param {Cell} cellValue - New cell value + */ +const updateCellAtIndex = (m, cellIndices, cellValue) => { + // We start from the row at specific index. + let cell = m[cellIndices[0]]; + // Going deeper into the next dimensions but not to the last one to preserve + // the pointer to the last dimension array. + for (let dimIdx = 1; dimIdx < cellIndices.length - 1; dimIdx += 1) { + cell = cell[cellIndices[dimIdx]]; + } + // At this moment the cell variable points to the array at the last needed dimension. + cell[cellIndices[cellIndices.length - 1]] = cellValue; +}; + +/** + * Adds two matrices element-wise. + * + * @param {Matrix} a + * @param {Matrix} b + * @return {Matrix} + */ +export const add = (a, b) => { + validateSameShape(a, b); + const result = zeros(shape(a)); + + walk(a, (cellIndices, cellValue) => { + updateCellAtIndex(result, cellIndices, cellValue); + }); + + walk(b, (cellIndices, cellValue) => { + const currentCellValue = getCellAtIndex(result, cellIndices); + updateCellAtIndex(result, cellIndices, currentCellValue + cellValue); + }); + + return result; +}; + +/** + * Multiplies two matrices element-wise. + * + * @param {Matrix} a + * @param {Matrix} b + * @return {Matrix} + */ +export const mul = (a, b) => { + validateSameShape(a, b); + const result = zeros(shape(a)); + + walk(a, (cellIndices, cellValue) => { + updateCellAtIndex(result, cellIndices, cellValue); + }); + + walk(b, (cellIndices, cellValue) => { + const currentCellValue = getCellAtIndex(result, cellIndices); + updateCellAtIndex(result, cellIndices, currentCellValue * cellValue); + }); + + return result; +}; + +/** + * Subtract two matrices element-wise. + * + * @param {Matrix} a + * @param {Matrix} b + * @return {Matrix} + */ +export const sub = (a, b) => { + validateSameShape(a, b); + const result = zeros(shape(a)); + + walk(a, (cellIndices, cellValue) => { + updateCellAtIndex(result, cellIndices, cellValue); + }); + + walk(b, (cellIndices, cellValue) => { + const currentCellValue = getCellAtIndex(result, cellIndices); + updateCellAtIndex(result, cellIndices, currentCellValue - cellValue); + }); + + return result; +}; diff --git a/src/algorithms/math/matrix/README.md b/src/algorithms/math/matrix/README.md new file mode 100644 index 0000000000..8e084403b0 --- /dev/null +++ b/src/algorithms/math/matrix/README.md @@ -0,0 +1,63 @@ +# Matrices + +In mathematics, a **matrix** (plural **matrices**) is a rectangular array or table of numbers, symbols, or expressions, arranged in rows and columns. For example, the dimension of the matrix below is `2 × 3` (read "two by three"), because there are two rows and three columns: + +``` +| 1 9 -13 | +| 20 5 -6 | +``` + +![An `m × n` matrix](https://upload.wikimedia.org/wikipedia/commons/b/bf/Matris.png) + +An `m × n` matrix: the `m` rows are horizontal, and the `n` columns are vertical. Each element of a matrix is often denoted by a variable with two subscripts. For example, a2,1 represents the element at the second row and first column of the matrix + +## Operations on matrices + +### Addition + +To add two matrices: add the numbers in the matching positions: + +![Matrices addition](https://www.mathsisfun.com/algebra/images/matrix-addition.gif) + +The two matrices must be the same size, i.e. the rows must match in size, and the columns must match in size. + +### Subtracting + +To subtract two matrices: subtract the numbers in the matching positions: + +![Matrices subtraction](https://www.mathsisfun.com/algebra/images/matrix-subtraction.gif) + +### Multiply by a Constant + +We can multiply a matrix by a constant (the value 2 in this case): + +![Matrices multiplication be a constant](https://www.mathsisfun.com/algebra/images/matrix-multiply-constant.gif) + +### Multiplying by Another Matrix + +To multiply a matrix by another matrix we need to do the [dot product](https://www.mathsisfun.com/algebra/vectors-dot-product.html) of rows and columns. + +To work out the answer for the **1st row** and **1st column**: + +![Matrices multiplication - 1st step](https://www.mathsisfun.com/algebra/images/matrix-multiply-a.svg) + +Here it is for the 1st row and 2nd column: + +![Matrices multiplication - 2st step](https://www.mathsisfun.com/algebra/images/matrix-multiply-b.svg) + +If we'll do the same for the rest of the rows and columns we'll get the following resulting matrix: + +![Matrices multiplication - Result](https://www.mathsisfun.com/algebra/images/matrix-multiply-c.svg) + +### Transposing + +To "transpose" a matrix, swap the rows and columns. + +We put a "T" in the top right-hand corner to mean transpose: + +![Transposing](https://www.mathsisfun.com/algebra/images/matrix-transpose.gif) + +## References + +- [Matrices on MathIsFun](https://www.mathsisfun.com/algebra/matrix-introduction.html) +- [Matrix on Wikipedia](https://en.wikipedia.org/wiki/Matrix_(mathematics)) diff --git a/src/algorithms/math/matrix/__tests__/Matrix.test.js b/src/algorithms/math/matrix/__tests__/Matrix.test.js new file mode 100644 index 0000000000..37dc892b0a --- /dev/null +++ b/src/algorithms/math/matrix/__tests__/Matrix.test.js @@ -0,0 +1,455 @@ +import * as mtrx from '../Matrix'; + +describe('Matrix', () => { + it('should throw when trying to add matrices of invalid shapes', () => { + expect( + () => mtrx.dot([0], [1]), + ).toThrowError('Invalid matrix format'); + expect( + () => mtrx.dot([[0]], [1]), + ).toThrowError('Invalid matrix format'); + expect( + () => mtrx.dot([[[0]]], [[1]]), + ).toThrowError('Matrix is not of 2D shape'); + expect( + () => mtrx.dot([[0]], [[1], [2]]), + ).toThrowError('Matrices have incompatible shape for multiplication'); + }); + + it('should calculate matrices dimensions', () => { + expect(mtrx.shape([])).toEqual([0]); + + expect(mtrx.shape([ + [], + ])).toEqual([1, 0]); + + expect(mtrx.shape([ + [0], + ])).toEqual([1, 1]); + + expect(mtrx.shape([ + [0, 0], + ])).toEqual([1, 2]); + + expect(mtrx.shape([ + [0, 0], + [0, 0], + ])).toEqual([2, 2]); + + expect(mtrx.shape([ + [0, 0, 0], + [0, 0, 0], + ])).toEqual([2, 3]); + + expect(mtrx.shape([ + [0, 0], + [0, 0], + [0, 0], + ])).toEqual([3, 2]); + + expect(mtrx.shape([ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + ])).toEqual([3, 3]); + + expect(mtrx.shape([ + [0], + [0], + [0], + ])).toEqual([3, 1]); + + expect(mtrx.shape([ + [[0], [0], [0]], + [[0], [0], [0]], + [[0], [0], [0]], + ])).toEqual([3, 3, 1]); + + expect(mtrx.shape([ + [[0, 0, 0], [0, 0, 0], [0, 0, 0]], + [[0, 0, 0], [0, 0, 0], [0, 0, 0]], + [[0, 0, 0], [0, 0, 0], [0, 0, 0]], + ])).toEqual([3, 3, 3]); + }); + + it('should generate the matrix of zeros', () => { + expect(mtrx.zeros([1, 0])).toEqual([ + [], + ]); + + expect(mtrx.zeros([1, 1])).toEqual([ + [0], + ]); + + expect(mtrx.zeros([1, 3])).toEqual([ + [0, 0, 0], + ]); + + expect(mtrx.zeros([3, 3])).toEqual([ + [0, 0, 0], + [0, 0, 0], + [0, 0, 0], + ]); + + expect(mtrx.zeros([3, 3, 1])).toEqual([ + [[0], [0], [0]], + [[0], [0], [0]], + [[0], [0], [0]], + ]); + }); + + it('should generate the matrix with custom values', () => { + expect(mtrx.generate([1, 0], () => 1)).toEqual([ + [], + ]); + + expect(mtrx.generate([1, 1], () => 1)).toEqual([ + [1], + ]); + + expect(mtrx.generate([1, 3], () => 1)).toEqual([ + [1, 1, 1], + ]); + + expect(mtrx.generate([3, 3], () => 1)).toEqual([ + [1, 1, 1], + [1, 1, 1], + [1, 1, 1], + ]); + + expect(mtrx.generate([3, 3, 1], () => 1)).toEqual([ + [[1], [1], [1]], + [[1], [1], [1]], + [[1], [1], [1]], + ]); + }); + + it('should generate a custom matrix based on specific cell indices', () => { + const indicesCallback = jest.fn((indices) => { + return indices[0] * 10 + indices[1]; + }); + const m = mtrx.generate([3, 3], indicesCallback); + + expect(indicesCallback).toHaveBeenCalledTimes(3 * 3); + expect(indicesCallback.mock.calls[0][0]).toEqual([0, 0]); + expect(indicesCallback.mock.calls[1][0]).toEqual([0, 1]); + expect(indicesCallback.mock.calls[2][0]).toEqual([0, 2]); + expect(indicesCallback.mock.calls[3][0]).toEqual([1, 0]); + expect(indicesCallback.mock.calls[4][0]).toEqual([1, 1]); + expect(indicesCallback.mock.calls[5][0]).toEqual([1, 2]); + expect(indicesCallback.mock.calls[6][0]).toEqual([2, 0]); + expect(indicesCallback.mock.calls[7][0]).toEqual([2, 1]); + expect(indicesCallback.mock.calls[8][0]).toEqual([2, 2]); + expect(m).toEqual([ + [0, 1, 2], + [10, 11, 12], + [20, 21, 22], + ]); + }); + + it('should multiply two matrices', () => { + let c; + c = mtrx.dot( + [ + [1, 2], + [3, 4], + ], + [ + [5, 6], + [7, 8], + ], + ); + expect(mtrx.shape(c)).toEqual([2, 2]); + expect(c).toEqual([ + [19, 22], + [43, 50], + ]); + + c = mtrx.dot( + [ + [1, 2], + [3, 4], + ], + [ + [5], + [6], + ], + ); + expect(mtrx.shape(c)).toEqual([2, 1]); + expect(c).toEqual([ + [17], + [39], + ]); + + c = mtrx.dot( + [ + [1, 2, 3], + [4, 5, 6], + ], + [ + [7, 8], + [9, 10], + [11, 12], + ], + ); + expect(mtrx.shape(c)).toEqual([2, 2]); + expect(c).toEqual([ + [58, 64], + [139, 154], + ]); + + c = mtrx.dot( + [ + [3, 4, 2], + ], + [ + [13, 9, 7, 5], + [8, 7, 4, 6], + [6, 4, 0, 3], + ], + ); + expect(mtrx.shape(c)).toEqual([1, 4]); + expect(c).toEqual([ + [83, 63, 37, 45], + ]); + }); + + it('should transpose matrices', () => { + expect(mtrx.t([[1, 2, 3]])).toEqual([ + [1], + [2], + [3], + ]); + + expect(mtrx.t([ + [1], + [2], + [3], + ])).toEqual([ + [1, 2, 3], + ]); + + expect(mtrx.t([ + [1, 2, 3], + [4, 5, 6], + ])).toEqual([ + [1, 4], + [2, 5], + [3, 6], + ]); + + expect(mtrx.t([ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ])).toEqual([ + [1, 4, 7], + [2, 5, 8], + [3, 6, 9], + ]); + }); + + it('should throw when trying to transpose non 2D matrix', () => { + expect(() => { + mtrx.t([[[1]]]); + }).toThrowError('Matrix is not of 2D shape'); + }); + + it('should add two matrices', () => { + expect(mtrx.add([[1]], [[2]])).toEqual([[3]]); + + expect(mtrx.add( + [[1, 2, 3]], + [[4, 5, 6]], + )) + .toEqual( + [[5, 7, 9]], + ); + + expect(mtrx.add( + [[1], [2], [3]], + [[4], [5], [6]], + )) + .toEqual( + [[5], [7], [9]], + ); + + expect(mtrx.add( + [ + [1, 2, 3], + [4, 5, 6], + [7, 8, 9], + ], + [ + [10, 11, 12], + [13, 14, 15], + [16, 17, 18], + ], + )) + .toEqual( + [ + [11, 13, 15], + [17, 19, 21], + [23, 25, 27], + ], + ); + + expect(mtrx.add( + [ + [[1], [2], [3]], + [[4], [5], [6]], + [[7], [8], [9]], + ], + [ + [[10], [11], [12]], + [[13], [14], [15]], + [[16], [17], [18]], + ], + )) + .toEqual( + [ + [[11], [13], [15]], + [[17], [19], [21]], + [[23], [25], [27]], + ], + ); + }); + + it('should throw when trying to add matrices of different shape', () => { + expect(() => mtrx.add([[0]], [[[0]]])).toThrowError( + 'Matrices have different dimensions', + ); + + expect(() => mtrx.add([[0]], [[0, 0]])).toThrowError( + 'Matrices have different shapes', + ); + }); + + it('should do element wise multiplication two matrices', () => { + expect(mtrx.mul([[2]], [[3]])).toEqual([[6]]); + + expect(mtrx.mul( + [[1, 2, 3]], + [[4, 5, 6]], + )) + .toEqual( + [[4, 10, 18]], + ); + + expect(mtrx.mul( + [[1], [2], [3]], + [[4], [5], [6]], + )) + .toEqual( + [[4], [10], [18]], + ); + + expect(mtrx.mul( + [ + [1, 2], + [3, 4], + ], + [ + [5, 6], + [7, 8], + ], + )) + .toEqual( + [ + [5, 12], + [21, 32], + ], + ); + + expect(mtrx.mul( + [ + [[1], [2]], + [[3], [4]], + ], + [ + [[5], [6]], + [[7], [8]], + ], + )) + .toEqual( + [ + [[5], [12]], + [[21], [32]], + ], + ); + }); + + it('should throw when trying to multiply matrices element-wise of different shape', () => { + expect(() => mtrx.mul([[0]], [[[0]]])).toThrowError( + 'Matrices have different dimensions', + ); + + expect(() => mtrx.mul([[0]], [[0, 0]])).toThrowError( + 'Matrices have different shapes', + ); + }); + + it('should do element wise subtraction two matrices', () => { + expect(mtrx.sub([[3]], [[2]])).toEqual([[1]]); + + expect(mtrx.sub( + [[10, 12, 14]], + [[4, 5, 6]], + )) + .toEqual( + [[6, 7, 8]], + ); + + expect(mtrx.sub( + [[[10], [12], [14]]], + [[[4], [5], [6]]], + )) + .toEqual( + [[[6], [7], [8]]], + ); + + expect(mtrx.sub( + [ + [10, 20], + [30, 40], + ], + [ + [5, 6], + [7, 8], + ], + )) + .toEqual( + [ + [5, 14], + [23, 32], + ], + ); + + expect(mtrx.sub( + [ + [[10], [20]], + [[30], [40]], + ], + [ + [[5], [6]], + [[7], [8]], + ], + )) + .toEqual( + [ + [[5], [14]], + [[23], [32]], + ], + ); + }); + + it('should throw when trying to subtract matrices element-wise of different shape', () => { + expect(() => mtrx.sub([[0]], [[[0]]])).toThrowError( + 'Matrices have different dimensions', + ); + + expect(() => mtrx.sub([[0]], [[0, 0]])).toThrowError( + 'Matrices have different shapes', + ); + }); +}); From 610f16fe209d78e9d14de245a0d92beb208f0da3 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sat, 19 Dec 2020 19:21:32 +0100 Subject: [PATCH 045/264] Add Euclidean Distance algorithm. --- README.md | 1 + .../math/euclidean-distance/README.md | 36 +++++++++++++++++++ .../__tests__/euclideanDistance.test.js | 23 ++++++++++++ .../euclidean-distance/euclideanDistance.js | 28 +++++++++++++++ src/algorithms/math/matrix/Matrix.js | 8 ++--- src/algorithms/ml/knn/__test__/knn.test.js | 2 +- src/algorithms/ml/knn/kNN.js | 25 +++---------- 7 files changed, 97 insertions(+), 26 deletions(-) create mode 100644 src/algorithms/math/euclidean-distance/README.md create mode 100644 src/algorithms/math/euclidean-distance/__tests__/euclideanDistance.test.js create mode 100644 src/algorithms/math/euclidean-distance/euclideanDistance.js diff --git a/README.md b/README.md index 454d70ff61..8f52db1d38 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Fast Powering](src/algorithms/math/fast-powering) * `B` [Horner's method](src/algorithms/math/horner-method) - polynomial evaluation * `B` [Matrices](src/algorithms/math/matrix) - matrices and basic matrix operations (multiplication, transposition, etc.) + * `B` [Euclidean Distance](src/algorithms/math/euclidean-distance) - distance between two points/vectors/matrices * `A` [Integer Partition](src/algorithms/math/integer-partition) * `A` [Square Root](src/algorithms/math/square-root) - Newton's method * `A` [Liu Hui π Algorithm](src/algorithms/math/liu-hui) - approximate π calculations based on N-gons diff --git a/src/algorithms/math/euclidean-distance/README.md b/src/algorithms/math/euclidean-distance/README.md new file mode 100644 index 0000000000..d67c217efe --- /dev/null +++ b/src/algorithms/math/euclidean-distance/README.md @@ -0,0 +1,36 @@ +# Euclidean Distance + +In mathematics, the **Euclidean distance** between two points in Euclidean space is the length of a line segment between the two points. It can be calculated from the Cartesian coordinates of the points using the Pythagorean theorem, therefore occasionally being called the Pythagorean distance. + +![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg) + +## Distance formulas + +### One dimension + +The distance between any two points on the real line is the absolute value of the numerical difference of their coordinates + +![One dimension formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/7d75418dbec9482dbcb70f9063ad66e9cf7b5db9) + +### Two dimensions + +![Two dimensions formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/9c0157084fd89f5f3d462efeedc47d3d7aa0b773) + +### Higher dimensions + +In three dimensions, for points given by their Cartesian coordinates, the distance is + +![Three dimensions formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/d1d13a40a7b203b455ae6d4be8b3cce898bda625) + +Example: the distance between the two points `(8,2,6)` and `(3,5,7)`: + +![3-dimension example](https://www.mathsisfun.com/algebra/images/dist-2-points-3d.svg) + +In general, for points given by Cartesian coordinates in `n`-dimensional Euclidean space, the distance is + +![n-dimensional formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/a0ef4fe055b2a51b4cca43a05e5d1cd93f758dcc) + +## References + +- [Euclidean Distance on MathIsFun](https://www.mathsisfun.com/algebra/distance-2-points.html) +- [Euclidean Distance on Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance) diff --git a/src/algorithms/math/euclidean-distance/__tests__/euclideanDistance.test.js b/src/algorithms/math/euclidean-distance/__tests__/euclideanDistance.test.js new file mode 100644 index 0000000000..78d7d8dc86 --- /dev/null +++ b/src/algorithms/math/euclidean-distance/__tests__/euclideanDistance.test.js @@ -0,0 +1,23 @@ +import euclideanDistance from '../euclideanDistance'; + +describe('euclideanDistance', () => { + it('should calculate euclidean distance between vectors', () => { + expect(euclideanDistance([[1]], [[2]])).toEqual(1); + expect(euclideanDistance([[2]], [[1]])).toEqual(1); + expect(euclideanDistance([[5, 8]], [[7, 3]])).toEqual(5.39); + expect(euclideanDistance([[5], [8]], [[7], [3]])).toEqual(5.39); + expect(euclideanDistance([[8, 2, 6]], [[3, 5, 7]])).toEqual(5.92); + expect(euclideanDistance([[8], [2], [6]], [[3], [5], [7]])).toEqual(5.92); + expect(euclideanDistance([[[8]], [[2]], [[6]]], [[[3]], [[5]], [[7]]])).toEqual(5.92); + }); + + it('should throw an error in case if two matrices are of different shapes', () => { + expect(() => euclideanDistance([[1]], [[[2]]])).toThrowError( + 'Matrices have different dimensions', + ); + + expect(() => euclideanDistance([[1]], [[2, 3]])).toThrowError( + 'Matrices have different shapes', + ); + }); +}); diff --git a/src/algorithms/math/euclidean-distance/euclideanDistance.js b/src/algorithms/math/euclidean-distance/euclideanDistance.js new file mode 100644 index 0000000000..afa5c2fece --- /dev/null +++ b/src/algorithms/math/euclidean-distance/euclideanDistance.js @@ -0,0 +1,28 @@ +/** + * @typedef {import('../matrix/Matrix.js').Matrix} Matrix + */ + +import * as mtrx from '../matrix/Matrix'; + +/** + * Calculates the euclidean distance between 2 matrices. + * + * @param {Matrix} a + * @param {Matrix} b + * @returns {number} + * @trows {Error} + */ +const euclideanDistance = (a, b) => { + mtrx.validateSameShape(a, b); + + let squaresTotal = 0; + + mtrx.walk(a, (indices, aCellValue) => { + const bCellValue = mtrx.getCellAtIndex(b, indices); + squaresTotal += (aCellValue - bCellValue) ** 2; + }); + + return Number(Math.sqrt(squaresTotal).toFixed(2)); +}; + +export default euclideanDistance; diff --git a/src/algorithms/math/matrix/Matrix.js b/src/algorithms/math/matrix/Matrix.js index 2470eb3913..2aee126ba2 100644 --- a/src/algorithms/math/matrix/Matrix.js +++ b/src/algorithms/math/matrix/Matrix.js @@ -58,7 +58,7 @@ const validate2D = (m) => { * @param {Matrix} b * @trows {Error} */ -const validateSameShape = (a, b) => { +export const validateSameShape = (a, b) => { validateType(a); validateType(b); @@ -177,7 +177,7 @@ export const t = (m) => { * @param {Matrix} m * @param {function(indices: CellIndices, c: Cell)} visit */ -const walk = (m, visit) => { +export const walk = (m, visit) => { /** * Traverses the matrix recursively. * @@ -208,7 +208,7 @@ const walk = (m, visit) => { * @param {CellIndices} cellIndices - Array of cell indices * @return {Cell} */ -const getCellAtIndex = (m, cellIndices) => { +export const getCellAtIndex = (m, cellIndices) => { // We start from the row at specific index. let cell = m[cellIndices[0]]; // Going deeper into the next dimensions but not to the last one to preserve @@ -227,7 +227,7 @@ const getCellAtIndex = (m, cellIndices) => { * @param {CellIndices} cellIndices - Array of cell indices * @param {Cell} cellValue - New cell value */ -const updateCellAtIndex = (m, cellIndices, cellValue) => { +export const updateCellAtIndex = (m, cellIndices, cellValue) => { // We start from the row at specific index. let cell = m[cellIndices[0]]; // Going deeper into the next dimensions but not to the last one to preserve diff --git a/src/algorithms/ml/knn/__test__/knn.test.js b/src/algorithms/ml/knn/__test__/knn.test.js index ccd69cd706..302bf3b7a9 100644 --- a/src/algorithms/ml/knn/__test__/knn.test.js +++ b/src/algorithms/ml/knn/__test__/knn.test.js @@ -25,7 +25,7 @@ describe('kNN', () => { const inconsistent = () => { kNN([[1, 1]], [1], [1]); }; - expect(inconsistent).toThrowError('Inconsistent vector lengths'); + expect(inconsistent).toThrowError('Matrices have different shapes'); }); it('should find the nearest neighbour', () => { diff --git a/src/algorithms/ml/knn/kNN.js b/src/algorithms/ml/knn/kNN.js index 24709af6f2..350e7ce176 100644 --- a/src/algorithms/ml/knn/kNN.js +++ b/src/algorithms/ml/knn/kNN.js @@ -1,23 +1,3 @@ -/** - * Calculates calculate the euclidean distance between 2 vectors. - * - * @param {number[]} x1 - * @param {number[]} x2 - * @returns {number} - */ -function euclideanDistance(x1, x2) { - // Checking for errors. - if (x1.length !== x2.length) { - throw new Error('Inconsistent vector lengths'); - } - // Calculate the euclidean distance between 2 vectors and return. - let squaresTotal = 0; - for (let i = 0; i < x1.length; i += 1) { - squaresTotal += (x1[i] - x2[i]) ** 2; - } - return Number(Math.sqrt(squaresTotal).toFixed(2)); -} - /** * Classifies the point in space based on k-nearest neighbors algorithm. * @@ -27,6 +7,9 @@ function euclideanDistance(x1, x2) { * @param {number} k - number of nearest neighbors which will be taken into account (preferably odd) * @return {number} - the class of the point */ + +import euclideanDistance from '../../math/euclidean-distance/euclideanDistance'; + export default function kNN( dataSet, labels, @@ -42,7 +25,7 @@ export default function kNN( const distances = []; for (let i = 0; i < dataSet.length; i += 1) { distances.push({ - dist: euclideanDistance(dataSet[i], toClassify), + dist: euclideanDistance([dataSet[i]], [toClassify]), label: labels[i], }); } From adda5c53b37c221573480ec6b949f0f424e4034f Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sat, 19 Dec 2020 19:26:02 +0100 Subject: [PATCH 046/264] Add Euclidean Distance formula (#602) * Add Matrices section with basic Matrix operations (multiplication, transposition, etc.) * Add Euclidean Distance algorithm. --- README.md | 1 + .../math/euclidean-distance/README.md | 36 +++++++++++++++++++ .../__tests__/euclideanDistance.test.js | 23 ++++++++++++ .../euclidean-distance/euclideanDistance.js | 28 +++++++++++++++ src/algorithms/math/matrix/Matrix.js | 8 ++--- src/algorithms/ml/knn/__test__/knn.test.js | 2 +- src/algorithms/ml/knn/kNN.js | 25 +++---------- 7 files changed, 97 insertions(+), 26 deletions(-) create mode 100644 src/algorithms/math/euclidean-distance/README.md create mode 100644 src/algorithms/math/euclidean-distance/__tests__/euclideanDistance.test.js create mode 100644 src/algorithms/math/euclidean-distance/euclideanDistance.js diff --git a/README.md b/README.md index 454d70ff61..8f52db1d38 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Fast Powering](src/algorithms/math/fast-powering) * `B` [Horner's method](src/algorithms/math/horner-method) - polynomial evaluation * `B` [Matrices](src/algorithms/math/matrix) - matrices and basic matrix operations (multiplication, transposition, etc.) + * `B` [Euclidean Distance](src/algorithms/math/euclidean-distance) - distance between two points/vectors/matrices * `A` [Integer Partition](src/algorithms/math/integer-partition) * `A` [Square Root](src/algorithms/math/square-root) - Newton's method * `A` [Liu Hui π Algorithm](src/algorithms/math/liu-hui) - approximate π calculations based on N-gons diff --git a/src/algorithms/math/euclidean-distance/README.md b/src/algorithms/math/euclidean-distance/README.md new file mode 100644 index 0000000000..d67c217efe --- /dev/null +++ b/src/algorithms/math/euclidean-distance/README.md @@ -0,0 +1,36 @@ +# Euclidean Distance + +In mathematics, the **Euclidean distance** between two points in Euclidean space is the length of a line segment between the two points. It can be calculated from the Cartesian coordinates of the points using the Pythagorean theorem, therefore occasionally being called the Pythagorean distance. + +![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg) + +## Distance formulas + +### One dimension + +The distance between any two points on the real line is the absolute value of the numerical difference of their coordinates + +![One dimension formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/7d75418dbec9482dbcb70f9063ad66e9cf7b5db9) + +### Two dimensions + +![Two dimensions formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/9c0157084fd89f5f3d462efeedc47d3d7aa0b773) + +### Higher dimensions + +In three dimensions, for points given by their Cartesian coordinates, the distance is + +![Three dimensions formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/d1d13a40a7b203b455ae6d4be8b3cce898bda625) + +Example: the distance between the two points `(8,2,6)` and `(3,5,7)`: + +![3-dimension example](https://www.mathsisfun.com/algebra/images/dist-2-points-3d.svg) + +In general, for points given by Cartesian coordinates in `n`-dimensional Euclidean space, the distance is + +![n-dimensional formula](https://wikimedia.org/api/rest_v1/media/math/render/svg/a0ef4fe055b2a51b4cca43a05e5d1cd93f758dcc) + +## References + +- [Euclidean Distance on MathIsFun](https://www.mathsisfun.com/algebra/distance-2-points.html) +- [Euclidean Distance on Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance) diff --git a/src/algorithms/math/euclidean-distance/__tests__/euclideanDistance.test.js b/src/algorithms/math/euclidean-distance/__tests__/euclideanDistance.test.js new file mode 100644 index 0000000000..78d7d8dc86 --- /dev/null +++ b/src/algorithms/math/euclidean-distance/__tests__/euclideanDistance.test.js @@ -0,0 +1,23 @@ +import euclideanDistance from '../euclideanDistance'; + +describe('euclideanDistance', () => { + it('should calculate euclidean distance between vectors', () => { + expect(euclideanDistance([[1]], [[2]])).toEqual(1); + expect(euclideanDistance([[2]], [[1]])).toEqual(1); + expect(euclideanDistance([[5, 8]], [[7, 3]])).toEqual(5.39); + expect(euclideanDistance([[5], [8]], [[7], [3]])).toEqual(5.39); + expect(euclideanDistance([[8, 2, 6]], [[3, 5, 7]])).toEqual(5.92); + expect(euclideanDistance([[8], [2], [6]], [[3], [5], [7]])).toEqual(5.92); + expect(euclideanDistance([[[8]], [[2]], [[6]]], [[[3]], [[5]], [[7]]])).toEqual(5.92); + }); + + it('should throw an error in case if two matrices are of different shapes', () => { + expect(() => euclideanDistance([[1]], [[[2]]])).toThrowError( + 'Matrices have different dimensions', + ); + + expect(() => euclideanDistance([[1]], [[2, 3]])).toThrowError( + 'Matrices have different shapes', + ); + }); +}); diff --git a/src/algorithms/math/euclidean-distance/euclideanDistance.js b/src/algorithms/math/euclidean-distance/euclideanDistance.js new file mode 100644 index 0000000000..afa5c2fece --- /dev/null +++ b/src/algorithms/math/euclidean-distance/euclideanDistance.js @@ -0,0 +1,28 @@ +/** + * @typedef {import('../matrix/Matrix.js').Matrix} Matrix + */ + +import * as mtrx from '../matrix/Matrix'; + +/** + * Calculates the euclidean distance between 2 matrices. + * + * @param {Matrix} a + * @param {Matrix} b + * @returns {number} + * @trows {Error} + */ +const euclideanDistance = (a, b) => { + mtrx.validateSameShape(a, b); + + let squaresTotal = 0; + + mtrx.walk(a, (indices, aCellValue) => { + const bCellValue = mtrx.getCellAtIndex(b, indices); + squaresTotal += (aCellValue - bCellValue) ** 2; + }); + + return Number(Math.sqrt(squaresTotal).toFixed(2)); +}; + +export default euclideanDistance; diff --git a/src/algorithms/math/matrix/Matrix.js b/src/algorithms/math/matrix/Matrix.js index 2470eb3913..2aee126ba2 100644 --- a/src/algorithms/math/matrix/Matrix.js +++ b/src/algorithms/math/matrix/Matrix.js @@ -58,7 +58,7 @@ const validate2D = (m) => { * @param {Matrix} b * @trows {Error} */ -const validateSameShape = (a, b) => { +export const validateSameShape = (a, b) => { validateType(a); validateType(b); @@ -177,7 +177,7 @@ export const t = (m) => { * @param {Matrix} m * @param {function(indices: CellIndices, c: Cell)} visit */ -const walk = (m, visit) => { +export const walk = (m, visit) => { /** * Traverses the matrix recursively. * @@ -208,7 +208,7 @@ const walk = (m, visit) => { * @param {CellIndices} cellIndices - Array of cell indices * @return {Cell} */ -const getCellAtIndex = (m, cellIndices) => { +export const getCellAtIndex = (m, cellIndices) => { // We start from the row at specific index. let cell = m[cellIndices[0]]; // Going deeper into the next dimensions but not to the last one to preserve @@ -227,7 +227,7 @@ const getCellAtIndex = (m, cellIndices) => { * @param {CellIndices} cellIndices - Array of cell indices * @param {Cell} cellValue - New cell value */ -const updateCellAtIndex = (m, cellIndices, cellValue) => { +export const updateCellAtIndex = (m, cellIndices, cellValue) => { // We start from the row at specific index. let cell = m[cellIndices[0]]; // Going deeper into the next dimensions but not to the last one to preserve diff --git a/src/algorithms/ml/knn/__test__/knn.test.js b/src/algorithms/ml/knn/__test__/knn.test.js index ccd69cd706..302bf3b7a9 100644 --- a/src/algorithms/ml/knn/__test__/knn.test.js +++ b/src/algorithms/ml/knn/__test__/knn.test.js @@ -25,7 +25,7 @@ describe('kNN', () => { const inconsistent = () => { kNN([[1, 1]], [1], [1]); }; - expect(inconsistent).toThrowError('Inconsistent vector lengths'); + expect(inconsistent).toThrowError('Matrices have different shapes'); }); it('should find the nearest neighbour', () => { diff --git a/src/algorithms/ml/knn/kNN.js b/src/algorithms/ml/knn/kNN.js index 24709af6f2..350e7ce176 100644 --- a/src/algorithms/ml/knn/kNN.js +++ b/src/algorithms/ml/knn/kNN.js @@ -1,23 +1,3 @@ -/** - * Calculates calculate the euclidean distance between 2 vectors. - * - * @param {number[]} x1 - * @param {number[]} x2 - * @returns {number} - */ -function euclideanDistance(x1, x2) { - // Checking for errors. - if (x1.length !== x2.length) { - throw new Error('Inconsistent vector lengths'); - } - // Calculate the euclidean distance between 2 vectors and return. - let squaresTotal = 0; - for (let i = 0; i < x1.length; i += 1) { - squaresTotal += (x1[i] - x2[i]) ** 2; - } - return Number(Math.sqrt(squaresTotal).toFixed(2)); -} - /** * Classifies the point in space based on k-nearest neighbors algorithm. * @@ -27,6 +7,9 @@ function euclideanDistance(x1, x2) { * @param {number} k - number of nearest neighbors which will be taken into account (preferably odd) * @return {number} - the class of the point */ + +import euclideanDistance from '../../math/euclidean-distance/euclideanDistance'; + export default function kNN( dataSet, labels, @@ -42,7 +25,7 @@ export default function kNN( const distances = []; for (let i = 0; i < dataSet.length; i += 1) { distances.push({ - dist: euclideanDistance(dataSet[i], toClassify), + dist: euclideanDistance([dataSet[i]], [toClassify]), label: labels[i], }); } From 3e5ddb81431a9967fe1eb28328709ea2c320a48e Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sat, 19 Dec 2020 19:32:57 +0100 Subject: [PATCH 047/264] Adding the Matrix traversal and generation to the Divide and Conquer section. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8f52db1d38..8e26125c1e 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,7 @@ algorithm is an abstraction higher than a computer program. * `B` [Quicksort](src/algorithms/sorting/quick-sort) * `B` [Tree Depth-First Search](src/algorithms/tree/depth-first-search) (DFS) * `B` [Graph Depth-First Search](src/algorithms/graph/depth-first-search) (DFS) + * `B` [Matrices](src/algorithms/math/matrix) - generating and traversing the matrices of different depths * `B` [Jump Game](src/algorithms/uncategorized/jump-game) * `B` [Fast Powering](src/algorithms/math/fast-powering) * `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions) From 636ebe1e268b1aeb226072c3285e5e3f28813e59 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sat, 19 Dec 2020 19:33:35 +0100 Subject: [PATCH 048/264] Adding the Matrix traversal and generation to the Divide and Conquer section. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8e26125c1e..4d88a064db 100644 --- a/README.md +++ b/README.md @@ -185,7 +185,7 @@ algorithm is an abstraction higher than a computer program. * `B` [Quicksort](src/algorithms/sorting/quick-sort) * `B` [Tree Depth-First Search](src/algorithms/tree/depth-first-search) (DFS) * `B` [Graph Depth-First Search](src/algorithms/graph/depth-first-search) (DFS) - * `B` [Matrices](src/algorithms/math/matrix) - generating and traversing the matrices of different depths + * `B` [Matrices](src/algorithms/math/matrix) - generating and traversing the matrices of different shapes * `B` [Jump Game](src/algorithms/uncategorized/jump-game) * `B` [Fast Powering](src/algorithms/math/fast-powering) * `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions) From b7cd425ce9a3fc0238321e717c26505335764322 Mon Sep 17 00:00:00 2001 From: Avi Agrawal <39293511+avi09@users.noreply.github.com> Date: Sat, 19 Dec 2020 13:36:08 -0500 Subject: [PATCH 049/264] Added kmeans clustering (#595) * added kmeans * added kmeans * added kmeans Co-authored-by: Oleksii Trekhleb --- README.md | 1 + src/algorithms/ml/kmeans/README.md | 32 ++++++ .../ml/kmeans/__test__/kmeans.test.js | 36 +++++++ src/algorithms/ml/kmeans/kmeans.js | 98 +++++++++++++++++++ 4 files changed, 167 insertions(+) create mode 100644 src/algorithms/ml/kmeans/README.md create mode 100644 src/algorithms/ml/kmeans/__test__/kmeans.test.js create mode 100644 src/algorithms/ml/kmeans/kmeans.js diff --git a/README.md b/README.md index 4d88a064db..11be805ae5 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,7 @@ a set of rules that precisely define a sequence of operations. * **Machine Learning** * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation) * `B` [k-NN](src/algorithms/ml/knn) - k-nearest neighbors classification algorithm + * `B` [k-Means](src/algorithms/ml/kmeans) - k-Means clustering algorithm * **Uncategorized** * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower) * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm diff --git a/src/algorithms/ml/kmeans/README.md b/src/algorithms/ml/kmeans/README.md new file mode 100644 index 0000000000..1c0d53ee8c --- /dev/null +++ b/src/algorithms/ml/kmeans/README.md @@ -0,0 +1,32 @@ +# k-Means Algorithm + +The **k-Means algorithm** is an unsupervised Machine Learning algorithm. It's a clustering algorithm, which groups the sample data on the basis of similarity between dimentions of vectors. + +In k-Means classification, the output is a set of classess asssigned to each vector. Each cluster location is continously optimized in order to get the accurate locations of each cluster such that they represent each group clearly. + +The idea is to calculate the similarity between cluster location and data vectors, and reassign clusters based on it. [Euclidean distance](https://en.wikipedia.org/wiki/Euclidean_distance) is used mostly for this task. + +![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg) + +_Image source: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_ + +The algorithm is as follows: + +1. Check for errors like invalid/inconsistent data +2. Initialize the k cluster locations with initial/random k points +3. Calculate the distance of each data point from each cluster +4. Assign the cluster label of each data point equal to that of the cluster at it's minimum distance +5. Calculate the centroid of each cluster based on the data points it contains +6. Repeat each of the above steps until the centroid locations are varying + +Here is a visualization of k-Means clustering for better understanding: + +![KNN Visualization 1](https://upload.wikimedia.org/wikipedia/commons/e/ea/K-means_convergence.gif) + +_Image source: [Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)_ + +The centroids are moving continously in order to create better distinction between the different set of data points. As we can see, after a few iterations, the difference in centroids is quite low between iterations. For example between itrations `13` and `14` the difference is quite small because there the optimizer is tuning boundary cases. + +## References + +- [k-Means neighbors algorithm on Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering) diff --git a/src/algorithms/ml/kmeans/__test__/kmeans.test.js b/src/algorithms/ml/kmeans/__test__/kmeans.test.js new file mode 100644 index 0000000000..ed90e9f78e --- /dev/null +++ b/src/algorithms/ml/kmeans/__test__/kmeans.test.js @@ -0,0 +1,36 @@ +import kMeans from '../kmeans'; + +describe('kMeans', () => { + it('should throw an error on invalid data', () => { + expect(() => { + kMeans(); + }).toThrowError('Either dataSet or labels or toClassify were not set'); + }); + + it('should throw an error on inconsistent data', () => { + expect(() => { + kMeans([[1, 2], [1]], 2); + }).toThrowError('Inconsistent vector lengths'); + }); + + it('should find the nearest neighbour', () => { + const dataSet = [[1, 1], [6, 2], [3, 3], [4, 5], [9, 2], [2, 4], [8, 7]]; + const k = 2; + const expectedCluster = [0, 1, 0, 1, 1, 0, 1]; + expect(kMeans(dataSet, k)).toEqual(expectedCluster); + }); + + it('should find the clusters with equal distances', () => { + const dataSet = [[0, 0], [1, 1], [2, 2]]; + const k = 3; + const expectedCluster = [0, 1, 2]; + expect(kMeans(dataSet, k)).toEqual(expectedCluster); + }); + + it('should find the nearest neighbour in 3D space', () => { + const dataSet = [[0, 0, 0], [0, 1, 0], [2, 0, 2]]; + const k = 2; + const expectedCluster = [1, 1, 0]; + expect(kMeans(dataSet, k)).toEqual(expectedCluster); + }); +}); diff --git a/src/algorithms/ml/kmeans/kmeans.js b/src/algorithms/ml/kmeans/kmeans.js new file mode 100644 index 0000000000..099ddab558 --- /dev/null +++ b/src/algorithms/ml/kmeans/kmeans.js @@ -0,0 +1,98 @@ +/** + * Calculates calculate the euclidean distance between 2 vectors. + * + * @param {number[]} x1 + * @param {number[]} x2 + * @returns {number} + */ +function euclideanDistance(x1, x2) { + // Checking for errors. + if (x1.length !== x2.length) { + throw new Error('Inconsistent vector lengths'); + } + // Calculate the euclidean distance between 2 vectors and return. + let squaresTotal = 0; + for (let i = 0; i < x1.length; i += 1) { + squaresTotal += (x1[i] - x2[i]) ** 2; + } + return Number(Math.sqrt(squaresTotal).toFixed(2)); +} +/** + * Classifies the point in space based on k-nearest neighbors algorithm. + * + * @param {number[][]} dataSet - array of dataSet points, i.e. [[0, 1], [3, 4], [5, 7]] + * @param {number} k - number of nearest neighbors which will be taken into account (preferably odd) + * @return {number[]} - the class of the point + */ +export default function kMeans( + dataSetm, + k = 1, +) { + const dataSet = dataSetm; + if (!dataSet) { + throw new Error('Either dataSet or labels or toClassify were not set'); + } + + // starting algorithm + // assign k clusters locations equal to the location of initial k points + const clusterCenters = []; + const nDim = dataSet[0].length; + for (let i = 0; i < k; i += 1) { + clusterCenters[clusterCenters.length] = Array.from(dataSet[i]); + } + + // continue optimization till convergence + // centroids should not be moving once optimized + // calculate distance of each candidate vector from each cluster center + // assign cluster number to each data vector according to minimum distance + let flag = true; + while (flag) { + flag = false; + // calculate and store distance of each dataSet point from each cluster + for (let i = 0; i < dataSet.length; i += 1) { + for (let n = 0; n < k; n += 1) { + dataSet[i][nDim + n] = euclideanDistance(clusterCenters[n], dataSet[i].slice(0, nDim)); + } + + // assign the cluster number to each dataSet point + const sliced = dataSet[i].slice(nDim, nDim + k); + let minmDistCluster = Math.min(...sliced); + for (let j = 0; j < sliced.length; j += 1) { + if (minmDistCluster === sliced[j]) { + minmDistCluster = j; + break; + } + } + + if (dataSet[i].length !== nDim + k + 1) { + flag = true; + dataSet[i][nDim + k] = minmDistCluster; + } else if (dataSet[i][nDim + k] !== minmDistCluster) { + flag = true; + dataSet[i][nDim + k] = minmDistCluster; + } + } + // recalculate cluster centriod values via all dimensions of the points under it + for (let i = 0; i < k; i += 1) { + clusterCenters[i] = Array(nDim).fill(0); + let classCount = 0; + for (let j = 0; j < dataSet.length; j += 1) { + if (dataSet[j][dataSet[j].length - 1] === i) { + classCount += 1; + for (let n = 0; n < nDim; n += 1) { + clusterCenters[i][n] += dataSet[j][n]; + } + } + } + for (let n = 0; n < nDim; n += 1) { + clusterCenters[i][n] = Number((clusterCenters[i][n] / classCount).toFixed(2)); + } + } + } + // return the clusters assigned + const soln = []; + for (let i = 0; i < dataSet.length; i += 1) { + soln.push(dataSet[i][dataSet[i].length - 1]); + } + return soln; +} From 569fd95bd08c1a0cb3f21cfeaa9f7324d86902ce Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sat, 19 Dec 2020 21:13:11 +0100 Subject: [PATCH 050/264] Simplify k-Means clustering algorithm. --- README.md | 2 +- .../ml/{kmeans => k-means}/README.md | 14 +-- .../__test__/kMeans.test.js} | 24 +++-- src/algorithms/ml/k-means/kMeans.js | 85 ++++++++++++++++ src/algorithms/ml/kmeans/kmeans.js | 98 ------------------- 5 files changed, 107 insertions(+), 116 deletions(-) rename src/algorithms/ml/{kmeans => k-means}/README.md (53%) rename src/algorithms/ml/{kmeans/__test__/kmeans.test.js => k-means/__test__/kMeans.test.js} (52%) create mode 100644 src/algorithms/ml/k-means/kMeans.js delete mode 100644 src/algorithms/ml/kmeans/kmeans.js diff --git a/README.md b/README.md index 11be805ae5..ffec78a9e2 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,7 @@ a set of rules that precisely define a sequence of operations. * **Machine Learning** * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation) * `B` [k-NN](src/algorithms/ml/knn) - k-nearest neighbors classification algorithm - * `B` [k-Means](src/algorithms/ml/kmeans) - k-Means clustering algorithm + * `B` [k-Means](src/algorithms/ml/k-means) - k-Means clustering algorithm * **Uncategorized** * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower) * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm diff --git a/src/algorithms/ml/kmeans/README.md b/src/algorithms/ml/k-means/README.md similarity index 53% rename from src/algorithms/ml/kmeans/README.md rename to src/algorithms/ml/k-means/README.md index 1c0d53ee8c..aebd60e100 100644 --- a/src/algorithms/ml/kmeans/README.md +++ b/src/algorithms/ml/k-means/README.md @@ -1,10 +1,10 @@ # k-Means Algorithm -The **k-Means algorithm** is an unsupervised Machine Learning algorithm. It's a clustering algorithm, which groups the sample data on the basis of similarity between dimentions of vectors. +The **k-Means algorithm** is an unsupervised Machine Learning algorithm. It's a clustering algorithm, which groups the sample data on the basis of similarity between dimensions of vectors. -In k-Means classification, the output is a set of classess asssigned to each vector. Each cluster location is continously optimized in order to get the accurate locations of each cluster such that they represent each group clearly. +In k-Means classification, the output is a set of classes assigned to each vector. Each cluster location is continuously optimized in order to get the accurate locations of each cluster such that they represent each group clearly. -The idea is to calculate the similarity between cluster location and data vectors, and reassign clusters based on it. [Euclidean distance](https://en.wikipedia.org/wiki/Euclidean_distance) is used mostly for this task. +The idea is to calculate the similarity between cluster location and data vectors, and reassign clusters based on it. [Euclidean distance](https://github.com/trekhleb/javascript-algorithms/tree/master/src/algorithms/math/euclidean-distance) is used mostly for this task. ![Euclidean distance between two points](https://upload.wikimedia.org/wikipedia/commons/5/55/Euclidean_distance_2d.svg) @@ -13,9 +13,9 @@ _Image source: [Wikipedia](https://en.wikipedia.org/wiki/Euclidean_distance)_ The algorithm is as follows: 1. Check for errors like invalid/inconsistent data -2. Initialize the k cluster locations with initial/random k points +2. Initialize the `k` cluster locations with initial/random `k` points 3. Calculate the distance of each data point from each cluster -4. Assign the cluster label of each data point equal to that of the cluster at it's minimum distance +4. Assign the cluster label of each data point equal to that of the cluster at its minimum distance 5. Calculate the centroid of each cluster based on the data points it contains 6. Repeat each of the above steps until the centroid locations are varying @@ -23,9 +23,9 @@ Here is a visualization of k-Means clustering for better understanding: ![KNN Visualization 1](https://upload.wikimedia.org/wikipedia/commons/e/ea/K-means_convergence.gif) -_Image source: [Wikipedia](https://en.wikipedia.org/wiki/K-nearest_neighbors_algorithm)_ +_Image source: [Wikipedia](https://en.wikipedia.org/wiki/K-means_clustering)_ -The centroids are moving continously in order to create better distinction between the different set of data points. As we can see, after a few iterations, the difference in centroids is quite low between iterations. For example between itrations `13` and `14` the difference is quite small because there the optimizer is tuning boundary cases. +The centroids are moving continuously in order to create better distinction between the different set of data points. As we can see, after a few iterations, the difference in centroids is quite low between iterations. For example between iterations `13` and `14` the difference is quite small because there the optimizer is tuning boundary cases. ## References diff --git a/src/algorithms/ml/kmeans/__test__/kmeans.test.js b/src/algorithms/ml/k-means/__test__/kMeans.test.js similarity index 52% rename from src/algorithms/ml/kmeans/__test__/kmeans.test.js rename to src/algorithms/ml/k-means/__test__/kMeans.test.js index ed90e9f78e..44a6f538e2 100644 --- a/src/algorithms/ml/kmeans/__test__/kmeans.test.js +++ b/src/algorithms/ml/k-means/__test__/kMeans.test.js @@ -1,36 +1,40 @@ -import kMeans from '../kmeans'; +import KMeans from '../kMeans'; describe('kMeans', () => { it('should throw an error on invalid data', () => { expect(() => { - kMeans(); - }).toThrowError('Either dataSet or labels or toClassify were not set'); + KMeans(); + }).toThrowError('The data is empty'); }); it('should throw an error on inconsistent data', () => { expect(() => { - kMeans([[1, 2], [1]], 2); - }).toThrowError('Inconsistent vector lengths'); + KMeans([[1, 2], [1]], 2); + }).toThrowError('Matrices have different shapes'); }); it('should find the nearest neighbour', () => { - const dataSet = [[1, 1], [6, 2], [3, 3], [4, 5], [9, 2], [2, 4], [8, 7]]; + const data = [[1, 1], [6, 2], [3, 3], [4, 5], [9, 2], [2, 4], [8, 7]]; const k = 2; - const expectedCluster = [0, 1, 0, 1, 1, 0, 1]; - expect(kMeans(dataSet, k)).toEqual(expectedCluster); + const expectedClusters = [0, 1, 0, 1, 1, 0, 1]; + expect(KMeans(data, k)).toEqual(expectedClusters); + + expect(KMeans([[0, 0], [0, 1], [10, 10]], 2)).toEqual( + [0, 0, 1], + ); }); it('should find the clusters with equal distances', () => { const dataSet = [[0, 0], [1, 1], [2, 2]]; const k = 3; const expectedCluster = [0, 1, 2]; - expect(kMeans(dataSet, k)).toEqual(expectedCluster); + expect(KMeans(dataSet, k)).toEqual(expectedCluster); }); it('should find the nearest neighbour in 3D space', () => { const dataSet = [[0, 0, 0], [0, 1, 0], [2, 0, 2]]; const k = 2; const expectedCluster = [1, 1, 0]; - expect(kMeans(dataSet, k)).toEqual(expectedCluster); + expect(KMeans(dataSet, k)).toEqual(expectedCluster); }); }); diff --git a/src/algorithms/ml/k-means/kMeans.js b/src/algorithms/ml/k-means/kMeans.js new file mode 100644 index 0000000000..4361eed689 --- /dev/null +++ b/src/algorithms/ml/k-means/kMeans.js @@ -0,0 +1,85 @@ +import * as mtrx from '../../math/matrix/Matrix'; +import euclideanDistance from '../../math/euclidean-distance/euclideanDistance'; + +/** + * Classifies the point in space based on k-Means algorithm. + * + * @param {number[][]} data - array of dataSet points, i.e. [[0, 1], [3, 4], [5, 7]] + * @param {number} k - number of clusters + * @return {number[]} - the class of the point + */ +export default function KMeans( + data, + k = 1, +) { + if (!data) { + throw new Error('The data is empty'); + } + + // Assign k clusters locations equal to the location of initial k points. + const dataDim = data[0].length; + const clusterCenters = data.slice(0, k); + + // Continue optimization till convergence. + // Centroids should not be moving once optimized. + // Calculate distance of each candidate vector from each cluster center. + // Assign cluster number to each data vector according to minimum distance. + + // Matrix of distance from each data point to each cluster centroid. + const distances = mtrx.zeros([data.length, k]); + + // Vector data points' classes. The value of -1 means that no class has bee assigned yet. + const classes = Array(data.length).fill(-1); + + let iterate = true; + while (iterate) { + iterate = false; + + // Calculate and store the distance of each data point from each cluster. + for (let dataIndex = 0; dataIndex < data.length; dataIndex += 1) { + for (let clusterIndex = 0; clusterIndex < k; clusterIndex += 1) { + distances[dataIndex][clusterIndex] = euclideanDistance( + [clusterCenters[clusterIndex]], + [data[dataIndex]], + ); + } + // Assign the closest cluster number to each dataSet point. + const closestClusterIdx = distances[dataIndex].indexOf( + Math.min(...distances[dataIndex]), + ); + + // Check if data point class has been changed and we still need to re-iterate. + if (classes[dataIndex] !== closestClusterIdx) { + iterate = true; + } + + classes[dataIndex] = closestClusterIdx; + } + + // Recalculate cluster centroid values via all dimensions of the points under it. + for (let clusterIndex = 0; clusterIndex < k; clusterIndex += 1) { + // Reset cluster center coordinates since we need to recalculate them. + clusterCenters[clusterIndex] = Array(dataDim).fill(0); + let clusterSize = 0; + for (let dataIndex = 0; dataIndex < data.length; dataIndex += 1) { + if (classes[dataIndex] === clusterIndex) { + // Register one more data point of current cluster. + clusterSize += 1; + for (let dimensionIndex = 0; dimensionIndex < dataDim; dimensionIndex += 1) { + // Add data point coordinates to the cluster center coordinates. + clusterCenters[clusterIndex][dimensionIndex] += data[dataIndex][dimensionIndex]; + } + } + } + // Calculate the average for each cluster center coordinate. + for (let dimensionIndex = 0; dimensionIndex < dataDim; dimensionIndex += 1) { + clusterCenters[clusterIndex][dimensionIndex] = parseFloat(Number( + clusterCenters[clusterIndex][dimensionIndex] / clusterSize, + ).toFixed(2)); + } + } + } + + // Return the clusters assigned. + return classes; +} diff --git a/src/algorithms/ml/kmeans/kmeans.js b/src/algorithms/ml/kmeans/kmeans.js deleted file mode 100644 index 099ddab558..0000000000 --- a/src/algorithms/ml/kmeans/kmeans.js +++ /dev/null @@ -1,98 +0,0 @@ -/** - * Calculates calculate the euclidean distance between 2 vectors. - * - * @param {number[]} x1 - * @param {number[]} x2 - * @returns {number} - */ -function euclideanDistance(x1, x2) { - // Checking for errors. - if (x1.length !== x2.length) { - throw new Error('Inconsistent vector lengths'); - } - // Calculate the euclidean distance between 2 vectors and return. - let squaresTotal = 0; - for (let i = 0; i < x1.length; i += 1) { - squaresTotal += (x1[i] - x2[i]) ** 2; - } - return Number(Math.sqrt(squaresTotal).toFixed(2)); -} -/** - * Classifies the point in space based on k-nearest neighbors algorithm. - * - * @param {number[][]} dataSet - array of dataSet points, i.e. [[0, 1], [3, 4], [5, 7]] - * @param {number} k - number of nearest neighbors which will be taken into account (preferably odd) - * @return {number[]} - the class of the point - */ -export default function kMeans( - dataSetm, - k = 1, -) { - const dataSet = dataSetm; - if (!dataSet) { - throw new Error('Either dataSet or labels or toClassify were not set'); - } - - // starting algorithm - // assign k clusters locations equal to the location of initial k points - const clusterCenters = []; - const nDim = dataSet[0].length; - for (let i = 0; i < k; i += 1) { - clusterCenters[clusterCenters.length] = Array.from(dataSet[i]); - } - - // continue optimization till convergence - // centroids should not be moving once optimized - // calculate distance of each candidate vector from each cluster center - // assign cluster number to each data vector according to minimum distance - let flag = true; - while (flag) { - flag = false; - // calculate and store distance of each dataSet point from each cluster - for (let i = 0; i < dataSet.length; i += 1) { - for (let n = 0; n < k; n += 1) { - dataSet[i][nDim + n] = euclideanDistance(clusterCenters[n], dataSet[i].slice(0, nDim)); - } - - // assign the cluster number to each dataSet point - const sliced = dataSet[i].slice(nDim, nDim + k); - let minmDistCluster = Math.min(...sliced); - for (let j = 0; j < sliced.length; j += 1) { - if (minmDistCluster === sliced[j]) { - minmDistCluster = j; - break; - } - } - - if (dataSet[i].length !== nDim + k + 1) { - flag = true; - dataSet[i][nDim + k] = minmDistCluster; - } else if (dataSet[i][nDim + k] !== minmDistCluster) { - flag = true; - dataSet[i][nDim + k] = minmDistCluster; - } - } - // recalculate cluster centriod values via all dimensions of the points under it - for (let i = 0; i < k; i += 1) { - clusterCenters[i] = Array(nDim).fill(0); - let classCount = 0; - for (let j = 0; j < dataSet.length; j += 1) { - if (dataSet[j][dataSet[j].length - 1] === i) { - classCount += 1; - for (let n = 0; n < nDim; n += 1) { - clusterCenters[i][n] += dataSet[j][n]; - } - } - } - for (let n = 0; n < nDim; n += 1) { - clusterCenters[i][n] = Number((clusterCenters[i][n] / classCount).toFixed(2)); - } - } - } - // return the clusters assigned - const soln = []; - for (let i = 0; i < dataSet.length; i += 1) { - soln.push(dataSet[i][dataSet[i].length - 1]); - } - return soln; -} From 4bc72734269daa6f8d39f429944b264d94b9f9e3 Mon Sep 17 00:00:00 2001 From: Adjie Djaka Permana Date: Sun, 20 Dec 2020 18:52:01 +0700 Subject: [PATCH 051/264] feat(lang): add README.id-ID.md translation for Bahasa Indonesia (#603) --- README.id-ID.md | 303 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 303 insertions(+) create mode 100644 README.id-ID.md diff --git a/README.id-ID.md b/README.id-ID.md new file mode 100644 index 0000000000..784fb76961 --- /dev/null +++ b/README.id-ID.md @@ -0,0 +1,303 @@ +# Algoritme dan Struktur Data Javascript + +[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) + +Repositori ini berisi contoh-contoh algoritme dan struktur data yang populer menggunakan JavaScript. + +Setiap algoritme dan struktur data memiliki README-nya tersendiri dengan penjelasan yang berkaitan dan tautan untuk bacaan lebih lanjut (termasuk tautan menuju video YouTube). + +_Baca ini dalam bahasa yang lain:_ +[_English_](https://github.com/trekhleb/javascript-algorithms/), +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_한국어_](README.ko-KR.md), +[_日本語_](README.ja-JP.md), +[_Polski_](README.pl-PL.md), +[_Français_](README.fr-FR.md), +[_Español_](README.es-ES.md), +[_Português_](README.pt-BR.md), +[_Русский_](README.ru-RU.md), +[_Türk_](README.tr-TR.md), +[_Italiana_](README.it-IT.md) + +_☝ Perhatikan bahwa proyek ini hanya dimaksudkan untuk tujuan pembelajaran dan riset, dan **tidak** dimaksudkan untuk digunakan sebagai produksi._ + +## Struktur Data + +Struktur data adalah cara tertentu untuk mengatur dan menyimpan data dalam komputer sehingga dapat diakses dan diubah secara efisien. Lebih tepatnya, struktur data adalah kumpulan dari nilai data, relasi di antara data-data, dan fungsi atau operasi yang dapat diterapkan pada data. + +`P` - Pemula, `L` - Lanjutan + +- `P` [Senarai Berantai](src/data-structures/linked-list) +- `P` [Senarai Berantai Ganda](src/data-structures/doubly-linked-list) +- `P` [Antrean](src/data-structures/queue) +- `P` [Tumpukan](src/data-structures/stack) +- `P` [Tabel Hash](src/data-structures/hash-table) +- `P` [_Heap_](src/data-structures/heap) - versi _heap_ maksimum dan minimum +- `P` [Antrean Prioritas](src/data-structures/priority-queue) +- `L` [_Trie_](src/data-structures/trie) +- `L` [Pohon](src/data-structures/tree) + - `L` [Pohon Telusur Biner](src/data-structures/tree/binary-search-tree) + - `L` [_AVL Tree_](src/data-structures/tree/avl-tree) + - `L` [Pohon Merah Hitam](src/data-structures/tree/red-black-tree) + - `L` [_Segment Tree_](src/data-structures/tree/segment-tree) - dengan contoh min/max/sum range query + - `L` [Pohon Fenwick](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree) +- `L` [Graf](src/data-structures/graph) (directed dan undirected) +- `L` [_Disjoint Set_](src/data-structures/disjoint-set) +- `L` [_Bloom Filter_](src/data-structures/bloom-filter) + +## Algoritme + +Algoritme adalah sebuah perincian yang jelas tentang cara untuk memecahkan suatu masalah. Ia adalah sekumpulan aturan yang menjelaskan secara tepat urutan-urutan dari sebuah operasi. + +`P` - Pemula, `L` - Lanjutan + +### Algoritme Berdasarkanan Topik + +- **Matematika** + - `P` [Manipulasi Bit](src/algorithms/math/bits) - menetapkan/mendapatkan/memperbarui/mengahpus bit, perkalian/pembagian dengan angka 2, membuat bilangan negatif etc. + - `P` [Faktorial](src/algorithms/math/Faktorial) + - `P` [Bilangan Fibonacci](src/algorithms/math/fibonacci) - versi klasik dan bentuk tertutup + - `P` [Faktor Prima](src/algorithms/math/prime-factors) - menemukan faktor prima dan menghitungnya menggunakan teorema Hardy-Ramanujan + - `P` [Pengujian Bilangan Prima](src/algorithms/math/primality-test) (metode _trial division_) + - `P` [Algoritme Euclidean](src/algorithms/math/euclidean-algorithm) - menghitung Faktor Persekutuan Terbesar (FPB) + - `P` [_Least Common Multiple_](src/algorithms/math/least-common-multiple) (LCM) + - `P` [_Sieve of Eratosthenes_](src/algorithms/math/sieve-of-eratosthenes) - menemukan semua bilangan prima hingga batas yang ditentukan + - `P` [_Is Power of Two_](src/algorithms/math/is-power-of-two) - mengecek apakah sebuah bilangan adalah hasil dari pangkat dua (algoritme _naive_ dan _bitwise_) + - `P` [Segitiga Pascal](src/algorithms/math/pascal-triangle) + - `P` [Bilangan Kompleks](src/algorithms/math/complex-number) - bilangan kompleks dengan operasi dasarnya + - `P` [Radian & Derajat](src/algorithms/math/radian) - konversi radian ke derajat dan sebaliknya + - `P` [_Fast Powering_](src/algorithms/math/fast-powering) + - `P` [Metode Horner](src/algorithms/math/horner-method) - evaluasi polinomial + - `L` [Partisi Bilangan Bulat](src/algorithms/math/integer-partition) + - `L` [Akar Pangkat Dua](src/algorithms/math/square-root) - metode Newton + - `L` [Algoritme π Liu Hui](src/algorithms/math/liu-hui) - perkiraan perhitungan π berdasarkan segibanyak + - `L` [Transformasi Diskrit Fourier](src/algorithms/math/fourier-transform) - menguraikan fungsi waktu (sinyal) menjadi frekuensi yang menyusunnya +- **Himpunan** + - `P` [Produk Kartesian](src/algorithms/sets/cartesian-product) - hasil dari beberapa himpunan + - `P` [Pengocokan Fisher–Yates](src/algorithms/sets/fisher-yates) - permutasi acak dari sebuah urutan terhingga + - `L` [Himpunan Kuasa](src/algorithms/sets/power-set) - semua himpunan bagian dari sebuah himpunan + - `L` [Permutasi](src/algorithms/sets/permutations) (dengan dan tanpa pengulangan) + - `L` [Kombinasi](src/algorithms/sets/combinations) (dengan dan tanpa pengulangan) + - `L` [_Longest Common Subsequence_](src/algorithms/sets/longest-common-subsequence) (LCS) + - `L` [_Longest Increasing Subsequence_](src/algorithms/sets/longest-increasing-subsequence) + - `L` [_Shortest Common Supersequence_](src/algorithms/sets/shortest-common-supersequence) (SCS) + - `L` [Permasalahan Knapsack](src/algorithms/sets/knapsack-problem) - "0/1" dan yang tidak "dibatasi" + - `L` [Upalarik Maksimum](src/algorithms/sets/maximum-subarray) - "_Brute Force_" dan "Pemrograman Dinamis" versi Kadane + - `L` [_Combination Sum_](src/algorithms/sets/combination-sum) - menemukan semua kombinasi yang membentuk jumlah tertentu +- **String** + - `P` [Jarak Hamming](src/algorithms/string/hamming-distance) - jumlah posisi di mana ditemukan simbol-simbol yang berbeda + - `L` [Algoritme Jarak Levenshtein](src/algorithms/string/levenshtein-distance) - _edit distance_ minimum antara dua urutan + - `L` [Algoritme Knuth–Morris–Pratt](src/algorithms/string/knuth-morris-pratt) (Algoritme KMP) - pencarian substring (pencocokan pola) + - `L` [AlgoritmeZ](src/algorithms/string/z-algorithm) - pencarian substring (pencocokan pola) + - `L` [Algoritme Rabin Karp](src/algorithms/string/rabin-karp) - pencarian substring + - `L` [_Longest Common Substring_](src/algorithms/string/longest-common-substring) + - `L` [Pencocokan Ekspresi Reguler](src/algorithms/string/regular-expression-matching) +- **Pencarian** + - `P` [Pencarian Linier](src/algorithms/search/linear-search) + - `P` [Pencarian Lompat](src/algorithms/search/jump-search) (atau Block Search) - pencarian di larik tersortir + - `P` [Pencarian Biner](src/algorithms/search/binary-search) - pencarian di larik tersortir + - `P` [Pencarian Interpolasi](src/algorithms/search/interpolation-search) - pencarian di larik tersortir yang terdistribusi seragam +- **Penyortiran** + - `P` [Sortir Gelembung](src/algorithms/sorting/bubble-sort) + - `P` [Sortir Seleksi](src/algorithms/sorting/selection-sort) + - `P` [Sortir Sisipan](src/algorithms/sorting/insertion-sort) + - `P` [Sortir _Heap_](src/algorithms/sorting/heap-sort) + - `P` [Sortir Gabungan](src/algorithms/sorting/merge-sort) + - `P` [Sortir Cepat](src/algorithms/sorting/quick-sort) - implementasi _in-place_ dan _non-in-place_ + - `P` [Sortir Shell](src/algorithms/sorting/shell-sort) + - `P` [Sortir Perhitungan](src/algorithms/sorting/counting-sort) + - `P` [Sortir Akar](src/algorithms/sorting/radix-sort) +- **Senarai Berantai** + - `P` [Lintas Lurus](src/algorithms/linked-list/traversal) + - `P` [Lintas Terbalik](src/algorithms/linked-list/reverse-traversal) +- **Pohon** + - `P` [Pencarian Kedalaman Pertama](src/algorithms/tree/depth-first-search) (DFS) + - `P` [Pencarian Luas Pertama](src/algorithms/tree/breadth-first-search) (BFS) +- **Graf** + - `P` [Pencarian Kedalaman Pertama](src/algorithms/graph/depth-first-search) (DFS) + - `P` [Pencarian Luas Pertama](src/algorithms/graph/breadth-first-search) (BFS) + - `P` [Algoritme Kruskal](src/algorithms/graph/kruskal) - mencari rentang pohon minimum untuk graf tidak berarah berbobot + - `L` [Algoritme Dijkstra](src/algorithms/graph/dijkstra) - menemukan jalur terpendek ke semua sudut graf dari sudut tunggal + - `L` [Algoritme Bellman-Ford](src/algorithms/graph/bellman-ford) - menemukan jalur terpendek ke semua sudut graf dari sudut tunggal + - `L` [Algoritme Floyd-Warshall](src/algorithms/graph/floyd-warshall) - menemukan jalur terpendek antara semua pasangan sudut + - `L` [Mendeteksi Siklus](src/algorithms/graph/detect-cycle) - untuk graf berarah dan tidak berarah (berdasarkan versi DFS dan _Disjoint Set_) + - `L` [ALgoritme Prim](src/algorithms/graph/prim) - mencari rentang pohon minimum untuk graf tidak berarah berbobot + - `L` [Sortir Topologi](src/algorithms/graph/topological-sorting) - metode DFS + - `L` [Poin Artikulasi](src/algorithms/graph/articulation-points) - Algoritme Tarjan (berdasarkan DFS) + - `L` [Jembatan](src/algorithms/graph/bridges) - Algoritme berdasarkan DFS + - `L` [Jalur dan Sirkuit Eulerian](src/algorithms/graph/eulerian-path) - Algoritme Fleury - Mengunjungi setiap tepinya tepat satu kali + - `L` [Siklus Hamiltonian](src/algorithms/graph/hamiltonian-cycle) - mengunjungi setiap sudutnya tepat satu kali + - `L` [Komponen yang Terkoneksi dengan Kuat](src/algorithms/graph/strongly-connected-components) - Algoritme Kosaraju + - `L` [Permasalahan Penjual Keliling](src/algorithms/graph/travelling-salesman) - kemungkinan rute terpendek untuk mengunjungi setiap kota dan kembali lagi ke kota asal +- **Kriptografi** + - `P` [Polinomial Hash](src/algorithms/cryptography/polynomial-hash) - fungsi rolling hash berdasarkan polinomial + - `P` [Sandi Caesar](src/algorithms/cryptography/caesar-cipher) - sandi pengganti sederhana +- **Pembelajaran Mesin** + - `P` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 fungsi JS sederhana yang mengilustrasikan bagaimana mesin-mesin dapat benar-benar belajar (perambatan maju/mundur) +- **Tidak Dikategorikan** + - `P` [Menara Hanoi](src/algorithms/uncategorized/hanoi-tower) + - `P` [Perputaran Matriks Persegi](src/algorithms/uncategorized/square-matrix-rotation) - algoritme _in-place_ + - `P` [Permainan Melompat](src/algorithms/uncategorized/jump-game) - runut-balik, pemrograman dinamis (atas ke bawah + bawah ke atas) and contoh-contoh _greedy_ + - `P` [_Unique Paths_](src/algorithms/uncategorized/unique-paths) - runut-balik, pemrograman dinamis and contoh-contoh beradsarkan Segitiga Pascal + - `P` [_Rain Terraces_](src/algorithms/uncategorized/rain-terraces) - permasalahan _trapping rain water_ (versi pemrograman dinamis and _brute force_) + - `P` [Tangga Rekursif](src/algorithms/uncategorized/recursive-staircase) - menghitung jumlah cara untuk mencapai ke atas tangga (4 solusi) + - `L` [Permainan N-Queen](src/algorithms/uncategorized/n-queens) + - `L` [Permainan Knight's Tour](src/algorithms/uncategorized/knight-tour) + +### Algoritme Berdasarkan Paradigma + +Paradigma algoritmik adalah sebuah metode atau pendekatan umum yang mendasari desain sebuah tingkatan algoritme. Paradigma algoritmik merupakan abstraksi yang lebih tinggi dari gagasan sebuah algoritme, seperti halnya sebuah algoritme merupakan abstraksi yang lebih tinggi dari sebuah program komputer. + +- **_Brute Force_** - melihat ke semua kemungkinan dan memilih solusi yang terbaik + - `P` [Pencarian Linier](src/algorithms/search/linear-search) + - `P` [_Rain Terraces_](src/algorithms/uncategorized/rain-terraces) - permasalahan _trapping rain water_ + - `P` [Tangga Rekursif](src/algorithms/uncategorized/recursive-staircase) - menghitung jumlah cara untuk mencapai ke atas tangga + - `L` [Upalarik Maksimum](src/algorithms/sets/maximum-subarray) + - `L` [Permasalahan Penjual Keliling](src/algorithms/graph/travelling-salesman) - kemungkinan rute terpendek untuk mengunjungi setiap kota dan kembali lagi ke kota asal + - `L` [Transformasi Diskrit Fourier](src/algorithms/math/fourier-transform) - menguraikan fungsi waktu (sinyal) menjadi frekuensi yang menyusunnya +- **_Greedy_** - memilih pilihan terbaik pada saat ini tanpa mempertimbangkan masa yang akan datang + - `P` [Permainan Melompat](src/algorithms/uncategorized/jump-game) + - `L` [Permasalahan Knapsack yang Tidak Dibatasi](src/algorithms/sets/knapsack-problem) + - `L` [Algoritme Dijkstra](src/algorithms/graph/dijkstra) - menemukan jalur terpendek ke semua sudut graf dari sudut tunggal + - `L` [Algoritme Prim](src/algorithms/graph/prim) - mencari rentang pohon minimum untuk graf tidak berarah berbobot + - `L` [Algoritme Kruskal](src/algorithms/graph/kruskal) - mencari rentang pohon minimum untuk graf tidak berarah berbobot +- **Memecah dan Menaklukkan** - membagi masalah menjadi bagian-bagian yang kecil, lalu memcahkan bagian-bagian tersebut + - `P` [Pencarian Biner](src/algorithms/search/binary-search) + - `P` [Menara Hanoi](src/algorithms/uncategorized/hanoi-tower) + - `P` [Segitiga Pascal](src/algorithms/math/pascal-triangle) + - `P` [Algoritme Euclidean](src/algorithms/math/euclidean-algorithm) - menghitung Faktor Persekutuan Terbesar (FPB) + - `P` [Sortir Gabungan](src/algorithms/sorting/merge-sort) + - `P` [Sortir Cepat](src/algorithms/sorting/quick-sort) + - `P` [Pencarian Kedalaman Pertama untuk Pohon](src/algorithms/tree/depth-first-search) (DFS) + - `P` [Pencarian Kedalaman Pertama untuk Graf](src/algorithms/graph/depth-first-search) (DFS) + - `P` [Permainan Melompat](src/algorithms/uncategorized/jump-game) + - `P` [_Fast Powering_](src/algorithms/math/fast-powering) + - `L` [Permutasi](src/algorithms/sets/permutations) (dengan dan tanpa pengulangan) + - `L` [Kombinasi](src/algorithms/sets/combinations) (dengan dan tanpa pengulangan) +- **Pemrograman Dinamis** - membangun sebuah solusi menggunakan upasolusi yang ditemukan sebelumnya + - `P` [Bilangan Fibonacci](src/algorithms/math/fibonacci) + - `P` [Permainan Melompat](src/algorithms/uncategorized/jump-game) + - `P` [_Unique Paths_](src/algorithms/uncategorized/unique-paths) + - `P` [_Rain Terraces_](src/algorithms/uncategorized/rain-terraces) - permasalahan _trapping rain water_ + - `P` [Tangga Rekursif](src/algorithms/uncategorized/recursive-staircase) - menghitung jumlah cara untuk mencapai ke atas tangga + - `L` [Algoritme Jarak Levenshtein](src/algorithms/string/levenshtein-distance) - _edit distance_ minimum antara dua urutan + - `L` [_Longest Common Subsquence_](src/algorithms/sets/longest-common-subsequence) (LCS) + - `L` [_Longest Common Substring_](src/algorithms/string/longest-common-substring) + - `L` [_Longest Increasing Subsequence_](src/algorithms/sets/longest-increasing-subsequence) + - `L` [_Shortest Common Supersequence_](src/algorithms/sets/shortest-common-supersequence) + - `L` [Permasalahan Knapsack 0/1](src/algorithms/sets/knapsack-problem) + - `L` [Partisi Bilangan Bulat](src/algorithms/math/integer-partition) + - `L` [Upalarik Maksimum](src/algorithms/sets/maximum-subarray) + - `L` [Algoritme Bellman-Ford](src/algorithms/graph/bellman-ford) - menemukan jalur terpendek ke semua sudut graf dari sudut tunggal + - `L` [Algoritme Floyd-Warshall](src/algorithms/graph/floyd-warshall) - menemukan jalur terpendek antara semua pasangan sudut + - `L` [Pencocokan Ekspresi Reguler](src/algorithms/string/regular-expression-matching) +- **Runut-balik** - sama halnya dengan _brute force_, algoritme ini mencoba untuk menghasilkan segala kemungkinan solusi, tetapi setiap kali anda menghasilkan solusi selanjutnya, anda akan menguji apakah solusi tersebut memenuhi semua kondisi dan setelah itu baru akan menghasilkan solusi berikutnya. Apabila tidak, maka akan merunut-balik dan mencari solusi di jalur yang berbeda. Biasanya menggunakan lintas DFS dari ruang keadaan. + - `P` [Permainan Melompat](src/algorithms/uncategorized/jump-game) + - `P` [_Unique Paths_](src/algorithms/uncategorized/unique-paths) + - `P` [Himpunan Kuasa](src/algorithms/sets/power-set) - semua himpunan bagian dari sebuah himpunan + - `L` [Siklus Hamiltonian](src/algorithms/graph/hamiltonian-cycle) - mengunjungi setiap sudutnya tepat satu kali + - `L` [Permainan N-Queen](src/algorithms/uncategorized/n-queens) + - `L` [Permainan Knight's Tour](src/algorithms/uncategorized/knight-tour) + - `L` [_Combination Sum_](src/algorithms/sets/combination-sum) - menemukan semua kombinasi yang membentuk jumlah tertentu +- **_Mencabang dan Membatasi_** - digunakan untuk membuang solusi parsial dengan biaya yang lebih besar dari solusi dengan biaya yang terendah yang ditemukan sejauh ini dengan cara mengingat solusi dengan biaya terendah yang ditemukan pada setiap tahap dari pencarian runut-balik dan menggunakan biaya dari solusi dengan biaya terendah sejauh ini sebagai batas bawah pada biaya dari solusi dengan biaya yang paling sedikit untuk permasalahannya. Biasanya menggunakan lintas BFS yang berkombinasi dengan lintas DFS dari pohon ruang keadaan. + +## Cara menggunakan repositori ini + +**Meng-_install_ semua dependensi** + +``` +npm install +``` + +**Menjalankan ESLint** + +Anda dapat menjalankannya untuk memeriksa kualitas kode. + +``` +npm run lint +``` + +**Menjalankan semua tes** + +``` +npm test +``` + +**Menjalankan tes berdasarkan nama** + +``` +npm test -- 'LinkedList' +``` + +**_Playground_** + +Anda dapat bermain dengan algoritme dan struktur data di _file_ `./src/playground/playground.js` dan menuliskan tesnya di `./src/playground/__test__/playground.test.js`. + +Lalu, hanya tinggal menjalankan perintah berikut untuk mengetes apakah kode _playground_ anda bekerja sesuai dengan keinginan: + +``` +npm test -- 'playground' +``` + +## Informasi Bermanfaat + +### Referensi + +[▶ Algoritme dan Struktur Data di YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) + +### Notasi _Big O_ + +Notasi _Big O_ digunakan untuk mengklasifikasikan algoritme berdasarkan durasi atau ruang yang dibutuhkan seiring bertambahnya _input_. Pada grafik dibawah, anda dapat menemukan urutan pertumbuhan yang paling umum dari algoritme yang ditentukan dalam notasi _Big O_. + +![Big O graphs](./assets/big-o-graph.png) + +Sumber: [Big O Cheat Sheet](http://bigocheatsheet.com/). + +Di bawah ini adalah daftar dari beberapa notasi _Bog O_ yang sering digunakan dan perbandingan kinerjanya terhadap berbagai ukuran _input data_. + +| Notasi _Big O_ | Komputasi untuk 10 elemen | Komputasi untuk 100 elemen | Komputasi untuk 1000 elemen | +| -------------- | ------------------------- | -------------------------- | --------------------------- | +| **O(1)** | 1 | 1 | 1 | +| **O(log N)** | 3 | 6 | 9 | +| **O(N)** | 10 | 100 | 1000 | +| **O(N log N)** | 30 | 600 | 9000 | +| **O(N^2)** | 100 | 10000 | 1000000 | +| **O(2^N)** | 1024 | 1.26e+29 | 1.07e+301 | +| **O(N!)** | 3628800 | 9.3e+157 | 4.02e+2567 | + +### Kompleksitas Operasi Struktur Data + +| Struktur Data | Akses | Pencarian | Penyisipan | Penghapusan | Keterangan | +| -------------------------------------------- | :----: | :-------: | :--------: | :---------: | :------------------------------------------------------- | +| **Array (Larik)** | 1 | n | n | n | | +| **Stack (Tumpukan)** | n | n | 1 | 1 | | +| **Queue (Antrean)** | n | n | 1 | 1 | | +| **Linked List (Senarai Berantai)** | n | n | 1 | n | | +| **Hash Table** | - | n | n | n | Apabila fungsi hash sempurna, biayanya akan menjadi O(1) | +| **Binary Search Tree (Pohon Telusur Biner)** | n | n | n | n | Apabila pohon seimbang, biayanya akan menjadi O(log(n)) | +| **B-Tree** | log(n) | log(n) | log(n) | log(n) | | +| **Red-Black Tree (Pohon Merah-Hitam)** | log(n) | log(n) | log(n) | log(n) | | +| **AVL Tree** | log(n) | log(n) | log(n) | log(n) | | +| **Bloom Filter** | - | 1 | 1 | - | Positif palsu dimungkinkan saat pencarian | + +### Kompleksitas Algoritme Sortir Larik + +| Nama | Terbaik | Rata-rata | Terburuk | Memori | Stabil | Keterangan | +| -------------------------------------- | :-----------: | :--------------------------: | :-------------------------: | :----: | :----: | :-------------------------------------------------------------------------------- | +| **Bubble sort (Sortir Gelembung)** | n | n2 | n2 | 1 | Ya | | +| **Insertion sort (Sortir Sisipan)** | n | n2 | n2 | 1 | Ya | | +| **Selection sort (Sortir Seleksi)** | n2 | n2 | n2 | 1 | Tidak | | +| **Heap sort (Sortir _Heap_)** | n log(n) | n log(n) | n log(n) | 1 | Tidak | | +| **Merge Sort (Sortir Gabungan)** | n log(n) | n log(n) | n log(n) | n | Ya | | +| **Quick sort (Sortir Cepat)** | n log(n) | n log(n) | n2 | log(n) | Tidak | Sortir Cepat biasanya dilakukan secara _in-place_ dengan O(log(n)) ruang tumpukan | +| **Shell sort (Sortir Shell)** | n log(n) | tergantung pada jarak urutan | n (log(n))2 | 1 | Tidak | | +| **Counting sort (Sortir Perhitungan)** | n + r | n + r | n + r | n + r | Ya | r - angka terbesar dalam larik | +| **Radix sort (Sortir Akar)** | n \* k | n \* k | n \* k | n + k | Ya | k - panjang dari kunci terpanjang | + +## Pendukung Proyek + +> Anda dapat mendukung proyek ini via ❤️️ [GitHub](https://github.com/sponsors/trekhleb) atau ❤️️ [Patreon](https://www.patreon.com/trekhleb). + +[Orang-orang yang mendukung proyek ini](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1` From c755110eb19229058ef80f607eaf31b5bb244d79 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sun, 20 Dec 2020 13:01:46 +0100 Subject: [PATCH 052/264] Adding Bahasa Indonesia. --- README.es-ES.md | 3 ++- README.fr-FR.md | 3 ++- README.id-ID.md | 2 +- README.it-IT.md | 3 ++- README.ja-JP.md | 3 ++- README.ko-KR.md | 3 ++- README.md | 3 ++- README.pl-PL.md | 3 ++- README.pt-BR.md | 3 ++- README.ru-RU.md | 3 ++- README.tr-TR.md | 3 ++- README.zh-CN.md | 3 ++- README.zh-TW.md | 3 ++- 13 files changed, 25 insertions(+), 13 deletions(-) diff --git a/README.es-ES.md b/README.es-ES.md index b6337a1c3d..ee0e0d6289 100644 --- a/README.es-ES.md +++ b/README.es-ES.md @@ -20,7 +20,8 @@ _Léelo en otros idiomas:_ [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), -[_Italiana_](README.it-IT.md) +[_Italiana_](README.it-IT.md), +[_Bahasa Indonesia_](README.id-ID.md) *☝ Nótese que este proyecto está pensado con fines de aprendizaje e investigación, y **no** para ser usado en producción.* diff --git a/README.fr-FR.md b/README.fr-FR.md index 7b3705544b..1e21add710 100644 --- a/README.fr-FR.md +++ b/README.fr-FR.md @@ -21,7 +21,8 @@ _Lisez ceci dans d'autres langues:_ [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), -[_Italiana_](README.it-IT.md) +[_Italiana_](README.it-IT.md), +[_Bahasa Indonesia_](README.id-ID.md) ## Data Structures diff --git a/README.id-ID.md b/README.id-ID.md index 784fb76961..5a31ff8b35 100644 --- a/README.id-ID.md +++ b/README.id-ID.md @@ -1,6 +1,6 @@ # Algoritme dan Struktur Data Javascript -[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster) [![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) Repositori ini berisi contoh-contoh algoritme dan struktur data yang populer menggunakan JavaScript. diff --git a/README.it-IT.md b/README.it-IT.md index 9598324058..31a7def923 100644 --- a/README.it-IT.md +++ b/README.it-IT.md @@ -17,7 +17,8 @@ _Leggilo in altre lingue:_ [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), -[_Türk_](README.tr-TR.md) +[_Türk_](README.tr-TR.md), +[_Bahasa Indonesia_](README.id-ID.md) *☝ Si noti che questo progetto è destinato ad essere utilizzato solo per l'apprendimento e la ricerca e non è destinato ad essere utilizzato per il commercio.* diff --git a/README.ja-JP.md b/README.ja-JP.md index 93321556c4..e955c3ae30 100644 --- a/README.ja-JP.md +++ b/README.ja-JP.md @@ -20,7 +20,8 @@ _Read this in other languages:_ [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), -[_Italiana_](README.it-IT.md) +[_Italiana_](README.it-IT.md), +[_Bahasa Indonesia_](README.id-ID.md) ## データ構造 diff --git a/README.ko-KR.md b/README.ko-KR.md index 0fa189d106..45c59cbe8e 100644 --- a/README.ko-KR.md +++ b/README.ko-KR.md @@ -19,7 +19,8 @@ _Read this in other languages:_ [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), -[_Italiana_](README.it-IT.md) +[_Italiana_](README.it-IT.md), +[_Bahasa Indonesia_](README.id-ID.md) ## 자료 구조 diff --git a/README.md b/README.md index ffec78a9e2..11293da799 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,8 @@ _Read this in other languages:_ [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), -[_Italiana_](README.it-IT.md) +[_Italiana_](README.it-IT.md), +[_Bahasa Indonesia_](README.id-ID.md) *☝ Note that this project is meant to be used for learning and researching purposes only, and it is **not** meant to be used for production.* diff --git a/README.pl-PL.md b/README.pl-PL.md index d1ad0ec224..0ede13db43 100644 --- a/README.pl-PL.md +++ b/README.pl-PL.md @@ -21,7 +21,8 @@ _Read this in other languages:_ [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), -[_Italiana_](README.it-IT.md) +[_Italiana_](README.it-IT.md), +[_Bahasa Indonesia_](README.id-ID.md) ## Struktury Danych diff --git a/README.pt-BR.md b/README.pt-BR.md index 17899af1d9..7517bb5086 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -21,7 +21,8 @@ _Leia isto em outros idiomas:_ [_Español_](README.es-ES.md), [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), -[_Italiana_](README.it-IT.md) +[_Italiana_](README.it-IT.md), +[_Bahasa Indonesia_](README.id-ID.md) ## Estrutura de Dados diff --git a/README.ru-RU.md b/README.ru-RU.md index e85446d31f..12c1324d36 100644 --- a/README.ru-RU.md +++ b/README.ru-RU.md @@ -18,7 +18,8 @@ _Читать на других языках:_ [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), [_Türk_](README.tr-TR.md), -[_Italiana_](README.it-IT.md) +[_Italiana_](README.it-IT.md), +[_Bahasa Indonesia_](README.id-ID.md) *☝ Замечание: этот репозиторий предназначен для учебно-исследовательских целей (**не** для использования в продакшн-системах).* diff --git a/README.tr-TR.md b/README.tr-TR.md index c65061e454..2b453000b9 100644 --- a/README.tr-TR.md +++ b/README.tr-TR.md @@ -19,7 +19,8 @@ _Read this in other languages:_ [_Español_](README.es-ES.md), [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), -[_Italiana_](README.it-IT.md) +[_Italiana_](README.it-IT.md), +[_Bahasa Indonesia_](README.id-ID.md) *☝ Not, bu proje araştırma ve öğrenme amacı ile yapılmış olup üretim için **yaplılmamıştır**.* diff --git a/README.zh-CN.md b/README.zh-CN.md index 05f580817f..c039524447 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -18,7 +18,8 @@ _Read this in other languages:_ [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), -[_Italiana_](README.it-IT.md) +[_Italiana_](README.it-IT.md), +[_Bahasa Indonesia_](README.id-ID.md) *注意:这个项目仅用于学习和研究,**不是**用于生产环境。* diff --git a/README.zh-TW.md b/README.zh-TW.md index 1a091720bb..69df9717cb 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -17,7 +17,8 @@ _Read this in other languages:_ [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), -[_Italiana_](README.it-IT.md) +[_Italiana_](README.it-IT.md), +[_Bahasa Indonesia_](README.id-ID.md) ## 資料結構 From 22abc6f8080e5f97266c18bdb8eff35245a95a67 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sun, 20 Dec 2020 13:05:41 +0100 Subject: [PATCH 053/264] Rename the CI workflow file. --- .github/workflows/{node.js.yml => ci.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{node.js.yml => ci.yml} (100%) diff --git a/.github/workflows/node.js.yml b/.github/workflows/ci.yml similarity index 100% rename from .github/workflows/node.js.yml rename to .github/workflows/ci.yml From 9641940fd78fce6766237118a36647204c67343c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Raskopf?= Date: Sun, 20 Dec 2020 14:40:22 -0300 Subject: [PATCH 054/264] Add rail fence cipher (#516) * Add rail fence cipher encoder & decoder * Add functions to encode & decode strings using the rail fence cipher method * Add unit tests covering empty strings, pair & odd number of characters in the input string, n=3 & n=4 * Add a README.md for the algorithm * Update root README.md to link to the new algorithm * Rename the CI workflow file. Co-authored-by: Oleksii Trekhleb --- .github/workflows/{node.js.yml => ci.yml} | 0 README.md | 1 + .../cryptography/rail-fence-cipher/README.md | 25 ++++ .../__test__/railFenceCypher.test.js | 26 +++++ .../rail-fence-cipher/decodeRailFence.js | 108 ++++++++++++++++++ .../rail-fence-cipher/encodeRailFence.js | 52 +++++++++ .../rail-fence-cipher/railFenceCipher.js | 50 ++++++++ 7 files changed, 262 insertions(+) rename .github/workflows/{node.js.yml => ci.yml} (100%) create mode 100644 src/algorithms/cryptography/rail-fence-cipher/README.md create mode 100644 src/algorithms/cryptography/rail-fence-cipher/__test__/railFenceCypher.test.js create mode 100644 src/algorithms/cryptography/rail-fence-cipher/decodeRailFence.js create mode 100644 src/algorithms/cryptography/rail-fence-cipher/encodeRailFence.js create mode 100644 src/algorithms/cryptography/rail-fence-cipher/railFenceCipher.js diff --git a/.github/workflows/node.js.yml b/.github/workflows/ci.yml similarity index 100% rename from .github/workflows/node.js.yml rename to .github/workflows/ci.yml diff --git a/README.md b/README.md index 11293da799..c6d8713451 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,7 @@ a set of rules that precisely define a sequence of operations. * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city * **Cryptography** * `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - rolling hash function based on polynomial + * `B` [Rail Fence Cypher](src/algorithms/cryptography/rail-fence-cipher) - a transposition cipher algorithm for encoding messages * `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - simple substitution cipher * `B` [Hill Cipher](src/algorithms/cryptography/hill-cipher) - substitution cipher based on linear algebra * **Machine Learning** diff --git a/src/algorithms/cryptography/rail-fence-cipher/README.md b/src/algorithms/cryptography/rail-fence-cipher/README.md new file mode 100644 index 0000000000..e090f557eb --- /dev/null +++ b/src/algorithms/cryptography/rail-fence-cipher/README.md @@ -0,0 +1,25 @@ +# Rail fence Cipher + +This is a [transposition cipher](https://en.wikipedia.org/wiki/Transposition_cipher) in which the message is split accross a set of rails on a fence for encoding. The fence is populated with the message's characters, starting at the top left and adding a character on each position, traversing them diagonally to the bottom. Upon reaching the last rail, the direction should then turn diagonal and upwards up to the very first rail in a zig-zag motion. Rinse and repeat until the message is fully disposed across the fence. The encoded message is the result of concatenating the text in each rail, from top to bottom. + +From [wikipedia](https://en.wikipedia.org/wiki/Rail_fence_cipher), this is what the message `WE ARE DISCOVERED. FLEE AT ONCE` looks like on a 3-rail fence: + +``` +W . . . E . . . C . . . R . . . L . . . T . . . E +. E . R . D . S . O . E . E . F . E . A . O . C . +. . A . . . I . . . V . . . D . . . E . . . N . . +------------------------------------------------- + ECRLTEERDSOEEFEAOCAIVDEN +``` + +The message can then be decoded by re-creating the encode fence, with the same traversal pattern, except characters should only be added on one rail at a time. To ilustrate that, a dash can be added on the rails that are not supposed to be poupated yet. This is what the fence would look like after populating the first rail, the dashes represent positions that were visited but not populated. + +``` +W . . . E . . . C . . . R . . . L . . . T . . . E +. - . - . - . - . - . - . - . - . - . - . - . - . +. . - . . . - . . . - . . . - . . . - . . . - . . +``` + +It's time to start populating the next rail once the number of visited fence positions is equal to the number of characters in the message. + +[Learn more](https://crypto.interactive-maths.com/rail-fence-cipher.html) diff --git a/src/algorithms/cryptography/rail-fence-cipher/__test__/railFenceCypher.test.js b/src/algorithms/cryptography/rail-fence-cipher/__test__/railFenceCypher.test.js new file mode 100644 index 0000000000..285841e2ce --- /dev/null +++ b/src/algorithms/cryptography/rail-fence-cipher/__test__/railFenceCypher.test.js @@ -0,0 +1,26 @@ +import encodeRailFenceCipher from '../encodeRailFence'; +import decodeRailFenceCipher from '../decodeRailFence'; + +describe('rail fence cipher', () => { + it('encodes a string correctly for base=3', () => { + expect(encodeRailFenceCipher('', 3)).toBe(''); + expect(encodeRailFenceCipher('WEAREDISCOVEREDFLEEATONCE', 3)).toBe('WECRLTEERDSOEEFEAOCAIVDEN'); + expect(encodeRailFenceCipher('Hello, World!', 3)).toBe('Hoo!el,Wrdl l'); + }); + + it('decodes a string correctly for base=3', () => { + expect(decodeRailFenceCipher('', 3)).toBe(''); + expect(decodeRailFenceCipher('WECRLTEERDSOEEFEAOCAIVDEN', 3)).toBe('WEAREDISCOVEREDFLEEATONCE'); + expect(decodeRailFenceCipher('Hoo!el,Wrdl l', 3)).toBe('Hello, World!'); + }); + + it('encodes a string correctly for base=4', () => { + expect(encodeRailFenceCipher('', 4)).toBe(''); + expect(encodeRailFenceCipher('THEYAREATTACKINGFROMTHENORTH', 4)).toBe('TEKOOHRACIRMNREATANFTETYTGHH'); + }); + + it('decodes a string correctly for base=4', () => { + expect(decodeRailFenceCipher('', 4)).toBe(''); + expect(decodeRailFenceCipher('TEKOOHRACIRMNREATANFTETYTGHH', 4)).toBe('THEYAREATTACKINGFROMTHENORTH'); + }); +}); diff --git a/src/algorithms/cryptography/rail-fence-cipher/decodeRailFence.js b/src/algorithms/cryptography/rail-fence-cipher/decodeRailFence.js new file mode 100644 index 0000000000..b1826b4883 --- /dev/null +++ b/src/algorithms/cryptography/rail-fence-cipher/decodeRailFence.js @@ -0,0 +1,108 @@ +import { + addChar, + buildFence, + DIRECTIONS, + getNextDirection, +} from './railFenceCipher'; + +/** + * @param {object} params + * @param {number} params.railCount + * @param {number} params.strLen + * @param {Array} params.string + * @param {Array} params.fence + * @param {number} params.targetRail + * @param {number} params.direction + * @param {Array} params.coords + * + * @returns {Array} + */ +const fillDecodeFence = ({ + railCount, strLen, string, fence, targetRail, direction, coords, +}) => { + if (string.length === 0) return fence; + + const [currentRail, currentColumn] = coords; + const shouldGoNextRail = currentColumn === strLen - 1; + const nextDirection = shouldGoNextRail + ? DIRECTIONS.DOWN + : getNextDirection({ railCount, currentRail, direction }); + const nextRail = shouldGoNextRail ? targetRail + 1 : targetRail; + const nextCoords = [ + shouldGoNextRail ? 0 : currentRail + nextDirection, + shouldGoNextRail ? 0 : currentColumn + 1, + ]; + + const shouldAddChar = currentRail === targetRail; + const [currentChar, ...remainderString] = string; + const nextString = shouldAddChar ? remainderString : string; + const nextFence = shouldAddChar ? fence.map(addChar(currentRail, currentChar)) : fence; + + return fillDecodeFence({ + railCount, + strLen, + string: nextString, + fence: nextFence, + targetRail: nextRail, + direction: nextDirection, + coords: nextCoords, + }); +}; + +/** + * @param {object} params + * @param {number} params.railCount + * @param {number} params.strLen + * @param {Array} params.fence + * @param {number} params.currentRail + * @param {number} params.direction + * @param {Array} params.code + * + * @returns {string} + */ +const decodeFence = ({ + railCount, strLen, fence, currentRail, direction, code, +}) => { + if (code.length === strLen) return code.join(''); + + const [currentChar, ...nextRail] = fence[currentRail]; + const nextDirection = getNextDirection({ railCount, currentRail, direction }); + + return decodeFence({ + railCount, + strLen, + currentRail: currentRail + nextDirection, + direction: nextDirection, + code: [...code, currentChar], + fence: fence.map((rail, idx) => (idx === currentRail ? nextRail : rail)), + }); +}; + +/** + * @param {string} string + * @param {number} railCount + * + * @returns {string} + */ +export default function decodeRailFenceCipher(string, railCount) { + const strLen = string.length; + const emptyFence = buildFence(railCount); + const filledFence = fillDecodeFence({ + railCount, + strLen, + string: string.split(''), + fence: emptyFence, + targetRail: 0, + direction: DIRECTIONS.DOWN, + coords: [0, 0], + }); + + return decodeFence({ + railCount, + strLen, + fence: filledFence, + currentRail: 0, + direction: DIRECTIONS.DOWN, + code: [], + }); +} diff --git a/src/algorithms/cryptography/rail-fence-cipher/encodeRailFence.js b/src/algorithms/cryptography/rail-fence-cipher/encodeRailFence.js new file mode 100644 index 0000000000..9a58131253 --- /dev/null +++ b/src/algorithms/cryptography/rail-fence-cipher/encodeRailFence.js @@ -0,0 +1,52 @@ +import { + addChar, + buildFence, + DIRECTIONS, + getNextDirection, +} from './railFenceCipher'; + +/** + * @param {object} params + * @param {number} params.railCount + * @param {number} params.currentRail + * @param {number} params.direction + * @param {Array} params.string + * + * @returns {Array} + */ +const fillEncodeFence = ({ + railCount, fence, currentRail, direction, string, +}) => { + if (string.length === 0) return fence; + + const [letter, ...nextString] = string; + const nextDirection = getNextDirection({ railCount, currentRail, direction }); + + return fillEncodeFence({ + railCount, + fence: fence.map(addChar(currentRail, letter)), + currentRail: currentRail + nextDirection, + direction: nextDirection, + string: nextString, + }); +}; + +/** + * @param {string} string + * @param {number} railCount + * + * @returns {string} + */ +export default function encodeRailFenceCipher(string, railCount) { + const fence = buildFence(railCount); + + const filledFence = fillEncodeFence({ + railCount, + fence, + currentRail: 0, + direction: DIRECTIONS.DOWN, + string: string.split(''), + }); + + return filledFence.flat().join(''); +} diff --git a/src/algorithms/cryptography/rail-fence-cipher/railFenceCipher.js b/src/algorithms/cryptography/rail-fence-cipher/railFenceCipher.js new file mode 100644 index 0000000000..e50b477a36 --- /dev/null +++ b/src/algorithms/cryptography/rail-fence-cipher/railFenceCipher.js @@ -0,0 +1,50 @@ +/** + * @constant DIRECTIONS + * @type {object} + * @property {number} UP + * @property {number} DOWN + */ +export const DIRECTIONS = { UP: -1, DOWN: 1 }; + +/** + * @param {number} rows + * + * @returns {Array} + */ +export const buildFence = (rows) => Array(rows) + .fill() + .map(() => []); + +/** + * @param {object} params + * @param {number} params.railCount + * @param {number} params.currentRail + * @param {number} params.direction + * + * @returns {number} + */ +export const getNextDirection = ({ railCount, currentRail, direction }) => { + switch (currentRail) { + case 0: return DIRECTIONS.DOWN; + case railCount - 1: return DIRECTIONS.UP; + default: return direction; + } +}; + +/** + * Given a rail, adds a char to it + * if it matches a targetIndex. + * @callback charAdder + * @param {number} rail + * @param {currentRail} number + */ + +/** + * @param {number} targetIndex + * @param {string} letter + * + * @returns {charAdder} + */ +export const addChar = (targetIndex, letter) => (rail, currentRail) => { + return (currentRail === targetIndex ? [...rail, letter] : rail); +}; From 2794445f9537d8acee3bba3142335a71f0e0628b Mon Sep 17 00:00:00 2001 From: Sagid M Date: Sun, 20 Dec 2020 21:57:03 +0300 Subject: [PATCH 055/264] Add the word "set" to avoid misinterpretation in description (#286) * Add word to avoid misinterpretation * Rename the CI workflow file. Co-authored-by: Sagid Magomedov Co-authored-by: Oleksii Trekhleb --- src/algorithms/math/is-power-of-two/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/math/is-power-of-two/README.md b/src/algorithms/math/is-power-of-two/README.md index 5b66b7c6cf..8253cb8700 100644 --- a/src/algorithms/math/is-power-of-two/README.md +++ b/src/algorithms/math/is-power-of-two/README.md @@ -12,7 +12,7 @@ the number can't be a power of two. **Bitwise solution** -Powers of two in binary form always have just one bit. +Powers of two in binary form always have just one bit set. The only exception is with a signed integer (e.g. an 8-bit signed integer with a value of -128 looks like: `10000000`) From cfba1d9954ab5b4a33251c7af3f7f55a256a0de5 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sun, 20 Dec 2020 19:57:51 +0100 Subject: [PATCH 056/264] Add Rail Fence Cipher. --- README.md | 2 +- .../cryptography/rail-fence-cipher/README.md | 15 +- ...Cypher.test.js => railFenceCipher.test.js} | 35 ++- .../rail-fence-cipher/decodeRailFence.js | 108 -------- .../rail-fence-cipher/encodeRailFence.js | 52 ---- .../rail-fence-cipher/railFenceCipher.js | 244 ++++++++++++++++-- 6 files changed, 254 insertions(+), 202 deletions(-) rename src/algorithms/cryptography/rail-fence-cipher/__test__/{railFenceCypher.test.js => railFenceCipher.test.js} (51%) delete mode 100644 src/algorithms/cryptography/rail-fence-cipher/decodeRailFence.js delete mode 100644 src/algorithms/cryptography/rail-fence-cipher/encodeRailFence.js diff --git a/README.md b/README.md index c6d8713451..feb9832d36 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ a set of rules that precisely define a sequence of operations. * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city * **Cryptography** * `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - rolling hash function based on polynomial - * `B` [Rail Fence Cypher](src/algorithms/cryptography/rail-fence-cipher) - a transposition cipher algorithm for encoding messages + * `B` [Rail Fence Cipher](src/algorithms/cryptography/rail-fence-cipher) - a transposition cipher algorithm for encoding messages * `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - simple substitution cipher * `B` [Hill Cipher](src/algorithms/cryptography/hill-cipher) - substitution cipher based on linear algebra * **Machine Learning** diff --git a/src/algorithms/cryptography/rail-fence-cipher/README.md b/src/algorithms/cryptography/rail-fence-cipher/README.md index e090f557eb..d01395f554 100644 --- a/src/algorithms/cryptography/rail-fence-cipher/README.md +++ b/src/algorithms/cryptography/rail-fence-cipher/README.md @@ -1,18 +1,18 @@ -# Rail fence Cipher +# Rail Fence Cipher -This is a [transposition cipher](https://en.wikipedia.org/wiki/Transposition_cipher) in which the message is split accross a set of rails on a fence for encoding. The fence is populated with the message's characters, starting at the top left and adding a character on each position, traversing them diagonally to the bottom. Upon reaching the last rail, the direction should then turn diagonal and upwards up to the very first rail in a zig-zag motion. Rinse and repeat until the message is fully disposed across the fence. The encoded message is the result of concatenating the text in each rail, from top to bottom. +The **rail fence cipher** (also called a **zigzag cipher**) is a [transposition cipher](https://en.wikipedia.org/wiki/Transposition_cipher) in which the message is split across a set of rails on a fence for encoding. The fence is populated with the message's characters, starting at the top left and adding a character on each position, traversing them diagonally to the bottom. Upon reaching the last rail, the direction should then turn diagonal and upwards up to the very first rail in a zig-zag motion. Rinse and repeat until the message is fully disposed across the fence. The encoded message is the result of concatenating the text in each rail, from top to bottom. -From [wikipedia](https://en.wikipedia.org/wiki/Rail_fence_cipher), this is what the message `WE ARE DISCOVERED. FLEE AT ONCE` looks like on a 3-rail fence: +From [wikipedia](https://en.wikipedia.org/wiki/Rail_fence_cipher), this is what the message `WE ARE DISCOVERED. FLEE AT ONCE` looks like on a `3`-rail fence: ``` W . . . E . . . C . . . R . . . L . . . T . . . E . E . R . D . S . O . E . E . F . E . A . O . C . . . A . . . I . . . V . . . D . . . E . . . N . . ------------------------------------------------- - ECRLTEERDSOEEFEAOCAIVDEN + WECRLTEERDSOEEFEAOCAIVDEN ``` -The message can then be decoded by re-creating the encode fence, with the same traversal pattern, except characters should only be added on one rail at a time. To ilustrate that, a dash can be added on the rails that are not supposed to be poupated yet. This is what the fence would look like after populating the first rail, the dashes represent positions that were visited but not populated. +The message can then be decoded by re-creating the encoded fence, with the same traversal pattern, except characters should only be added on one rail at a time. To illustrate that, a dash can be added on the rails that are not supposed to be populated yet. This is what the fence would look like after populating the first rail, the dashes represent positions that were visited but not populated. ``` W . . . E . . . C . . . R . . . L . . . T . . . E @@ -22,4 +22,7 @@ W . . . E . . . C . . . R . . . L . . . T . . . E It's time to start populating the next rail once the number of visited fence positions is equal to the number of characters in the message. -[Learn more](https://crypto.interactive-maths.com/rail-fence-cipher.html) +## References + +- [Rail Fence Cipher on Wikipedia](https://en.wikipedia.org/wiki/Rail_fence_cipher) +- [Rail Fence Cipher Calculator](https://crypto.interactive-maths.com/rail-fence-cipher.html) diff --git a/src/algorithms/cryptography/rail-fence-cipher/__test__/railFenceCypher.test.js b/src/algorithms/cryptography/rail-fence-cipher/__test__/railFenceCipher.test.js similarity index 51% rename from src/algorithms/cryptography/rail-fence-cipher/__test__/railFenceCypher.test.js rename to src/algorithms/cryptography/rail-fence-cipher/__test__/railFenceCipher.test.js index 285841e2ce..db0c49eb6b 100644 --- a/src/algorithms/cryptography/rail-fence-cipher/__test__/railFenceCypher.test.js +++ b/src/algorithms/cryptography/rail-fence-cipher/__test__/railFenceCipher.test.js @@ -1,26 +1,43 @@ -import encodeRailFenceCipher from '../encodeRailFence'; -import decodeRailFenceCipher from '../decodeRailFence'; +import { encodeRailFenceCipher, decodeRailFenceCipher } from '../railFenceCipher'; -describe('rail fence cipher', () => { +describe('railFenceCipher', () => { it('encodes a string correctly for base=3', () => { expect(encodeRailFenceCipher('', 3)).toBe(''); - expect(encodeRailFenceCipher('WEAREDISCOVEREDFLEEATONCE', 3)).toBe('WECRLTEERDSOEEFEAOCAIVDEN'); - expect(encodeRailFenceCipher('Hello, World!', 3)).toBe('Hoo!el,Wrdl l'); + expect(encodeRailFenceCipher('12345', 3)).toBe( + '15243', + ); + expect(encodeRailFenceCipher('WEAREDISCOVEREDFLEEATONCE', 3)).toBe( + 'WECRLTEERDSOEEFEAOCAIVDEN', + ); + expect(encodeRailFenceCipher('Hello, World!', 3)).toBe( + 'Hoo!el,Wrdl l', + ); }); it('decodes a string correctly for base=3', () => { expect(decodeRailFenceCipher('', 3)).toBe(''); - expect(decodeRailFenceCipher('WECRLTEERDSOEEFEAOCAIVDEN', 3)).toBe('WEAREDISCOVEREDFLEEATONCE'); - expect(decodeRailFenceCipher('Hoo!el,Wrdl l', 3)).toBe('Hello, World!'); + expect(decodeRailFenceCipher('WECRLTEERDSOEEFEAOCAIVDEN', 3)).toBe( + 'WEAREDISCOVEREDFLEEATONCE', + ); + expect(decodeRailFenceCipher('Hoo!el,Wrdl l', 3)).toBe( + 'Hello, World!', + ); + expect(decodeRailFenceCipher('15243', 3)).toBe( + '12345', + ); }); it('encodes a string correctly for base=4', () => { expect(encodeRailFenceCipher('', 4)).toBe(''); - expect(encodeRailFenceCipher('THEYAREATTACKINGFROMTHENORTH', 4)).toBe('TEKOOHRACIRMNREATANFTETYTGHH'); + expect(encodeRailFenceCipher('THEYAREATTACKINGFROMTHENORTH', 4)).toBe( + 'TEKOOHRACIRMNREATANFTETYTGHH', + ); }); it('decodes a string correctly for base=4', () => { expect(decodeRailFenceCipher('', 4)).toBe(''); - expect(decodeRailFenceCipher('TEKOOHRACIRMNREATANFTETYTGHH', 4)).toBe('THEYAREATTACKINGFROMTHENORTH'); + expect(decodeRailFenceCipher('TEKOOHRACIRMNREATANFTETYTGHH', 4)).toBe( + 'THEYAREATTACKINGFROMTHENORTH', + ); }); }); diff --git a/src/algorithms/cryptography/rail-fence-cipher/decodeRailFence.js b/src/algorithms/cryptography/rail-fence-cipher/decodeRailFence.js deleted file mode 100644 index b1826b4883..0000000000 --- a/src/algorithms/cryptography/rail-fence-cipher/decodeRailFence.js +++ /dev/null @@ -1,108 +0,0 @@ -import { - addChar, - buildFence, - DIRECTIONS, - getNextDirection, -} from './railFenceCipher'; - -/** - * @param {object} params - * @param {number} params.railCount - * @param {number} params.strLen - * @param {Array} params.string - * @param {Array} params.fence - * @param {number} params.targetRail - * @param {number} params.direction - * @param {Array} params.coords - * - * @returns {Array} - */ -const fillDecodeFence = ({ - railCount, strLen, string, fence, targetRail, direction, coords, -}) => { - if (string.length === 0) return fence; - - const [currentRail, currentColumn] = coords; - const shouldGoNextRail = currentColumn === strLen - 1; - const nextDirection = shouldGoNextRail - ? DIRECTIONS.DOWN - : getNextDirection({ railCount, currentRail, direction }); - const nextRail = shouldGoNextRail ? targetRail + 1 : targetRail; - const nextCoords = [ - shouldGoNextRail ? 0 : currentRail + nextDirection, - shouldGoNextRail ? 0 : currentColumn + 1, - ]; - - const shouldAddChar = currentRail === targetRail; - const [currentChar, ...remainderString] = string; - const nextString = shouldAddChar ? remainderString : string; - const nextFence = shouldAddChar ? fence.map(addChar(currentRail, currentChar)) : fence; - - return fillDecodeFence({ - railCount, - strLen, - string: nextString, - fence: nextFence, - targetRail: nextRail, - direction: nextDirection, - coords: nextCoords, - }); -}; - -/** - * @param {object} params - * @param {number} params.railCount - * @param {number} params.strLen - * @param {Array} params.fence - * @param {number} params.currentRail - * @param {number} params.direction - * @param {Array} params.code - * - * @returns {string} - */ -const decodeFence = ({ - railCount, strLen, fence, currentRail, direction, code, -}) => { - if (code.length === strLen) return code.join(''); - - const [currentChar, ...nextRail] = fence[currentRail]; - const nextDirection = getNextDirection({ railCount, currentRail, direction }); - - return decodeFence({ - railCount, - strLen, - currentRail: currentRail + nextDirection, - direction: nextDirection, - code: [...code, currentChar], - fence: fence.map((rail, idx) => (idx === currentRail ? nextRail : rail)), - }); -}; - -/** - * @param {string} string - * @param {number} railCount - * - * @returns {string} - */ -export default function decodeRailFenceCipher(string, railCount) { - const strLen = string.length; - const emptyFence = buildFence(railCount); - const filledFence = fillDecodeFence({ - railCount, - strLen, - string: string.split(''), - fence: emptyFence, - targetRail: 0, - direction: DIRECTIONS.DOWN, - coords: [0, 0], - }); - - return decodeFence({ - railCount, - strLen, - fence: filledFence, - currentRail: 0, - direction: DIRECTIONS.DOWN, - code: [], - }); -} diff --git a/src/algorithms/cryptography/rail-fence-cipher/encodeRailFence.js b/src/algorithms/cryptography/rail-fence-cipher/encodeRailFence.js deleted file mode 100644 index 9a58131253..0000000000 --- a/src/algorithms/cryptography/rail-fence-cipher/encodeRailFence.js +++ /dev/null @@ -1,52 +0,0 @@ -import { - addChar, - buildFence, - DIRECTIONS, - getNextDirection, -} from './railFenceCipher'; - -/** - * @param {object} params - * @param {number} params.railCount - * @param {number} params.currentRail - * @param {number} params.direction - * @param {Array} params.string - * - * @returns {Array} - */ -const fillEncodeFence = ({ - railCount, fence, currentRail, direction, string, -}) => { - if (string.length === 0) return fence; - - const [letter, ...nextString] = string; - const nextDirection = getNextDirection({ railCount, currentRail, direction }); - - return fillEncodeFence({ - railCount, - fence: fence.map(addChar(currentRail, letter)), - currentRail: currentRail + nextDirection, - direction: nextDirection, - string: nextString, - }); -}; - -/** - * @param {string} string - * @param {number} railCount - * - * @returns {string} - */ -export default function encodeRailFenceCipher(string, railCount) { - const fence = buildFence(railCount); - - const filledFence = fillEncodeFence({ - railCount, - fence, - currentRail: 0, - direction: DIRECTIONS.DOWN, - string: string.split(''), - }); - - return filledFence.flat().join(''); -} diff --git a/src/algorithms/cryptography/rail-fence-cipher/railFenceCipher.js b/src/algorithms/cryptography/rail-fence-cipher/railFenceCipher.js index e50b477a36..7b58037e22 100644 --- a/src/algorithms/cryptography/rail-fence-cipher/railFenceCipher.js +++ b/src/algorithms/cryptography/rail-fence-cipher/railFenceCipher.js @@ -1,50 +1,242 @@ +/** + * @typedef {string[]} Rail + * @typedef {Rail[]} Fence + * @typedef {number} Direction + */ + /** * @constant DIRECTIONS * @type {object} - * @property {number} UP - * @property {number} DOWN + * @property {Direction} UP + * @property {Direction} DOWN */ -export const DIRECTIONS = { UP: -1, DOWN: 1 }; +const DIRECTIONS = { UP: -1, DOWN: 1 }; /** - * @param {number} rows + * Builds a fence with a specific number of rows. * - * @returns {Array} + * @param {number} rowsNum + * @returns {Fence} */ -export const buildFence = (rows) => Array(rows) - .fill() +const buildFence = (rowsNum) => Array(rowsNum) + .fill(null) .map(() => []); /** - * @param {object} params - * @param {number} params.railCount - * @param {number} params.currentRail - * @param {number} params.direction + * Get next direction to move (based on the current one) while traversing the fence. * - * @returns {number} + * @param {object} params + * @param {number} params.railCount - Number of rows in the fence + * @param {number} params.currentRail - Current row that we're visiting + * @param {Direction} params.direction - Current direction + * @returns {Direction} - The next direction to take */ -export const getNextDirection = ({ railCount, currentRail, direction }) => { +const getNextDirection = ({ railCount, currentRail, direction }) => { switch (currentRail) { - case 0: return DIRECTIONS.DOWN; - case railCount - 1: return DIRECTIONS.UP; - default: return direction; + case 0: + // Go down if we're on top of the fence. + return DIRECTIONS.DOWN; + case railCount - 1: + // Go up if we're at the bottom of the fence. + return DIRECTIONS.UP; + default: + // Continue with the same direction if we're in the middle of the fence. + return direction; } }; /** - * Given a rail, adds a char to it - * if it matches a targetIndex. - * @callback charAdder - * @param {number} rail - * @param {currentRail} number + * @param {number} targetRailIndex + * @param {string} letter + * @returns {Function} */ +const addCharToRail = (targetRailIndex, letter) => { + /** + * Given a rail, adds a char to it if it matches a targetIndex. + * + * @param {Rail} rail + * @param {number} currentRail + * @returns {Rail} + */ + function onEachRail(rail, currentRail) { + return currentRail === targetRailIndex + ? [...rail, letter] + : rail; + } + return onEachRail; +}; /** - * @param {number} targetIndex - * @param {string} letter + * Hangs the characters on the fence. * - * @returns {charAdder} + * @param {object} params + * @param {Fence} params.fence + * @param {number} params.currentRail + * @param {Direction} params.direction + * @param {string[]} params.chars + * @returns {Fence} + */ +const fillEncodeFence = ({ + fence, + currentRail, + direction, + chars, +}) => { + if (chars.length === 0) { + // All chars have been placed on a fence. + return fence; + } + + const railCount = fence.length; + + // Getting the next character to place on a fence. + const [letter, ...nextChars] = chars; + const nextDirection = getNextDirection({ + railCount, + currentRail, + direction, + }); + + return fillEncodeFence({ + fence: fence.map(addCharToRail(currentRail, letter)), + currentRail: currentRail + nextDirection, + direction: nextDirection, + chars: nextChars, + }); +}; + +/** + * @param {object} params + * @param {number} params.strLen + * @param {string[]} params.chars + * @param {Fence} params.fence + * @param {number} params.targetRail + * @param {Direction} params.direction + * @param {number[]} params.coords + * @returns {Fence} */ -export const addChar = (targetIndex, letter) => (rail, currentRail) => { - return (currentRail === targetIndex ? [...rail, letter] : rail); +const fillDecodeFence = (params) => { + const { + strLen, chars, fence, targetRail, direction, coords, + } = params; + + const railCount = fence.length; + + if (chars.length === 0) { + return fence; + } + + const [currentRail, currentColumn] = coords; + const shouldGoNextRail = currentColumn === strLen - 1; + const nextDirection = shouldGoNextRail + ? DIRECTIONS.DOWN + : getNextDirection( + { railCount, currentRail, direction }, + ); + const nextRail = shouldGoNextRail ? targetRail + 1 : targetRail; + const nextCoords = [ + shouldGoNextRail ? 0 : currentRail + nextDirection, + shouldGoNextRail ? 0 : currentColumn + 1, + ]; + + const shouldAddChar = currentRail === targetRail; + const [currentChar, ...remainderChars] = chars; + const nextString = shouldAddChar ? remainderChars : chars; + const nextFence = shouldAddChar ? fence.map(addCharToRail(currentRail, currentChar)) : fence; + + return fillDecodeFence({ + strLen, + chars: nextString, + fence: nextFence, + targetRail: nextRail, + direction: nextDirection, + coords: nextCoords, + }); +}; + +/** + * @param {object} params + * @param {number} params.strLen + * @param {Fence} params.fence + * @param {number} params.currentRail + * @param {Direction} params.direction + * @param {number[]} params.code + * @returns {string} + */ +const decodeFence = (params) => { + const { + strLen, + fence, + currentRail, + direction, + code, + } = params; + + if (code.length === strLen) { + return code.join(''); + } + + const railCount = fence.length; + + const [currentChar, ...nextRail] = fence[currentRail]; + const nextDirection = getNextDirection( + { railCount, currentRail, direction }, + ); + + return decodeFence({ + railCount, + strLen, + currentRail: currentRail + nextDirection, + direction: nextDirection, + code: [...code, currentChar], + fence: fence.map((rail, idx) => (idx === currentRail ? nextRail : rail)), + }); +}; + +/** + * Encodes the message using Rail Fence Cipher. + * + * @param {string} string - The string to be encoded + * @param {number} railCount - The number of rails in a fence + * @returns {string} - Encoded string + */ +export const encodeRailFenceCipher = (string, railCount) => { + const fence = buildFence(railCount); + + const filledFence = fillEncodeFence({ + fence, + currentRail: 0, + direction: DIRECTIONS.DOWN, + chars: string.split(''), + }); + + return filledFence.flat().join(''); +}; + +/** + * Decodes the message using Rail Fence Cipher. + * + * @param {string} string - Encoded string + * @param {number} railCount - The number of rows in a fence + * @returns {string} - Decoded string. + */ +export const decodeRailFenceCipher = (string, railCount) => { + const strLen = string.length; + const emptyFence = buildFence(railCount); + const filledFence = fillDecodeFence({ + strLen, + chars: string.split(''), + fence: emptyFence, + targetRail: 0, + direction: DIRECTIONS.DOWN, + coords: [0, 0], + }); + + return decodeFence({ + strLen, + fence: filledFence, + currentRail: 0, + direction: DIRECTIONS.DOWN, + code: [], + }); }; From 521e0a9bbd8f4e2ff5bd29840a3d7305fd07351c Mon Sep 17 00:00:00 2001 From: Andy Chen <25174488+KsRyY@users.noreply.github.com> Date: Mon, 21 Dec 2020 03:00:44 +0800 Subject: [PATCH 057/264] Remove a extra space (#291) From fa1f930c99bf869e0074515f981cd018da185412 Mon Sep 17 00:00:00 2001 From: Brandon Villa Date: Sun, 20 Dec 2020 13:05:18 -0600 Subject: [PATCH 058/264] Add missing step (#345) --- src/data-structures/linked-list/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/data-structures/linked-list/README.md b/src/data-structures/linked-list/README.md index 2b8a7507b6..f357889de6 100644 --- a/src/data-structures/linked-list/README.md +++ b/src/data-structures/linked-list/README.md @@ -102,6 +102,7 @@ Remove(head, value) if n.next != ø if n.next = tail tail ← n + tail.next = null end if n.next ← n.next.next return true From f617569760979d540f795e41f039e93204c91af0 Mon Sep 17 00:00:00 2001 From: Go Date: Mon, 21 Dec 2020 04:06:36 +0900 Subject: [PATCH 059/264] fix typo (#350) --- src/algorithms/string/levenshtein-distance/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/string/levenshtein-distance/README.md b/src/algorithms/string/levenshtein-distance/README.md index 4d4078b854..8876d6791c 100644 --- a/src/algorithms/string/levenshtein-distance/README.md +++ b/src/algorithms/string/levenshtein-distance/README.md @@ -50,7 +50,7 @@ to assist natural language translation based on translation memory. Let’s take a simple example of finding minimum edit distance between strings `ME` and `MY`. Intuitively you already know that minimum edit distance -here is `1` operation and this operation. And it is replacing `E` with `Y`. But +here is `1` operation, which is replacing `E` with `Y`. But let’s try to formalize it in a form of the algorithm in order to be able to do more complex examples like transforming `Saturday` into `Sunday`. From e07620359090a8f372fe2b4297bb9e806d5d0343 Mon Sep 17 00:00:00 2001 From: Yura Sherman Date: Sun, 20 Dec 2020 21:09:09 +0200 Subject: [PATCH 060/264] Fix a grammar mistake (#396) --- src/data-structures/bloom-filter/README.ru-RU.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data-structures/bloom-filter/README.ru-RU.md b/src/data-structures/bloom-filter/README.ru-RU.md index 38830f9efb..b5c19c06c8 100644 --- a/src/data-structures/bloom-filter/README.ru-RU.md +++ b/src/data-structures/bloom-filter/README.ru-RU.md @@ -19,7 +19,7 @@ срабатываний фильтра. Вот пример Блум фильтра, представляющего набор `{x, y, z}`. Цветные стрелки показывают позиции в битовом массиве, -которым привязан каждый элемент набора. Элемент `w` не в набора `{x, y, z}`, потому что он привязан к позиции в битовом +которым привязан каждый элемент набора. Элемент `w` не в наборе `{x, y, z}`, потому что он привязан к позиции в битовом массиве, равной `0`. Для этой формы , `m = 18`, а `k = 3`. Фильтр Блума представляет собой битовый массив из `m` бит. Изначально, когда структура данных хранит пустое множество, все From 148f9179c941d9586e36930af4d80c9f2f74bbbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Savi=C3=B1on?= <44041766+Mengeroshi@users.noreply.github.com> Date: Sun, 20 Dec 2020 13:16:35 -0600 Subject: [PATCH 061/264] Linked List Spanish Traslation (#409) * Linked List Spanish Traslation * Rename the CI workflow file. Co-authored-by: Oleksii Trekhleb --- .../linked-list/README.es-ES.md | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 src/data-structures/linked-list/README.es-ES.md diff --git a/src/data-structures/linked-list/README.es-ES.md b/src/data-structures/linked-list/README.es-ES.md new file mode 100644 index 0000000000..978e234ddf --- /dev/null +++ b/src/data-structures/linked-list/README.es-ES.md @@ -0,0 +1,164 @@ +# Lista Enlazada (Linked List) + +_Lee esto en otros idiomas:_ +[_简体中文_](README.zh-CN.md), +[_Русский_](README.ru-RU.md), +[_日本語_](README.ja-JP.md), +[_Português_](README.pt-BR.md) +[_English_](README.md) + +En ciencias de la computaciòn una **lista enlazada** es una coleccion linear +de elemntos de datos, en los cuales el orden linear no es dado por +su posciòn fisica en memoria. En cambio, cada +elemento señala al siguiente. Es una estructura de datos +que consiste en un grupo de nodos los cuales juntos representan +una secuencia. Bajo la forma mas simple, cada nodo es +compuesto de datos y una referencia (en otras palabras, +un lazo) al siguiente nodo en la secuencia. Esta estructura +permite la insercion o remocion de elementos +desde cualquier posicion en la secuencia durante la iteracion. +Variantes mas complejas agregan lazos adicionales, permitiendo +una eficiente insercion o remocion desde referencias arbitrarias +del elemento. Una desventaja de las listas lazadas es que el tiempo de +acceso es linear (y dificil de canalizar) Un acceso +mas rapido, como un acceso aleatorio, no es factible. Los arreglos +tienen una mejor locazion comparados con las listas lazadas. + + +![Linked List](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) + +## Pseudocodigo para operacones basicas + +### Insertar + +```text +Add(value) + Pre: value is the value to add to the list + Post: value has been placed at the tail of the list + n ← node(value) + if head = ø + head ← n + tail ← n + else + tail.next ← n + tail ← n + end if +end Add +``` + +```text +Prepend(value) + Pre: value is the value to add to the list + Post: value has been placed at the head of the list + n ← node(value) + n.next ← head + head ← n + if tail = ø + tail ← n + end +end Prepend +``` + +### Buscar + +```text +Contains(head, value) + Pre: head is the head node in the list + value is the value to search for + Post: the item is either in the linked list, true; otherwise false + n ← head + while n != ø and n.value != value + n ← n.next + end while + if n = ø + return false + end if + return true +end Contains +``` + +### Borrar + +```text +Remove(head, value) + Pre: head is the head node in the list + value is the value to remove from the list + Post: value is removed from the list, true, otherwise false + if head = ø + return false + end if + n ← head + if n.value = value + if head = tail + head ← ø + tail ← ø + else + head ← head.next + end if + return true + end if + while n.next != ø and n.next.value != value + n ← n.next + end while + if n.next != ø + if n.next = tail + tail ← n + end if + n.next ← n.next.next + return true + end if + return false +end Remove +``` + +### Atrevesar + +```text +Traverse(head) + Pre: head is the head node in the list + Post: the items in the list have been traversed + n ← head + while n != ø + yield n.value + n ← n.next + end while +end Traverse +``` + +### Atravesar en Reversa + +```text +ReverseTraversal(head, tail) + Pre: head and tail belong to the same list + Post: the items in the list have been traversed in reverse order + if tail != ø + curr ← tail + while curr != head + prev ← head + while prev.next != curr + prev ← prev.next + end while + yield curr.value + curr ← prev + end while + yield curr.value + end if +end ReverseTraversal +``` + +## Complexities + +### Time Complexity + +| Access | Search | Insertion | Deletion | +| :-------: | :-------: | :-------: | :-------: | +| O(n) | O(n) | O(1) | O(n) | + +### Space Complexity + +O(n) + +## References + +- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list) +- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) From 4b6c601158b7b0284c9aad3a899fe97285fc7c1a Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sun, 20 Dec 2020 20:18:12 +0100 Subject: [PATCH 062/264] Add Spanish link for the Linked List README. --- src/algorithms/math/is-power-of-two/README.md | 15 ++++---- src/data-structures/linked-list/README.md | 35 ++++++++++--------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/algorithms/math/is-power-of-two/README.md b/src/algorithms/math/is-power-of-two/README.md index 8253cb8700..6ed1e92568 100644 --- a/src/algorithms/math/is-power-of-two/README.md +++ b/src/algorithms/math/is-power-of-two/README.md @@ -1,14 +1,13 @@ # Is a power of two -Given a positive integer, write a function to find if it is +Given a positive integer, write a function to find if it is a power of two or not. **Naive solution** In naive solution we just keep dividing the number by two -unless the number becomes `1` and every time we do so we -check that remainder after division is always `0`. Otherwise -the number can't be a power of two. +unless the number becomes `1` and every time we do so, we +check that remainder after division is always `0`. Otherwise, the number can't be a power of two. **Bitwise solution** @@ -23,8 +22,8 @@ signed integer with a value of -128 looks like: `10000000`) 8: 1000 ``` -So after checking that the number is greater than zero, -we can use a bitwise hack to test that one and only one +So after checking that the number is greater than zero, +we can use a bitwise hack to test that one and only one bit is set. ``` @@ -38,11 +37,11 @@ For example for number `8` that operations will look like: - 0001 ---- 0111 - + 1000 & 0111 ---- - 0000 + 0000 ``` ## References diff --git a/src/data-structures/linked-list/README.md b/src/data-structures/linked-list/README.md index f357889de6..656ad68f58 100644 --- a/src/data-structures/linked-list/README.md +++ b/src/data-structures/linked-list/README.md @@ -5,23 +5,24 @@ _Read this in other languages:_ [_Русский_](README.ru-RU.md), [_日本語_](README.ja-JP.md), [_Português_](README.pt-BR.md), -[_한국어_](README.ko-KR.md) - -In computer science, a **linked list** is a linear collection -of data elements, in which linear order is not given by -their physical placement in memory. Instead, each -element points to the next. It is a data structure -consisting of a group of nodes which together represent -a sequence. Under the simplest form, each node is -composed of data and a reference (in other words, +[_한국어_](README.ko-KR.md), +[_Español_](README.es-ES.md), + +In computer science, a **linked list** is a linear collection +of data elements, in which linear order is not given by +their physical placement in memory. Instead, each +element points to the next. It is a data structure +consisting of a group of nodes which together represent +a sequence. Under the simplest form, each node is +composed of data and a reference (in other words, a link) to the next node in the sequence. This structure -allows for efficient insertion or removal of elements -from any position in the sequence during iteration. -More complex variants add additional links, allowing -efficient insertion or removal from arbitrary element -references. A drawback of linked lists is that access -time is linear (and difficult to pipeline). Faster -access, such as random access, is not feasible. Arrays +allows for efficient insertion or removal of elements +from any position in the sequence during iteration. +More complex variants add additional links, allowing +efficient insertion or removal from arbitrary element +references. A drawback of linked lists is that access +time is linear (and difficult to pipeline). Faster +access, such as random access, is not feasible. Arrays have better cache locality as compared to linked lists. ![Linked List](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) @@ -75,7 +76,7 @@ Contains(head, value) return true end Contains ``` - + ### Delete ```text From 37871171a5f20cb6ccd3d1409af483852f22423f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 22 Dec 2020 16:59:06 +0100 Subject: [PATCH 063/264] Bump node-notifier from 8.0.0 to 8.0.1 (#607) Bumps [node-notifier](https://github.com/mikaelbr/node-notifier) from 8.0.0 to 8.0.1. - [Release notes](https://github.com/mikaelbr/node-notifier/releases) - [Changelog](https://github.com/mikaelbr/node-notifier/blob/v8.0.1/CHANGELOG.md) - [Commits](https://github.com/mikaelbr/node-notifier/compare/v8.0.0...v8.0.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index e68c95c1e5..7b212c5f47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4432,8 +4432,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true, - "optional": true + "dev": true }, "har-schema": { "version": "2.0.0", @@ -5069,7 +5068,6 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, - "optional": true, "requires": { "is-docker": "^2.0.0" } @@ -7140,11 +7138,10 @@ "dev": true }, "node-notifier": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.0.tgz", - "integrity": "sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz", + "integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==", "dev": true, - "optional": true, "requires": { "growly": "^1.3.0", "is-wsl": "^2.2.0", @@ -7159,7 +7156,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", "dev": true, - "optional": true, "requires": { "lru-cache": "^6.0.0" } @@ -8113,8 +8109,7 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true, - "optional": true + "dev": true }, "side-channel": { "version": "1.0.3", @@ -8881,8 +8876,7 @@ "version": "8.3.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", - "dev": true, - "optional": true + "dev": true }, "v8-compile-cache": { "version": "2.2.0", From bc53ba7362517f8d4b821c26304f570d37708488 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Tue, 22 Dec 2020 17:04:51 +0100 Subject: [PATCH 064/264] Update dependencies. --- package-lock.json | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7b212c5f47..ce714a9c07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4432,7 +4432,8 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true + "dev": true, + "optional": true }, "har-schema": { "version": "2.0.0", @@ -5068,6 +5069,7 @@ "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, + "optional": true, "requires": { "is-docker": "^2.0.0" } @@ -7142,6 +7144,7 @@ "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz", "integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==", "dev": true, + "optional": true, "requires": { "growly": "^1.3.0", "is-wsl": "^2.2.0", @@ -7156,6 +7159,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", "dev": true, + "optional": true, "requires": { "lru-cache": "^6.0.0" } @@ -8109,7 +8113,8 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true + "dev": true, + "optional": true }, "side-channel": { "version": "1.0.3", @@ -8876,7 +8881,8 @@ "version": "8.3.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", - "dev": true + "dev": true, + "optional": true }, "v8-compile-cache": { "version": "2.2.0", From e71dc8dc1690a631d55dd07d15369dc3d87fcb3d Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Tue, 22 Dec 2020 17:08:53 +0100 Subject: [PATCH 065/264] Update dependencies. --- package-lock.json | 310 +++++++++++++++++++++++++--------------------- package.json | 22 ++-- 2 files changed, 180 insertions(+), 152 deletions(-) diff --git a/package-lock.json b/package-lock.json index ce714a9c07..aeeed97b47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@babel/cli": { - "version": "7.12.8", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.12.8.tgz", - "integrity": "sha512-/6nQj11oaGhLmZiuRUfxsujiPDc9BBReemiXgIbxc+M5W+MIiFKYwvNDJvBfnGKNsJTKbUfEheKc9cwoPHAVQA==", + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.12.10.tgz", + "integrity": "sha512-+y4ZnePpvWs1fc/LhZRTHkTesbXkyBYuOB+5CyodZqrEuETXi3zOVfpAQIdgC3lXbHLTDG9dQosxR9BhvLKDLQ==", "dev": true, "requires": { "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents", @@ -99,12 +99,31 @@ } }, "@babel/helper-annotate-as-pure": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", - "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz", + "integrity": "sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ==", "dev": true, "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.12.10" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "dev": true + }, + "@babel/types": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.11.tgz", + "integrity": "sha512-ukA9SQtKThINm++CX1CwmliMrE54J6nIYB5XTwL5f/CLFW9owfls+YSU8tVW15RQ2w+a3fSbPjC6HdQNtWZkiA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.12.11", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-builder-binary-assignment-operator-visitor": { @@ -308,9 +327,9 @@ "dev": true }, "@babel/helper-validator-option": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz", - "integrity": "sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz", + "integrity": "sha512-TBFCyj939mFSdeX7U7DDj32WtzYY7fDcalgq8v3fBZMNOJQNn7nOYzMaUCiPxPYfCup69mtIpqlKgMZLvQ8Xhw==", "dev": true }, "@babel/helper-wrap-function": { @@ -642,9 +661,9 @@ } }, "@babel/plugin-transform-block-scoping": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz", - "integrity": "sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.11.tgz", + "integrity": "sha512-atR1Rxc3hM+VPg/NvNvfYw0npQEAcHuJ+MGZnFn6h3bo+1U3BWXMdFMlvVRApBTWKQMX7SOwRJZA5FBF/JQbvA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" @@ -898,9 +917,9 @@ } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.1.tgz", - "integrity": "sha512-EPGgpGy+O5Kg5pJFNDKuxt9RdmTgj5sgrus2XVeMp/ZIbOESadgILUbm50SNpghOh3/6yrbsH+NB5+WJTmsA7Q==", + "version": "7.12.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.10.tgz", + "integrity": "sha512-JQ6H8Rnsogh//ijxspCjc21YPd3VLVoYtAwv3zQmqAt8YGYUtdo5usNhdl4b9/Vir2kPFZl6n1h0PfUz4hJhaA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.10.4" @@ -926,16 +945,16 @@ } }, "@babel/preset-env": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.7.tgz", - "integrity": "sha512-OnNdfAr1FUQg7ksb7bmbKoby4qFOHw6DKWWUNB9KqnnCldxhxJlP+21dpyaWFmf2h0rTbOkXJtAGevY3XW1eew==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.11.tgz", + "integrity": "sha512-j8Tb+KKIXKYlDBQyIOy4BLxzv1NUOwlHfZ74rvW+Z0Gp4/cI2IMDPBWAgWceGcE7aep9oL/0K9mlzlMGxA8yNw==", "dev": true, "requires": { "@babel/compat-data": "^7.12.7", "@babel/helper-compilation-targets": "^7.12.5", "@babel/helper-module-imports": "^7.12.5", "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-validator-option": "^7.12.1", + "@babel/helper-validator-option": "^7.12.11", "@babel/plugin-proposal-async-generator-functions": "^7.12.1", "@babel/plugin-proposal-class-properties": "^7.12.1", "@babel/plugin-proposal-dynamic-import": "^7.12.1", @@ -964,7 +983,7 @@ "@babel/plugin-transform-arrow-functions": "^7.12.1", "@babel/plugin-transform-async-to-generator": "^7.12.1", "@babel/plugin-transform-block-scoped-functions": "^7.12.1", - "@babel/plugin-transform-block-scoping": "^7.12.1", + "@babel/plugin-transform-block-scoping": "^7.12.11", "@babel/plugin-transform-classes": "^7.12.1", "@babel/plugin-transform-computed-properties": "^7.12.1", "@babel/plugin-transform-destructuring": "^7.12.1", @@ -990,13 +1009,32 @@ "@babel/plugin-transform-spread": "^7.12.1", "@babel/plugin-transform-sticky-regex": "^7.12.7", "@babel/plugin-transform-template-literals": "^7.12.1", - "@babel/plugin-transform-typeof-symbol": "^7.12.1", + "@babel/plugin-transform-typeof-symbol": "^7.12.10", "@babel/plugin-transform-unicode-escapes": "^7.12.1", "@babel/plugin-transform-unicode-regex": "^7.12.1", "@babel/preset-modules": "^0.1.3", - "@babel/types": "^7.12.7", - "core-js-compat": "^3.7.0", + "@babel/types": "^7.12.11", + "core-js-compat": "^3.8.0", "semver": "^5.5.0" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "dev": true + }, + "@babel/types": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.11.tgz", + "integrity": "sha512-ukA9SQtKThINm++CX1CwmliMrE54J6nIYB5XTwL5f/CLFW9owfls+YSU8tVW15RQ2w+a3fSbPjC6HdQNtWZkiA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.12.11", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/preset-modules": { @@ -1104,9 +1142,9 @@ } }, "@eslint/eslintrc": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.1.tgz", - "integrity": "sha512-XRUeBZ5zBWLYgSANMpThFddrZZkEbGHgUdt5UJjZfnlN9BGCiUBrf+nvbRupSjMvqzwnQN0qwCmOxITt1cfywA==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", + "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -1948,9 +1986,9 @@ } }, "@types/jest": { - "version": "26.0.16", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.16.tgz", - "integrity": "sha512-Gp12+7tmKCgv9JjtltxUXokohCAEZfpJaEW5tn871SGRp8I+bRWBonQO7vW5NHwnAHe5dd50+Q4zyKuN35i09g==", + "version": "26.0.19", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.19.tgz", + "integrity": "sha512-jqHoirTG61fee6v6rwbnEuKhpSKih0tuhqeFbCmMmErhtu3BYlOZaXWjffgOstMM4S/3iQD31lI5bGLTrs97yQ==", "dev": true, "requires": { "jest-diff": "^26.0.0", @@ -2314,9 +2352,9 @@ "dev": true }, "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true }, "async-each": { @@ -2622,14 +2660,14 @@ "dev": true }, "browserslist": { - "version": "4.15.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.15.0.tgz", - "integrity": "sha512-IJ1iysdMkGmjjYeRlDU8PQejVwxvVO5QOfXH7ylW31GO6LwNRSmm/SgRXtNsEXqMLl2e+2H5eEJ7sfynF8TCaQ==", + "version": "4.16.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.0.tgz", + "integrity": "sha512-/j6k8R0p3nxOC6kx5JGAxsnhc9ixaWJfYc+TNTzxg6+ARaESAvQGV7h0uNOB4t+pLQJZWzcrMxXOxjgsCj3dqQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001164", + "caniuse-lite": "^1.0.30001165", "colorette": "^1.2.1", - "electron-to-chromium": "^1.3.612", + "electron-to-chromium": "^1.3.621", "escalade": "^3.1.1", "node-releases": "^1.1.67" } @@ -2689,9 +2727,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001165", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001165.tgz", - "integrity": "sha512-8cEsSMwXfx7lWSUMA2s08z9dIgsnR5NAqjXP23stdsU3AUWkCr/rr4s4OFtHXn5XXr6+7kam3QFVoYyXNPdJPA==", + "version": "1.0.30001170", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001170.tgz", + "integrity": "sha512-Dd4d/+0tsK0UNLrZs3CvNukqalnVTRrxb5mcQm8rHL49t7V5ZaTygwXkrq+FB+dVDf++4ri8eJnFEJAB8332PA==", "dev": true }, "capture-exit": { @@ -3005,12 +3043,12 @@ "dev": true }, "core-js-compat": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.0.tgz", - "integrity": "sha512-o9QKelQSxQMYWHXc/Gc4L8bx/4F7TTraE5rhuN8I7mKBt5dBIUpXpIR3omv70ebr8ST5R3PqbDQr+ZI3+Tt1FQ==", + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.1.tgz", + "integrity": "sha512-a16TLmy9NVD1rkjUGbwuyWkiDoN0FDpAwrfLONvHFQx0D9k7J9y0srwMT8QP/Z6HE3MIFaVynEeYwZwPX1o5RQ==", "dev": true, "requires": { - "browserslist": "^4.14.7", + "browserslist": "^4.15.0", "semver": "7.0.0" }, "dependencies": { @@ -3288,9 +3326,9 @@ } }, "electron-to-chromium": { - "version": "1.3.616", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.616.tgz", - "integrity": "sha512-CI8L38UN2BEnqXw3/oRIQTmde0LiSeqWSRlPA42ZTYgJQ8fYenzAM2Z3ni+jtILTcrs5aiXZCGJ96Pm+3/yGyQ==", + "version": "1.3.631", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.631.tgz", + "integrity": "sha512-mPEG/52142po0XK1jQkZtbMmp38MZtQ3JDFItYxV65WXyhxDYEQ54tP4rb93m0RbMlZqQ+4zBw2N7UumSgGfbA==", "dev": true }, "emittery": { @@ -3300,9 +3338,9 @@ "dev": true }, "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "end-of-stream": { @@ -3437,13 +3475,13 @@ } }, "eslint": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.14.0.tgz", - "integrity": "sha512-5YubdnPXrlrYAFCKybPuHIAH++PINe1pmKNc5wQRB9HSbqIK1ywAnntE3Wwua4giKu0bjligf1gLF6qxMGOYRA==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.16.0.tgz", + "integrity": "sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.2.1", + "@eslint/eslintrc": "^0.2.2", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -3453,10 +3491,10 @@ "eslint-scope": "^5.1.1", "eslint-utils": "^2.1.0", "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.0", + "espree": "^7.3.1", "esquery": "^1.2.0", "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", + "file-entry-cache": "^6.0.0", "functional-red-black-tree": "^1.0.1", "glob-parent": "^5.0.0", "globals": "^12.1.0", @@ -3476,7 +3514,7 @@ "semver": "^7.2.1", "strip-ansi": "^6.0.0", "strip-json-comments": "^3.1.0", - "table": "^5.2.3", + "table": "^6.0.4", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, @@ -3749,13 +3787,13 @@ "dev": true }, "espree": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.0.tgz", - "integrity": "sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw==", + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", "dev": true, "requires": { "acorn": "^7.4.0", - "acorn-jsx": "^5.2.0", + "acorn-jsx": "^5.3.1", "eslint-visitor-keys": "^1.3.0" }, "dependencies": { @@ -4169,12 +4207,12 @@ } }, "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz", + "integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==", "dev": true, "requires": { - "flat-cache": "^2.0.1" + "flat-cache": "^3.0.4" } }, "fill-range": { @@ -4219,20 +4257,19 @@ } }, "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" } }, "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz", + "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==", "dev": true }, "for-in": { @@ -4543,9 +4580,9 @@ "dev": true }, "husky": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.0.tgz", - "integrity": "sha512-tTMeLCLqSBqnflBZnlVDhpaIMucSGaYyX6855jM4AguGeWCeSzNdb1mfyWduTZ3pe3SJVvVWGL0jO1iKZVPfTA==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.6.tgz", + "integrity": "sha512-o6UjVI8xtlWRL5395iWq9LKDyp/9TE7XMOTvIpEVzW638UcGxTmV5cfel6fsk/jbZSTlvfGVJf2svFtybcIZag==", "dev": true, "requires": { "chalk": "^4.0.0", @@ -4691,9 +4728,9 @@ "dev": true }, "import-fresh": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.2.tgz", - "integrity": "sha512-cTPNrlvJT6twpYy+YmKUKrTSjWFs3bjYjAhCwm+z4EOCubZxAuO+hHpRN64TqjEaYSHs7tJAE0w1CKMGmsG/lw==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { "parent-module": "^1.0.0", @@ -4961,9 +4998,9 @@ "dev": true }, "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, "is-generator-fn": { @@ -7081,15 +7118,6 @@ } } }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -7980,9 +8008,9 @@ "dev": true }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" @@ -8145,14 +8173,40 @@ "dev": true }, "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } } }, "snapdragon": { @@ -8424,31 +8478,14 @@ } }, "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" } }, "string.prototype.matchall": { @@ -8572,15 +8609,15 @@ "dev": true }, "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/table/-/table-6.0.4.tgz", + "integrity": "sha512-sBT4xRLdALd+NFBvwOz8bw4b15htyythha+q+DVZqy2RS08PPC8O2sZFgJYEY7bJvbCFKccs+WIZ/cd+xxTWCw==", "dev": true, "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" + "ajv": "^6.12.4", + "lodash": "^4.17.20", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0" } }, "terminal-link": { @@ -9082,15 +9119,6 @@ "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, "write-file-atomic": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", diff --git a/package.json b/package.json index b740fa4878..73da04e0cf 100644 --- a/package.json +++ b/package.json @@ -34,17 +34,17 @@ }, "homepage": "https://github.com/trekhleb/javascript-algorithms#readme", "devDependencies": { - "@babel/cli": "^7.12.8", - "@babel/preset-env": "^7.12.7", - "@types/jest": "^26.0.16", - "eslint": "^7.14.0", - "eslint-config-airbnb": "^18.2.1", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jest": "^24.1.3", - "eslint-plugin-jsx-a11y": "^6.4.1", - "eslint-plugin-react": "^7.21.5", - "husky": "^4.3.0", - "jest": "^26.6.3" + "@babel/cli": "7.12.10", + "@babel/preset-env": "7.12.11", + "@types/jest": "26.0.19", + "eslint": "7.16.0", + "eslint-config-airbnb": "18.2.1", + "eslint-plugin-import": "2.22.1", + "eslint-plugin-jest": "24.1.3", + "eslint-plugin-jsx-a11y": "6.4.1", + "eslint-plugin-react": "7.21.5", + "husky": "4.3.6", + "jest": "26.6.3" }, "dependencies": {} } From 4973392cb9f676a2605a1abe16fb8f5025e1c28e Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 23 Dec 2020 17:01:13 +0100 Subject: [PATCH 066/264] Add divide and conquer example: best time to buy and sell stocks. --- README.md | 14 ++- .../best-time-to-buy-sell-stocks/README.md | 107 ++++++++++++++++++ ...accumulatorBestTimeToBuySellStocks.test.js | 48 ++++++++ .../dqBestTimeToBuySellStocks.test.js | 48 ++++++++ .../peakvalleyBestTimeToBuySellStocks.test.js | 48 ++++++++ .../accumulatorBestTimeToBuySellStocks.js | 20 ++++ .../dqBestTimeToBuySellStocks.js | 42 +++++++ .../peakvalleyBestTimeToBuySellStocks.js | 35 ++++++ 8 files changed, 356 insertions(+), 6 deletions(-) create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/accumulatorBestTimeToBuySellStocks.test.js create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dqBestTimeToBuySellStocks.test.js create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/peakvalleyBestTimeToBuySellStocks.test.js create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/accumulatorBestTimeToBuySellStocks.js create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dqBestTimeToBuySellStocks.js create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/peakvalleyBestTimeToBuySellStocks.js diff --git a/README.md b/README.md index feb9832d36..f7ae004523 100644 --- a/README.md +++ b/README.md @@ -129,9 +129,9 @@ a set of rules that precisely define a sequence of operations. * `B` [Depth-First Search](src/algorithms/graph/depth-first-search) (DFS) * `B` [Breadth-First Search](src/algorithms/graph/breadth-first-search) (BFS) * `B` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph - * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding shortest paths to all graph vertices from single vertex - * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding shortest paths to all graph vertices from single vertex - * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - find shortest paths between all pairs of vertices + * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding the shortest paths to all graph vertices from single vertex + * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding the shortest paths to all graph vertices from single vertex + * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - find the shortest paths between all pairs of vertices * `A` [Detect Cycle](src/algorithms/graph/detect-cycle) - for both directed and undirected graphs (DFS and Disjoint Set based versions) * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph * `A` [Topological Sorting](src/algorithms/graph/topological-sorting) - DFS method @@ -157,6 +157,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (dynamic programming and brute force versions) * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top (4 solutions) + * `B` [Best Time To Buy Sell Stocks](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - divide and conquer and one-pass examples * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens) * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour) @@ -176,7 +177,7 @@ algorithm is an abstraction higher than a computer program. * **Greedy** - choose the best option at the current time, without any consideration for the future * `B` [Jump Game](src/algorithms/uncategorized/jump-game) * `A` [Unbound Knapsack Problem](src/algorithms/sets/knapsack-problem) - * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding shortest path to all graph vertices + * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding the shortest path to all graph vertices * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph * `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph * **Divide and Conquer** - divide the problem into smaller parts and then solve those parts @@ -191,6 +192,7 @@ algorithm is an abstraction higher than a computer program. * `B` [Matrices](src/algorithms/math/matrix) - generating and traversing the matrices of different shapes * `B` [Jump Game](src/algorithms/uncategorized/jump-game) * `B` [Fast Powering](src/algorithms/math/fast-powering) + * `B` [Best Time To Buy Sell Stocks](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - divide and conquer and one-pass examples * `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions) * `A` [Combinations](src/algorithms/sets/combinations) (with and without repetitions) * **Dynamic Programming** - build up a solution using previously found sub-solutions @@ -207,8 +209,8 @@ algorithm is an abstraction higher than a computer program. * `A` [0/1 Knapsack Problem](src/algorithms/sets/knapsack-problem) * `A` [Integer Partition](src/algorithms/math/integer-partition) * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray) - * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding shortest path to all graph vertices - * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - find shortest paths between all pairs of vertices + * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding the shortest path to all graph vertices + * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - find the shortest paths between all pairs of vertices * `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching) * **Backtracking** - similarly to brute force, try to generate all possible solutions, but each time you generate next solution you test if it satisfies all conditions, and only then continue generating subsequent solutions. Otherwise, backtrack, and go on a diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md new file mode 100644 index 0000000000..982262d94d --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md @@ -0,0 +1,107 @@ +# Best Time to Buy and Sell Stock + +## Task Description + +Say you have an array prices for which the `i`-th element is the price of a given stock on day `i`. + +Find the maximum profit. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times). + +> Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again). + +**Example #1** + +``` +Input: [7, 1, 5, 3, 6, 4] +Output: 7 +``` + +_Explanation:_ Buy on day `2` (`price = 1`) and sell on day `3` (`price = 5`), `profit = 5-1 = 4`. Then buy on day `4` (`price = 3`) and sell on day `5` (`price = 6`), `profit = 6-3 = 3`. + +**Example #2** + +``` +Input: [1, 2, 3, 4, 5] +Output: 4 +``` + +_Explanation:_ Buy on day `1` (`price = 1`) and sell on day `5` (`price = 5`), `profit = 5-1 = 4`. Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are engaging multiple transactions at the same time. You must sell before buying again. + +**Example #3** + +``` +Input: [7, 6, 4, 3, 1] +Output: 0 +``` + +_Explanation:_ In this case, no transaction is done, i.e. max `profit = 0`. + +## Possible Solutions + +### Divide and conquer approach + +We may try **all** combinations of buying and selling and find out the most profitable one by applying _divide and conquer approach_. + +Let's say we have an array of prices `[7, 6, 4, 3, 1]` and we're on the _1st_ day of trading (at the very beginning of the array). At this point we may say that the overall maximum profit would be the _maximum_ of two following values: + +1. _Option 1: Keep the money_ → profit would equal to the profit from buying/selling the rest of the stocks → `keepProfit = profit([6, 4, 3, 1])`. +2. _Option 2: Buy/sell at current price_ → profit in this case would equal to the profit from buying/selling the rest of the stocks plus (or minus, depending on whether we're selling or buying) the current stock price → `buySellProfit = -7 + profit([6, 4, 3, 1])`. + +The overall profit would be equal to → `overalProfit = Max(keepProfit, buySellProfit)`. + +As you can see the `profit([6, 4, 3, 1])` task is being solved in the same recursive manner. + +> See the full code example in [dqBestTimeToBuySellStocks.js](dqBestTimeToBuySellStocks.js) + +#### Time Complexity + +As you may see, every recursive call will produce _2_ more recursive branches. The depth of the recursion will be `n` (size of prices array) and thus, the time complexity will equal to `O(2^n)`. + +As you may see, this is very inefficient. For example for just `20` prices the number of recursive calls will be somewhere close to `2M`! + +#### Additional Space Complexity + +If we avoid cloning the prices array between recursive function calls and will use the array pointer then additional space complexity will be proportional to the depth of the recursion: `O(n)` + +## Peak Valley Approach + +If we plot the prices array (i.e. `[7, 1, 5, 3, 6, 4]`) we may notice that the points of interest are the consecutive valleys and peaks + +![Peak Valley Approach](https://leetcode.com/media/original_images/122_maxprofit_1.PNG) + +_Image source: [LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/solution/)_ + +So, if we will track the growing price and will sell the stocks immediately _before_ the price goes down we'll get the maximum profit (remember, we bought the stock in the valley at its low price). + +> See the full code example in [peakvalleyBestTimeToBuySellStocks.js](peakvalleyBestTimeToBuySellStocks.js) + +#### Time Complexity + +Since the algorithm requires only one pass through the prices array, the time complexity would equal `O(n)`. + +#### Additional Space Complexity + +Except of the prices array itself the algorithm consumes the constant amount of memory. Thus, additional space complexity is `O(1)`. + +## Accumulator Approach + +There is even simpler approach exists. Let's say we have the prices array which looks like this `[1, 7, 2, 3, 6, 7, 6, 7]`: + +![Simple One Pass](https://leetcode.com/media/original_images/122_maxprofit_2.PNG) + +_Image source: [LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/solution/)_ + +You may notice, that we don't even need to keep tracking of a constantly growing price. Instead, we may simply add the price difference for _all growing segments_ of the chart which eventually sums up to the highest possible profit, + +> See the full code example in [accumulatorBestTimeToBuySellStocks.js](accumulatorBestTimeToBuySellStocks.js) + +#### Time Complexity + +Since the algorithm requires only one pass through the prices array, the time complexity would equal `O(n)`. + +#### Additional Space Complexity + +Except of the prices array itself the algorithm consumes the constant amount of memory. Thus, additional space complexity is `O(1)`. + +## References + +- [Best Time to Buy and Sell Stock on LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/) diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/accumulatorBestTimeToBuySellStocks.test.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/accumulatorBestTimeToBuySellStocks.test.js new file mode 100644 index 0000000000..40c1557770 --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/accumulatorBestTimeToBuySellStocks.test.js @@ -0,0 +1,48 @@ +import accumulatorBestTimeToBuySellStocks from '../accumulatorBestTimeToBuySellStocks'; + +describe('accumulatorBestTimeToBuySellStocks', () => { + it('should find the best time to buy and sell stocks', () => { + let visit; + + expect(accumulatorBestTimeToBuySellStocks([1, 5])).toEqual(4); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(1); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([1, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(2); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([5, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(2); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([1, 5, 10], visit)).toEqual(9); + expect(visit).toHaveBeenCalledTimes(3); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([10, 1, 5, 20, 15, 21], visit)).toEqual(25); + expect(visit).toHaveBeenCalledTimes(6); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([7, 1, 5, 3, 6, 4], visit)).toEqual(7); + expect(visit).toHaveBeenCalledTimes(6); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([1, 2, 3, 4, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(5); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([7, 6, 4, 3, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(5); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], + visit, + )).toEqual(19); + expect(visit).toHaveBeenCalledTimes(20); + }); +}); diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dqBestTimeToBuySellStocks.test.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dqBestTimeToBuySellStocks.test.js new file mode 100644 index 0000000000..f4fe9ad3f5 --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dqBestTimeToBuySellStocks.test.js @@ -0,0 +1,48 @@ +import dqBestTimeToBuySellStocks from '../dqBestTimeToBuySellStocks'; + +describe('dqBestTimeToBuySellStocks', () => { + it('should find the best time to buy and sell stocks', () => { + let visit; + + expect(dqBestTimeToBuySellStocks([1, 5])).toEqual(4); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(3); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([1, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(7); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([5, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(7); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([1, 5, 10], visit)).toEqual(9); + expect(visit).toHaveBeenCalledTimes(15); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([10, 1, 5, 20, 15, 21], visit)).toEqual(25); + expect(visit).toHaveBeenCalledTimes(127); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([7, 1, 5, 3, 6, 4], visit)).toEqual(7); + expect(visit).toHaveBeenCalledTimes(127); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([1, 2, 3, 4, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(63); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([7, 6, 4, 3, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(63); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], + visit, + )).toEqual(19); + expect(visit).toHaveBeenCalledTimes(2097151); + }); +}); diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/peakvalleyBestTimeToBuySellStocks.test.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/peakvalleyBestTimeToBuySellStocks.test.js new file mode 100644 index 0000000000..4eeadf673c --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/peakvalleyBestTimeToBuySellStocks.test.js @@ -0,0 +1,48 @@ +import peakvalleyBestTimeToBuySellStocks from '../peakvalleyBestTimeToBuySellStocks'; + +describe('peakvalleyBestTimeToBuySellStocks', () => { + it('should find the best time to buy and sell stocks', () => { + let visit; + + expect(peakvalleyBestTimeToBuySellStocks([1, 5])).toEqual(4); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(1); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([1, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(2); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([5, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(2); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([1, 5, 10], visit)).toEqual(9); + expect(visit).toHaveBeenCalledTimes(3); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([10, 1, 5, 20, 15, 21], visit)).toEqual(25); + expect(visit).toHaveBeenCalledTimes(6); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([7, 1, 5, 3, 6, 4], visit)).toEqual(7); + expect(visit).toHaveBeenCalledTimes(6); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([1, 2, 3, 4, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(5); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([7, 6, 4, 3, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(5); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], + visit, + )).toEqual(19); + expect(visit).toHaveBeenCalledTimes(20); + }); +}); diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/accumulatorBestTimeToBuySellStocks.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/accumulatorBestTimeToBuySellStocks.js new file mode 100644 index 0000000000..9e244c89e1 --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/accumulatorBestTimeToBuySellStocks.js @@ -0,0 +1,20 @@ +/** + * Finds the maximum profit from selling and buying the stocks. + * ACCUMULATOR APPROACH. + * + * @param {number[]} prices - Array of stock prices, i.e. [7, 6, 4, 3, 1] + * @param {function(): void} visit - Visiting callback to calculate the number of iterations. + * @return {number} - The maximum profit + */ +const accumulatorBestTimeToBuySellStocks = (prices, visit = () => {}) => { + visit(); + let profit = 0; + for (let day = 1; day < prices.length; day += 1) { + visit(); + // Add the increase of the price from yesterday till today (if there was any) to the profit. + profit += Math.max(prices[day] - prices[day - 1], 0); + } + return profit; +}; + +export default accumulatorBestTimeToBuySellStocks; diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dqBestTimeToBuySellStocks.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dqBestTimeToBuySellStocks.js new file mode 100644 index 0000000000..188ad9fe1e --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dqBestTimeToBuySellStocks.js @@ -0,0 +1,42 @@ +/** + * Finds the maximum profit from selling and buying the stocks. + * DIVIDE & CONQUER APPROACH. + * + * @param {number[]} prices - Array of stock prices, i.e. [7, 6, 4, 3, 1] + * @param {function(): void} visit - Visiting callback to calculate the number of iterations. + * @return {number} - The maximum profit + */ +const dqBestTimeToBuySellStocks = (prices, visit = () => {}) => { + /** + * Recursive implementation of the main function. It is hidden from the users. + * + * @param {boolean} buy - Whether we're allow to sell or to buy now + * @param {number} day - Current day of trading (current index of prices array) + * @returns {number} - Max profit from buying/selling + */ + const recursiveBuyerSeller = (buy, day) => { + // Registering the recursive call visit to calculate the complexity. + visit(); + + // Quitting the recursion if this is the last day of trading (prices array ended). + if (day === prices.length) { + return 0; + } + + // If we're buying - we're loosing money (-1), if we're selling we're getting money (+1). + const operationSign = buy ? -1 : +1; + return Math.max( + // Option 1: Don't do anything. + recursiveBuyerSeller(buy, day + 1), + // Option 2: Sell or Buy at the current price. + operationSign * prices[day] + recursiveBuyerSeller(!buy, day + 1), + ); + }; + + const buy = true; + const day = 0; + + return recursiveBuyerSeller(buy, day); +}; + +export default dqBestTimeToBuySellStocks; diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/peakvalleyBestTimeToBuySellStocks.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/peakvalleyBestTimeToBuySellStocks.js new file mode 100644 index 0000000000..44e8bcbd7d --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/peakvalleyBestTimeToBuySellStocks.js @@ -0,0 +1,35 @@ +/** + * Finds the maximum profit from selling and buying the stocks. + * PEAK VALLEY APPROACH. + * + * @param {number[]} prices - Array of stock prices, i.e. [7, 6, 4, 3, 1] + * @param {function(): void} visit - Visiting callback to calculate the number of iterations. + * @return {number} - The maximum profit + */ +const peakvalleyBestTimeToBuySellStocks = (prices, visit = () => {}) => { + visit(); + let profit = 0; + let low = prices[0]; + let high = prices[0]; + + prices.slice(1).forEach((currentPrice) => { + visit(); + if (currentPrice < high) { + // If price went down, we need to sell. + profit += high - low; + low = currentPrice; + high = currentPrice; + } else { + // If price went up, we don't need to do anything but increase a high record. + high = currentPrice; + } + }); + + // In case if price went up during the last day + // and we didn't have chance to sell inside the forEach loop. + profit += high - low; + + return profit; +}; + +export default peakvalleyBestTimeToBuySellStocks; From 79cf9eb4343ae78151eace6d26705c63f955b9d0 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 23 Dec 2020 17:04:02 +0100 Subject: [PATCH 067/264] Add divide and conquer example: best time to buy and sell stocks. --- .../uncategorized/best-time-to-buy-sell-stocks/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md index 982262d94d..9446993e98 100644 --- a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md @@ -37,7 +37,7 @@ _Explanation:_ In this case, no transaction is done, i.e. max `profit = 0`. ## Possible Solutions -### Divide and conquer approach +### Divide and conquer approach `O(2^n)` We may try **all** combinations of buying and selling and find out the most profitable one by applying _divide and conquer approach_. @@ -62,7 +62,7 @@ As you may see, this is very inefficient. For example for just `20` prices the n If we avoid cloning the prices array between recursive function calls and will use the array pointer then additional space complexity will be proportional to the depth of the recursion: `O(n)` -## Peak Valley Approach +## Peak Valley Approach `O(n)` If we plot the prices array (i.e. `[7, 1, 5, 3, 6, 4]`) we may notice that the points of interest are the consecutive valleys and peaks @@ -82,7 +82,7 @@ Since the algorithm requires only one pass through the prices array, the time co Except of the prices array itself the algorithm consumes the constant amount of memory. Thus, additional space complexity is `O(1)`. -## Accumulator Approach +## Accumulator Approach `O(n)` There is even simpler approach exists. Let's say we have the prices array which looks like this `[1, 7, 2, 3, 6, 7, 6, 7]`: From 1c1b244d972f2d32f3bc7162886cd93653e469e4 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 23 Dec 2020 17:19:53 +0100 Subject: [PATCH 068/264] Add dynamic programming version. --- .../dpBestTimeToBuySellStocks.test.js | 48 +++++++++++++++++++ .../dpBestTimeToBuySellStocks.js | 25 ++++++++++ 2 files changed, 73 insertions(+) create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dpBestTimeToBuySellStocks.test.js create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dpBestTimeToBuySellStocks.js diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dpBestTimeToBuySellStocks.test.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dpBestTimeToBuySellStocks.test.js new file mode 100644 index 0000000000..5904ee54f0 --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dpBestTimeToBuySellStocks.test.js @@ -0,0 +1,48 @@ +import dpBestTimeToBuySellStocks from '../dpBestTimeToBuySellStocks'; + +describe('dpBestTimeToBuySellStocks', () => { + it('should find the best time to buy and sell stocks', () => { + let visit; + + expect(dpBestTimeToBuySellStocks([1, 5])).toEqual(4); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(1); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([1, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(2); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([5, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(2); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([1, 5, 10], visit)).toEqual(9); + expect(visit).toHaveBeenCalledTimes(3); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([10, 1, 5, 20, 15, 21], visit)).toEqual(25); + expect(visit).toHaveBeenCalledTimes(6); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([7, 1, 5, 3, 6, 4], visit)).toEqual(7); + expect(visit).toHaveBeenCalledTimes(6); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([1, 2, 3, 4, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(5); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([7, 6, 4, 3, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(5); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], + visit, + )).toEqual(19); + expect(visit).toHaveBeenCalledTimes(20); + }); +}); diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dpBestTimeToBuySellStocks.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dpBestTimeToBuySellStocks.js new file mode 100644 index 0000000000..8bf1645f11 --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dpBestTimeToBuySellStocks.js @@ -0,0 +1,25 @@ +/** + * Finds the maximum profit from selling and buying the stocks. + * DYNAMIC PROGRAMMING APPROACH. + * + * @param {number[]} prices - Array of stock prices, i.e. [7, 6, 4, 3, 1] + * @param {function(): void} visit - Visiting callback to calculate the number of iterations. + * @return {number} - The maximum profit + */ +const dpBestTimeToBuySellStocks = (prices, visit = () => {}) => { + visit(); + let lastBuy = -prices[0]; + let lastSold = 0; + + for (let day = 1; day < prices.length; day += 1) { + visit(); + const curBuy = Math.max(lastBuy, lastSold - prices[day]); + const curSold = Math.max(lastSold, lastBuy + prices[day]); + lastBuy = curBuy; + lastSold = curSold; + } + + return lastSold; +}; + +export default dpBestTimeToBuySellStocks; From 2bbe12b83befddb6e8c1080d535795c9dee4a639 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 23 Dec 2020 17:24:49 +0100 Subject: [PATCH 069/264] Add divide and conquer example: best time to buy and sell stocks (#612) * Add divide and conquer example: best time to buy and sell stocks. * Add divide and conquer example: best time to buy and sell stocks. * Add dynamic programming version. --- README.md | 14 ++- .../best-time-to-buy-sell-stocks/README.md | 107 ++++++++++++++++++ ...accumulatorBestTimeToBuySellStocks.test.js | 48 ++++++++ .../dpBestTimeToBuySellStocks.test.js | 48 ++++++++ .../dqBestTimeToBuySellStocks.test.js | 48 ++++++++ .../peakvalleyBestTimeToBuySellStocks.test.js | 48 ++++++++ .../accumulatorBestTimeToBuySellStocks.js | 20 ++++ .../dpBestTimeToBuySellStocks.js | 25 ++++ .../dqBestTimeToBuySellStocks.js | 42 +++++++ .../peakvalleyBestTimeToBuySellStocks.js | 35 ++++++ 10 files changed, 429 insertions(+), 6 deletions(-) create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/accumulatorBestTimeToBuySellStocks.test.js create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dpBestTimeToBuySellStocks.test.js create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dqBestTimeToBuySellStocks.test.js create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/peakvalleyBestTimeToBuySellStocks.test.js create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/accumulatorBestTimeToBuySellStocks.js create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dpBestTimeToBuySellStocks.js create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dqBestTimeToBuySellStocks.js create mode 100644 src/algorithms/uncategorized/best-time-to-buy-sell-stocks/peakvalleyBestTimeToBuySellStocks.js diff --git a/README.md b/README.md index feb9832d36..f7ae004523 100644 --- a/README.md +++ b/README.md @@ -129,9 +129,9 @@ a set of rules that precisely define a sequence of operations. * `B` [Depth-First Search](src/algorithms/graph/depth-first-search) (DFS) * `B` [Breadth-First Search](src/algorithms/graph/breadth-first-search) (BFS) * `B` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph - * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding shortest paths to all graph vertices from single vertex - * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding shortest paths to all graph vertices from single vertex - * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - find shortest paths between all pairs of vertices + * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding the shortest paths to all graph vertices from single vertex + * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding the shortest paths to all graph vertices from single vertex + * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - find the shortest paths between all pairs of vertices * `A` [Detect Cycle](src/algorithms/graph/detect-cycle) - for both directed and undirected graphs (DFS and Disjoint Set based versions) * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph * `A` [Topological Sorting](src/algorithms/graph/topological-sorting) - DFS method @@ -157,6 +157,7 @@ a set of rules that precisely define a sequence of operations. * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - backtracking, dynamic programming and Pascal's Triangle based examples * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem (dynamic programming and brute force versions) * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top (4 solutions) + * `B` [Best Time To Buy Sell Stocks](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - divide and conquer and one-pass examples * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens) * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour) @@ -176,7 +177,7 @@ algorithm is an abstraction higher than a computer program. * **Greedy** - choose the best option at the current time, without any consideration for the future * `B` [Jump Game](src/algorithms/uncategorized/jump-game) * `A` [Unbound Knapsack Problem](src/algorithms/sets/knapsack-problem) - * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding shortest path to all graph vertices + * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - finding the shortest path to all graph vertices * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - finding Minimum Spanning Tree (MST) for weighted undirected graph * `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - finding Minimum Spanning Tree (MST) for weighted undirected graph * **Divide and Conquer** - divide the problem into smaller parts and then solve those parts @@ -191,6 +192,7 @@ algorithm is an abstraction higher than a computer program. * `B` [Matrices](src/algorithms/math/matrix) - generating and traversing the matrices of different shapes * `B` [Jump Game](src/algorithms/uncategorized/jump-game) * `B` [Fast Powering](src/algorithms/math/fast-powering) + * `B` [Best Time To Buy Sell Stocks](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - divide and conquer and one-pass examples * `A` [Permutations](src/algorithms/sets/permutations) (with and without repetitions) * `A` [Combinations](src/algorithms/sets/combinations) (with and without repetitions) * **Dynamic Programming** - build up a solution using previously found sub-solutions @@ -207,8 +209,8 @@ algorithm is an abstraction higher than a computer program. * `A` [0/1 Knapsack Problem](src/algorithms/sets/knapsack-problem) * `A` [Integer Partition](src/algorithms/math/integer-partition) * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray) - * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding shortest path to all graph vertices - * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - find shortest paths between all pairs of vertices + * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - finding the shortest path to all graph vertices + * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - find the shortest paths between all pairs of vertices * `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching) * **Backtracking** - similarly to brute force, try to generate all possible solutions, but each time you generate next solution you test if it satisfies all conditions, and only then continue generating subsequent solutions. Otherwise, backtrack, and go on a diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md new file mode 100644 index 0000000000..9446993e98 --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/README.md @@ -0,0 +1,107 @@ +# Best Time to Buy and Sell Stock + +## Task Description + +Say you have an array prices for which the `i`-th element is the price of a given stock on day `i`. + +Find the maximum profit. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times). + +> Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again). + +**Example #1** + +``` +Input: [7, 1, 5, 3, 6, 4] +Output: 7 +``` + +_Explanation:_ Buy on day `2` (`price = 1`) and sell on day `3` (`price = 5`), `profit = 5-1 = 4`. Then buy on day `4` (`price = 3`) and sell on day `5` (`price = 6`), `profit = 6-3 = 3`. + +**Example #2** + +``` +Input: [1, 2, 3, 4, 5] +Output: 4 +``` + +_Explanation:_ Buy on day `1` (`price = 1`) and sell on day `5` (`price = 5`), `profit = 5-1 = 4`. Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are engaging multiple transactions at the same time. You must sell before buying again. + +**Example #3** + +``` +Input: [7, 6, 4, 3, 1] +Output: 0 +``` + +_Explanation:_ In this case, no transaction is done, i.e. max `profit = 0`. + +## Possible Solutions + +### Divide and conquer approach `O(2^n)` + +We may try **all** combinations of buying and selling and find out the most profitable one by applying _divide and conquer approach_. + +Let's say we have an array of prices `[7, 6, 4, 3, 1]` and we're on the _1st_ day of trading (at the very beginning of the array). At this point we may say that the overall maximum profit would be the _maximum_ of two following values: + +1. _Option 1: Keep the money_ → profit would equal to the profit from buying/selling the rest of the stocks → `keepProfit = profit([6, 4, 3, 1])`. +2. _Option 2: Buy/sell at current price_ → profit in this case would equal to the profit from buying/selling the rest of the stocks plus (or minus, depending on whether we're selling or buying) the current stock price → `buySellProfit = -7 + profit([6, 4, 3, 1])`. + +The overall profit would be equal to → `overalProfit = Max(keepProfit, buySellProfit)`. + +As you can see the `profit([6, 4, 3, 1])` task is being solved in the same recursive manner. + +> See the full code example in [dqBestTimeToBuySellStocks.js](dqBestTimeToBuySellStocks.js) + +#### Time Complexity + +As you may see, every recursive call will produce _2_ more recursive branches. The depth of the recursion will be `n` (size of prices array) and thus, the time complexity will equal to `O(2^n)`. + +As you may see, this is very inefficient. For example for just `20` prices the number of recursive calls will be somewhere close to `2M`! + +#### Additional Space Complexity + +If we avoid cloning the prices array between recursive function calls and will use the array pointer then additional space complexity will be proportional to the depth of the recursion: `O(n)` + +## Peak Valley Approach `O(n)` + +If we plot the prices array (i.e. `[7, 1, 5, 3, 6, 4]`) we may notice that the points of interest are the consecutive valleys and peaks + +![Peak Valley Approach](https://leetcode.com/media/original_images/122_maxprofit_1.PNG) + +_Image source: [LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/solution/)_ + +So, if we will track the growing price and will sell the stocks immediately _before_ the price goes down we'll get the maximum profit (remember, we bought the stock in the valley at its low price). + +> See the full code example in [peakvalleyBestTimeToBuySellStocks.js](peakvalleyBestTimeToBuySellStocks.js) + +#### Time Complexity + +Since the algorithm requires only one pass through the prices array, the time complexity would equal `O(n)`. + +#### Additional Space Complexity + +Except of the prices array itself the algorithm consumes the constant amount of memory. Thus, additional space complexity is `O(1)`. + +## Accumulator Approach `O(n)` + +There is even simpler approach exists. Let's say we have the prices array which looks like this `[1, 7, 2, 3, 6, 7, 6, 7]`: + +![Simple One Pass](https://leetcode.com/media/original_images/122_maxprofit_2.PNG) + +_Image source: [LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/solution/)_ + +You may notice, that we don't even need to keep tracking of a constantly growing price. Instead, we may simply add the price difference for _all growing segments_ of the chart which eventually sums up to the highest possible profit, + +> See the full code example in [accumulatorBestTimeToBuySellStocks.js](accumulatorBestTimeToBuySellStocks.js) + +#### Time Complexity + +Since the algorithm requires only one pass through the prices array, the time complexity would equal `O(n)`. + +#### Additional Space Complexity + +Except of the prices array itself the algorithm consumes the constant amount of memory. Thus, additional space complexity is `O(1)`. + +## References + +- [Best Time to Buy and Sell Stock on LeetCode](https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii/) diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/accumulatorBestTimeToBuySellStocks.test.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/accumulatorBestTimeToBuySellStocks.test.js new file mode 100644 index 0000000000..40c1557770 --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/accumulatorBestTimeToBuySellStocks.test.js @@ -0,0 +1,48 @@ +import accumulatorBestTimeToBuySellStocks from '../accumulatorBestTimeToBuySellStocks'; + +describe('accumulatorBestTimeToBuySellStocks', () => { + it('should find the best time to buy and sell stocks', () => { + let visit; + + expect(accumulatorBestTimeToBuySellStocks([1, 5])).toEqual(4); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(1); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([1, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(2); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([5, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(2); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([1, 5, 10], visit)).toEqual(9); + expect(visit).toHaveBeenCalledTimes(3); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([10, 1, 5, 20, 15, 21], visit)).toEqual(25); + expect(visit).toHaveBeenCalledTimes(6); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([7, 1, 5, 3, 6, 4], visit)).toEqual(7); + expect(visit).toHaveBeenCalledTimes(6); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([1, 2, 3, 4, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(5); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks([7, 6, 4, 3, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(5); + + visit = jest.fn(); + expect(accumulatorBestTimeToBuySellStocks( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], + visit, + )).toEqual(19); + expect(visit).toHaveBeenCalledTimes(20); + }); +}); diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dpBestTimeToBuySellStocks.test.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dpBestTimeToBuySellStocks.test.js new file mode 100644 index 0000000000..5904ee54f0 --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dpBestTimeToBuySellStocks.test.js @@ -0,0 +1,48 @@ +import dpBestTimeToBuySellStocks from '../dpBestTimeToBuySellStocks'; + +describe('dpBestTimeToBuySellStocks', () => { + it('should find the best time to buy and sell stocks', () => { + let visit; + + expect(dpBestTimeToBuySellStocks([1, 5])).toEqual(4); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(1); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([1, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(2); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([5, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(2); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([1, 5, 10], visit)).toEqual(9); + expect(visit).toHaveBeenCalledTimes(3); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([10, 1, 5, 20, 15, 21], visit)).toEqual(25); + expect(visit).toHaveBeenCalledTimes(6); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([7, 1, 5, 3, 6, 4], visit)).toEqual(7); + expect(visit).toHaveBeenCalledTimes(6); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([1, 2, 3, 4, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(5); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks([7, 6, 4, 3, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(5); + + visit = jest.fn(); + expect(dpBestTimeToBuySellStocks( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], + visit, + )).toEqual(19); + expect(visit).toHaveBeenCalledTimes(20); + }); +}); diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dqBestTimeToBuySellStocks.test.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dqBestTimeToBuySellStocks.test.js new file mode 100644 index 0000000000..f4fe9ad3f5 --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/dqBestTimeToBuySellStocks.test.js @@ -0,0 +1,48 @@ +import dqBestTimeToBuySellStocks from '../dqBestTimeToBuySellStocks'; + +describe('dqBestTimeToBuySellStocks', () => { + it('should find the best time to buy and sell stocks', () => { + let visit; + + expect(dqBestTimeToBuySellStocks([1, 5])).toEqual(4); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(3); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([1, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(7); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([5, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(7); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([1, 5, 10], visit)).toEqual(9); + expect(visit).toHaveBeenCalledTimes(15); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([10, 1, 5, 20, 15, 21], visit)).toEqual(25); + expect(visit).toHaveBeenCalledTimes(127); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([7, 1, 5, 3, 6, 4], visit)).toEqual(7); + expect(visit).toHaveBeenCalledTimes(127); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([1, 2, 3, 4, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(63); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks([7, 6, 4, 3, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(63); + + visit = jest.fn(); + expect(dqBestTimeToBuySellStocks( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], + visit, + )).toEqual(19); + expect(visit).toHaveBeenCalledTimes(2097151); + }); +}); diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/peakvalleyBestTimeToBuySellStocks.test.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/peakvalleyBestTimeToBuySellStocks.test.js new file mode 100644 index 0000000000..4eeadf673c --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/__tests__/peakvalleyBestTimeToBuySellStocks.test.js @@ -0,0 +1,48 @@ +import peakvalleyBestTimeToBuySellStocks from '../peakvalleyBestTimeToBuySellStocks'; + +describe('peakvalleyBestTimeToBuySellStocks', () => { + it('should find the best time to buy and sell stocks', () => { + let visit; + + expect(peakvalleyBestTimeToBuySellStocks([1, 5])).toEqual(4); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(1); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([1, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(2); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([5, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(2); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([1, 5, 10], visit)).toEqual(9); + expect(visit).toHaveBeenCalledTimes(3); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([10, 1, 5, 20, 15, 21], visit)).toEqual(25); + expect(visit).toHaveBeenCalledTimes(6); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([7, 1, 5, 3, 6, 4], visit)).toEqual(7); + expect(visit).toHaveBeenCalledTimes(6); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([1, 2, 3, 4, 5], visit)).toEqual(4); + expect(visit).toHaveBeenCalledTimes(5); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks([7, 6, 4, 3, 1], visit)).toEqual(0); + expect(visit).toHaveBeenCalledTimes(5); + + visit = jest.fn(); + expect(peakvalleyBestTimeToBuySellStocks( + [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20], + visit, + )).toEqual(19); + expect(visit).toHaveBeenCalledTimes(20); + }); +}); diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/accumulatorBestTimeToBuySellStocks.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/accumulatorBestTimeToBuySellStocks.js new file mode 100644 index 0000000000..9e244c89e1 --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/accumulatorBestTimeToBuySellStocks.js @@ -0,0 +1,20 @@ +/** + * Finds the maximum profit from selling and buying the stocks. + * ACCUMULATOR APPROACH. + * + * @param {number[]} prices - Array of stock prices, i.e. [7, 6, 4, 3, 1] + * @param {function(): void} visit - Visiting callback to calculate the number of iterations. + * @return {number} - The maximum profit + */ +const accumulatorBestTimeToBuySellStocks = (prices, visit = () => {}) => { + visit(); + let profit = 0; + for (let day = 1; day < prices.length; day += 1) { + visit(); + // Add the increase of the price from yesterday till today (if there was any) to the profit. + profit += Math.max(prices[day] - prices[day - 1], 0); + } + return profit; +}; + +export default accumulatorBestTimeToBuySellStocks; diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dpBestTimeToBuySellStocks.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dpBestTimeToBuySellStocks.js new file mode 100644 index 0000000000..8bf1645f11 --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dpBestTimeToBuySellStocks.js @@ -0,0 +1,25 @@ +/** + * Finds the maximum profit from selling and buying the stocks. + * DYNAMIC PROGRAMMING APPROACH. + * + * @param {number[]} prices - Array of stock prices, i.e. [7, 6, 4, 3, 1] + * @param {function(): void} visit - Visiting callback to calculate the number of iterations. + * @return {number} - The maximum profit + */ +const dpBestTimeToBuySellStocks = (prices, visit = () => {}) => { + visit(); + let lastBuy = -prices[0]; + let lastSold = 0; + + for (let day = 1; day < prices.length; day += 1) { + visit(); + const curBuy = Math.max(lastBuy, lastSold - prices[day]); + const curSold = Math.max(lastSold, lastBuy + prices[day]); + lastBuy = curBuy; + lastSold = curSold; + } + + return lastSold; +}; + +export default dpBestTimeToBuySellStocks; diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dqBestTimeToBuySellStocks.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dqBestTimeToBuySellStocks.js new file mode 100644 index 0000000000..188ad9fe1e --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/dqBestTimeToBuySellStocks.js @@ -0,0 +1,42 @@ +/** + * Finds the maximum profit from selling and buying the stocks. + * DIVIDE & CONQUER APPROACH. + * + * @param {number[]} prices - Array of stock prices, i.e. [7, 6, 4, 3, 1] + * @param {function(): void} visit - Visiting callback to calculate the number of iterations. + * @return {number} - The maximum profit + */ +const dqBestTimeToBuySellStocks = (prices, visit = () => {}) => { + /** + * Recursive implementation of the main function. It is hidden from the users. + * + * @param {boolean} buy - Whether we're allow to sell or to buy now + * @param {number} day - Current day of trading (current index of prices array) + * @returns {number} - Max profit from buying/selling + */ + const recursiveBuyerSeller = (buy, day) => { + // Registering the recursive call visit to calculate the complexity. + visit(); + + // Quitting the recursion if this is the last day of trading (prices array ended). + if (day === prices.length) { + return 0; + } + + // If we're buying - we're loosing money (-1), if we're selling we're getting money (+1). + const operationSign = buy ? -1 : +1; + return Math.max( + // Option 1: Don't do anything. + recursiveBuyerSeller(buy, day + 1), + // Option 2: Sell or Buy at the current price. + operationSign * prices[day] + recursiveBuyerSeller(!buy, day + 1), + ); + }; + + const buy = true; + const day = 0; + + return recursiveBuyerSeller(buy, day); +}; + +export default dqBestTimeToBuySellStocks; diff --git a/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/peakvalleyBestTimeToBuySellStocks.js b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/peakvalleyBestTimeToBuySellStocks.js new file mode 100644 index 0000000000..44e8bcbd7d --- /dev/null +++ b/src/algorithms/uncategorized/best-time-to-buy-sell-stocks/peakvalleyBestTimeToBuySellStocks.js @@ -0,0 +1,35 @@ +/** + * Finds the maximum profit from selling and buying the stocks. + * PEAK VALLEY APPROACH. + * + * @param {number[]} prices - Array of stock prices, i.e. [7, 6, 4, 3, 1] + * @param {function(): void} visit - Visiting callback to calculate the number of iterations. + * @return {number} - The maximum profit + */ +const peakvalleyBestTimeToBuySellStocks = (prices, visit = () => {}) => { + visit(); + let profit = 0; + let low = prices[0]; + let high = prices[0]; + + prices.slice(1).forEach((currentPrice) => { + visit(); + if (currentPrice < high) { + // If price went down, we need to sell. + profit += high - low; + low = currentPrice; + high = currentPrice; + } else { + // If price went up, we don't need to do anything but increase a high record. + high = currentPrice; + } + }); + + // In case if price went up during the last day + // and we didn't have chance to sell inside the forEach loop. + profit += high - low; + + return profit; +}; + +export default peakvalleyBestTimeToBuySellStocks; From d35cfba32da319dd457ac096a0d04599541d8006 Mon Sep 17 00:00:00 2001 From: Yanina Trekhleb <36455834+YaninaTrekhleb@users.noreply.github.com> Date: Wed, 23 Dec 2020 19:00:36 +0100 Subject: [PATCH 070/264] Add Ukrainian translation of the main README file. (#613) * Add ukrainian translate. * Error correction. * Add a link to UA version to all README.file. --- README.es-ES.md | 3 +- README.fr-FR.md | 3 +- README.it-IT.md | 3 +- README.ja-JP.md | 3 +- README.ko-KR.md | 3 +- README.md | 3 +- README.pl-PL.md | 3 +- README.pt-BR.md | 3 +- README.ru-RU.md | 3 +- README.tr-TR.md | 3 +- README.uk-UA.md | 304 ++++++++++++++++++++++++++++++++++++++++++++++++ README.zh-CN.md | 3 +- README.zh-TW.md | 3 +- 13 files changed, 328 insertions(+), 12 deletions(-) create mode 100644 README.uk-UA.md diff --git a/README.es-ES.md b/README.es-ES.md index ee0e0d6289..927848640c 100644 --- a/README.es-ES.md +++ b/README.es-ES.md @@ -21,7 +21,8 @@ _Léelo en otros idiomas:_ [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), -[_Bahasa Indonesia_](README.id-ID.md) +[_Bahasa Indonesia_](README.id-ID.md), +[_Українська_](README.uk-UA.md) *☝ Nótese que este proyecto está pensado con fines de aprendizaje e investigación, y **no** para ser usado en producción.* diff --git a/README.fr-FR.md b/README.fr-FR.md index 1e21add710..d5f11815ce 100644 --- a/README.fr-FR.md +++ b/README.fr-FR.md @@ -22,7 +22,8 @@ _Lisez ceci dans d'autres langues:_ [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), -[_Bahasa Indonesia_](README.id-ID.md) +[_Bahasa Indonesia_](README.id-ID.md), +[_Українська_](README.uk-UA.md) ## Data Structures diff --git a/README.it-IT.md b/README.it-IT.md index 31a7def923..4db5a4c2b7 100644 --- a/README.it-IT.md +++ b/README.it-IT.md @@ -18,7 +18,8 @@ _Leggilo in altre lingue:_ [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), -[_Bahasa Indonesia_](README.id-ID.md) +[_Bahasa Indonesia_](README.id-ID.md), +[_Українська_](README.uk-UA.md) *☝ Si noti che questo progetto è destinato ad essere utilizzato solo per l'apprendimento e la ricerca e non è destinato ad essere utilizzato per il commercio.* diff --git a/README.ja-JP.md b/README.ja-JP.md index e955c3ae30..627ce10079 100644 --- a/README.ja-JP.md +++ b/README.ja-JP.md @@ -21,7 +21,8 @@ _Read this in other languages:_ [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), -[_Bahasa Indonesia_](README.id-ID.md) +[_Bahasa Indonesia_](README.id-ID.md), +[_Українська_](README.uk-UA.md) ## データ構造 diff --git a/README.ko-KR.md b/README.ko-KR.md index 45c59cbe8e..4e7e39be1d 100644 --- a/README.ko-KR.md +++ b/README.ko-KR.md @@ -20,7 +20,8 @@ _Read this in other languages:_ [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), -[_Bahasa Indonesia_](README.id-ID.md) +[_Bahasa Indonesia_](README.id-ID.md), +[_Українська_](README.uk-UA.md) ## 자료 구조 diff --git a/README.md b/README.md index f7ae004523..fca1760314 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,8 @@ _Read this in other languages:_ [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), -[_Bahasa Indonesia_](README.id-ID.md) +[_Bahasa Indonesia_](README.id-ID.md), +[_Українська_](README.uk-UA.md) *☝ Note that this project is meant to be used for learning and researching purposes only, and it is **not** meant to be used for production.* diff --git a/README.pl-PL.md b/README.pl-PL.md index 0ede13db43..f6cfbbfeb4 100644 --- a/README.pl-PL.md +++ b/README.pl-PL.md @@ -22,7 +22,8 @@ _Read this in other languages:_ [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), -[_Bahasa Indonesia_](README.id-ID.md) +[_Bahasa Indonesia_](README.id-ID.md), +[_Українська_](README.uk-UA.md) ## Struktury Danych diff --git a/README.pt-BR.md b/README.pt-BR.md index 7517bb5086..512d44a670 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -22,7 +22,8 @@ _Leia isto em outros idiomas:_ [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), -[_Bahasa Indonesia_](README.id-ID.md) +[_Bahasa Indonesia_](README.id-ID.md), +[_Українська_](README.uk-UA.md) ## Estrutura de Dados diff --git a/README.ru-RU.md b/README.ru-RU.md index 12c1324d36..f491dff108 100644 --- a/README.ru-RU.md +++ b/README.ru-RU.md @@ -19,7 +19,8 @@ _Читать на других языках:_ [_Português_](README.pt-BR.md), [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), -[_Bahasa Indonesia_](README.id-ID.md) +[_Bahasa Indonesia_](README.id-ID.md), +[_Українська_](README.uk-UA.md) *☝ Замечание: этот репозиторий предназначен для учебно-исследовательских целей (**не** для использования в продакшн-системах).* diff --git a/README.tr-TR.md b/README.tr-TR.md index 2b453000b9..940f79e29d 100644 --- a/README.tr-TR.md +++ b/README.tr-TR.md @@ -20,7 +20,8 @@ _Read this in other languages:_ [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), [_Italiana_](README.it-IT.md), -[_Bahasa Indonesia_](README.id-ID.md) +[_Bahasa Indonesia_](README.id-ID.md), +[_Українська_](README.uk-UA.md) *☝ Not, bu proje araştırma ve öğrenme amacı ile yapılmış olup üretim için **yaplılmamıştır**.* diff --git a/README.uk-UA.md b/README.uk-UA.md new file mode 100644 index 0000000000..cc51025480 --- /dev/null +++ b/README.uk-UA.md @@ -0,0 +1,304 @@ +# Алгоритми JavaScript та структури даних + +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster) +[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) + +Даний репозиторій приклади багатьох популярних алгоритмів та структур даних на основі JavaScript. + +Кожен алгоритм та структура даних має свій окремий README-файл із відповідними поясненнями та посиланнями для подальшого вивчення (включаючи посилання на відео на YouTube). + +_Вивчення матеріалу на інших мовах:_ +[_English_](README.md), +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_한국어_](README.ko-KR.md), +[_日本語_](README.ja-JP.md), +[_Polski_](README.pl-PL.md), +[_Français_](README.fr-FR.md), +[_Español_](README.es-ES.md), +[_Português_](README.pt-BR.md), +[_Русский_](README.ru-RU.md), +[_Türk_](README.tr-TR.md), +[_Italiana_](README.it-IT.md) + +*☝ Зверніть увагу! Даний проект призначений лише для навчальних та дослідницьких цілей, і він **не** призначений для виробництва (продакшн).* + +## Структури даних + +Структура даних (в програмуванні) - це спосіб організації даних в комп'ютерах. Часто разом зі структурою даних пов'язується і специфічний перелік операцій, що можуть бути виконаними над даними, організованими в таку структуру. +Точніше, структура даних - це сукупність даних цінності, взаємозв'язки між ними та функції або операції, до яких можна застосувати дані. + +`B` - Початківець, `A` - Просунутий рівень + +* `B` [Зв'язаний список](src/data-structures/linked-list) +* `B` [Двобічно зв'язаний список](src/data-structures/doubly-linked-list) +* `B` [Черга](src/data-structures/queue) +* `B` [Стек](src/data-structures/stack) +* `B` [Геш-таблиця](src/data-structures/hash-table) +* `B` [Купа, стіс або піраміда](src/data-structures/heap) - max and min heap versions +* `B` [Черга з пріоритетом](src/data-structures/priority-queue) +* `A` [Префіксне дерево](src/data-structures/trie) +* `A` [Дерево](src/data-structures/tree) + * `A` [Двійкове дерево пошуку](src/data-structures/tree/binary-search-tree) + * `A` [АВЛ-дерево](src/data-structures/tree/avl-tree) + * `A` [Червоно-чорне дерево](src/data-structures/tree/red-black-tree) + * `A` [Дерево відрізків](src/data-structures/tree/segment-tree) - with min/max/sum range queries examples + * `A` [Дерево Фенвіка](src/data-structures/tree/fenwick-tree) (Binary Indexed Tree) +* `A` [Граф (абстрактний тип даних)](src/data-structures/graph) (both directed and undirected) +* `A` [Система неперетинних множин](src/data-structures/disjoint-set) +* `A` [Фільтр Блума](src/data-structures/bloom-filter) + + +## Алгоритми + +Алгоритм - це однозначна специфікація способу вирішення класу задач. Це набір правил, які точно визначають послідовність операцій. + +`B` - Початківець, `A` - Просунутий рівень + +### Алгоритми за тематикою + +* **Математика** + * `B` [Бітова маніпуляція](src/algorithms/math/bits) - встановити / отримати / оновити / очистити біти, множення / ділення на два, робити від’ємними тощо + * `B` [Факторіал](src/algorithms/math/factorial) + * `B` [Послідовність Фібоначчі](src/algorithms/math/fibonacci) - класична та закриті версії + * `B` [Основні фактори](src/algorithms/math/prime-factors) - пошук простих множників і підрахунок їх за допомогою теореми Харді-Рамануджана + * `B` [Тест простоти](src/algorithms/math/primality-test) (метод пробного поділу) + * `B` [Алгоритм Евкліда](src/algorithms/math/euclidean-algorithm) - метод обчислення найбільшого спільного дільника (НСД) + * `B` [Найменше спільне кратне](src/algorithms/math/least-common-multiple) (НСК) + * `B` [Решето Ератосфена](src/algorithms/math/sieve-of-eratosthenes) - алгоритм знаходження всіх простих чисел менших деякого цілого числа *n* + * `B` [Піднесення до степеня](src/algorithms/math/is-power-of-two) - перевірити, чи є число ступенем двох (просте та побітове рішення) + * `B` [Трикутник Паскаля](src/algorithms/math/pascal-triangle) + * `B` [Комплексне число](src/algorithms/math/complex-number) - комплексні числа та основні операції з ними + * `B` [Радіани & Градуси](src/algorithms/math/radian) - перетворення радіанів у градуси та навпаки + * `B` [Швидке піднесення до степеня](src/algorithms/math/fast-powering) + * `B` [Схема Горнера](src/algorithms/math/horner-method) - поліноміальна оцінка + * `A` [Розбиття числа](src/algorithms/math/integer-partition) + * `A` [Метод дотичних (метод Ньютона)](src/algorithms/math/square-root) - метод наближеного знаходження кореня дійсного рівняння + * `A` [Алгоритм Лю Хуея](src/algorithms/math/liu-hui) - розрахунок числа π з заданою точністю методом вписаних правильних багатокутників + * `A` [Дискретне перетворення Фур'є](src/algorithms/math/fourier-transform) - розкладання тимчасової функції (сигналу) на частотні складові +* **Множина** + * `B` [Декартів добуток множин](src/algorithms/sets/cartesian-product) - множина усіх можливих впорядкованих пар + * `B` [Тасування Фішера - Єйтса](src/algorithms/sets/fisher-yates) - створення випадкових перестановок кінцевого безлічі + * `A` [Булеан](src/algorithms/sets/power-set) - множина всіх підмножин даної множини (бітові та зворотні рішення) + * `A` [Перестановка](src/algorithms/sets/permutations) (з повтореннями та без) + * `A` [Комбінації](src/algorithms/sets/combinations) (з повтореннями та без) + * `A` [Пошук найдовшої спільної підпослідовності](src/algorithms/sets/longest-common-subsequence) + * `A` [Завдання пошуку найбільшою збільшується підпослідовності](src/algorithms/sets/longest-increasing-subsequence) + * `A` [Найменша загальна супер-послідовність](src/algorithms/sets/shortest-common-supersequence) + * `A` [Задача пакування рюкзака](src/algorithms/sets/knapsack-problem) - приклади "0/1" та "Необмежений" + * `A` [Максимальний підмасив](src/algorithms/sets/maximum-subarray) - метод «Грубої сили» та алгоритм Кадана + * `A` [Комбінована сума](src/algorithms/sets/combination-sum) - знайти всі комбінації, що утворюють конкретну суму +* **Алгоритми роботи з рядками** + * `B` [Відстань Геммінга](src/algorithms/string/hamming-distance) - число позицій, у яких відповідні цифри двох двійкових слів однакової довжини різні + * `A` [Відстань Левенштейна](src/algorithms/string/levenshtein-distance) - міра відмінності двох послідовностей символів (рядків) + * `A` [Алгоритм Кнута — Морріса — Пратта](src/algorithms/string/knuth-morris-pratt) пошук підрядків (узгодження шаблонів) + * `A` [Z-функція](src/algorithms/string/z-algorithm) - пошук підрядків (зіставлення зразків) + * `A` [Алгоритм Рабіна — Карпа](src/algorithms/string/rabin-karp) - алгоритм пошуку рядка + * `A` [Найбільший загальний підрядок](src/algorithms/string/longest-common-substring) + * `A` [Підбирання регулярного виразу](src/algorithms/string/regular-expression-matching) +* **Алгоритми пошуку** + * `B` [Лінійний пошук](src/algorithms/search/linear-search) + * `B` [Пошук блоків](src/algorithms/search/jump-search) - пошук у відсортованому масиві + * `B` [Двійковий пошук](src/algorithms/search/binary-search) - знаходження заданого значення у впорядкованому масиві + * `B` [Інтерполяційний алгоритм пошуку](src/algorithms/search/interpolation-search) - алгоритм для пошуку за заданим ключем в індексованому масиві, який впорядкований за значенням ключів +* **Алгоритми сортування** + * `B` [Сортування бульбашкою](src/algorithms/sorting/bubble-sort) + * `B` [Сортування вибором](src/algorithms/sorting/selection-sort) + * `B` [Сортування включенням](src/algorithms/sorting/insertion-sort) + * `B` [Пірамідальне сортування](src/algorithms/sorting/heap-sort) + * `B` [Сортування злиттям](src/algorithms/sorting/merge-sort) + * `B` [Швидке сортування](src/algorithms/sorting/quick-sort) + * `B` [Сортування Шелла](src/algorithms/sorting/shell-sort) + * `B` [Сортування підрахунком](src/algorithms/sorting/counting-sort) + * `B` [Сортування за розрядами](src/algorithms/sorting/radix-sort) +* **Зв’язані списки** + * `B` [Прямий обхід](src/algorithms/linked-list/traversal) + * `B` [Зворотний обхід](src/algorithms/linked-list/reverse-traversal) +* **Дерева** + * `B` [Пошук у глибину](src/algorithms/tree/depth-first-search) + * `B` [Пошук у ширину](src/algorithms/tree/breadth-first-search) +* **Графи** + * `B` [Пошук у глибину](src/algorithms/graph/depth-first-search) + * `B` [Пошук у ширину](src/algorithms/graph/breadth-first-search) + * `B` [Алгоритм Крускала](src/algorithms/graph/kruskal) - алгоритм побудови мінімального кістякового дерева зваженого неорієнтовного графа + * `A` [Алгоритм Дейкстри](src/algorithms/graph/dijkstra) - знаходження найкоротшого шляху від однієї вершини графа до всіх інших вершин + * `A` [Алгоритм Беллмана — Форда](src/algorithms/graph/bellman-ford) - алгоритм пошуку найкоротшого шляху в зваженому графі + * `A` [Алгоритм Флойда — Воршелла](src/algorithms/graph/floyd-warshall) - знаходження найкоротшого шляху в зваженому графі з додатними або від'ємними вагами ребер (але без від'ємнозначних циклів) + * `A` [Циклічний граф](src/algorithms/graph/detect-cycle) - граф, що складається з єдиного циклу, або, іншими словами, деякого числа вершин, з'єднаних замкнутим ланцюгом. + * `A` [Алгоритм Прима](src/algorithms/graph/prim) - жадібний алгоритм побудови мінімального кістякового дерева зваженого зв'язного неорієнтованого графа + * `A` [Топологічне сортування](src/algorithms/graph/topological-sorting) - впорядковування вершин безконтурного орієнтованого графа згідно з частковим порядком, визначеним ребрами цього графу на множині його вершин + * `A` [Алгоритм Тар'яна](src/algorithms/graph/articulation-points) - алгоритм пошуку компонент сильної зв'язності в орієнтованому графі, що працює за лінійний час + * `A` [Міст (теорія графів)](src/algorithms/graph/bridges) + * `A` [Ейлерів ланцюг](src/algorithms/graph/eulerian-path) - ланцюг у графі, який проходить кожне ребро рівно один раз + * `A` [Гамільтонів граф](src/algorithms/graph/hamiltonian-cycle) - шлях, що містить кожну вершину графа рівно один раз + * `A` [Компонента сильної зв'язності графа](src/algorithms/graph/strongly-connected-components) - Алгоритм Косараджу - алгоритм для знаходження компонент сильної зв’язності орієнтованого графу + * `A` [Задача комівояжера](src/algorithms/graph/travelling-salesman) - знаходження найвигіднішого маршруту, що проходить через вказані міста хоча б по одному разу +* **Криптографія** + * `B` [Хеш-функція](src/algorithms/cryptography/polynomial-hash) - функція, що перетворює вхідні дані будь-якого (як правило великого) розміру в дані фіксованого розміру. + * `B` [Шифр Цезаря (шифр зсуву)](src/algorithms/cryptography/caesar-cipher) - симетричний моноалфавітний алгоритм шифрування, в якому кожна буква відкритого тексту заміняється на ту, що віддалена від неї в алфавіті на сталу кількість позицій + * `B` [Шифр Гілла](src/algorithms/cryptography/hill-cipher) - поліграмний шифр підстановки, заснований на лінійній алгебрі +* **Машинне навчання** + * `B` [Нано-нейрон](https://github.com/trekhleb/nano-neuron) - 7 простих функцій JS, які ілюструють, як машини насправді можуть навчатися (пряме та зворотнє поширення) + * `B` [Метод k-найближчих сусідів](src/algorithms/ml/knn) - простий непараметричний класифікаційний метод, де для класифікації об'єктів у рамках простору властивостей використовуються відстані (зазвичай евклідові), пораховані до усіх інших об'єктів + * `B` [Кластеризація методом к–середніх](src/algorithms/ml/knn) - популярний метод кластеризації, — впорядкування множини об'єктів в порівняно однорідні групи. +* **Без категорії** + * `B` [Ханойська вежа](src/algorithms/uncategorized/hanoi-tower) + * `B` [Поворот квадратної матриці](src/algorithms/uncategorized/square-matrix-rotation) + * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади + * `B` [Проблема унікальних шляхів](src/algorithms/uncategorized/unique-paths) - зворотне відстеження, динамічне програмування та приклади на основі Трикутника Паскаля + * `B` [Дощові тераси](src/algorithms/uncategorized/rain-terraces) - проблема захоплення дощової води (динамічне програмування та версії грубої сили) + * `B` [Завдання про рекурсивні сходи](src/algorithms/uncategorized/recursive-staircase) - підрахунок кількості способів досягти вершини (4 рішення) + * `A` [Задача про вісім ферзів](src/algorithms/uncategorized/n-queens) + * `A` [Задача про хід коня](src/algorithms/uncategorized/knight-tour) + +### Парадигма програмування + +Парадиигма програмува́ння — це система ідей і понять, які визначають стиль написання комп'ютерних програм, а також спосіб мислення програміста. Це спосіб концептуалізації, що визначає організацію обчислень і структурування роботи, яку виконує комп'ютер. + +* **Метод «грубої сили» або повний перебір** - метод рішення криптографічної задачі шляхом перебору всіх можливих варіантів ключа + * `B` [Лінійний пошук](src/algorithms/search/linear-search) + * `B` [Дощові тераси](src/algorithms/uncategorized/rain-terraces) - задача про дощові тераси + * `B` [Завдання про рекурсивні сходи](src/algorithms/uncategorized/recursive-staircase) - підрахунок кількості способів досягти вершини + * `A` [Максимальний підмасив](src/algorithms/sets/maximum-subarray) + * `A` [Задача комівояжера](src/algorithms/graph/travelling-salesman) - знаходження найвигіднішого маршруту, що проходить через вказані міста хоча б по одному разу + * `A` [Дискретне перетворення Фур'є](src/algorithms/math/fourier-transform) - розкладання тимчасової функції (сигналу) на частотні складові +* **"Жадібні" алгоритми** - простий і прямолінійний евристичний алгоритм, який приймає найкраще рішення, виходячи з наявних на кожному етапі даних, не зважаючи на можливі наслідки, сподіваючись урешті-решт отримати оптимальний розв'язок + * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади + * `A` [Задача пакування рюкзака](src/algorithms/sets/knapsack-problem) - приклади "0/1" та "Необмежений" + * `A` [Алгоритм Дейкстри](src/algorithms/graph/dijkstra) - знаходження найкоротшого шляху від однієї вершини графа до всіх інших вершин + * `A` [Алгоритм Прима](src/algorithms/graph/prim) - жадібний алгоритм побудови мінімального кістякового дерева зваженого зв'язного неорієнтованого графа + * `A` [Алгоритм Крускала](src/algorithms/graph/kruskal) - алгоритм побудови мінімального кістякового дерева зваженого неорієнтовного графа +* **Розділяй і володарюй** - важлива парадигма розробки алгоритмів, що полягає в рекурсивному розбитті розв'язуваної задачі на дві або більше підзадачі того ж типу, але меншого розміру, і комбінуванні їх розв'язків для отримання відповіді до вихідного завдання. Розбиття виконуються доти, поки всі підзавдання не стануть елементарними. + * `B` [Двійковий пошук](src/algorithms/search/binary-search) - знаходження заданого значення у впорядкованому масиві + * `B` [Ханойська вежа](src/algorithms/uncategorized/hanoi-tower) + * `B` [Трикутник Паскаля](src/algorithms/math/pascal-triangle) + * `B` [Алгоритм Евкліда](src/algorithms/math/euclidean-algorithm) - метод обчислення найбільшого спільного дільника (НСД) + * `B` [Сортування злиттям](src/algorithms/sorting/merge-sort) + * `B` [Швидке сортування](src/algorithms/sorting/quick-sort) + * `B` [Пошук у глибину](src/algorithms/tree/depth-first-search) + * `B` [Пошук у ширину](src/algorithms/tree/breadth-first-search) + * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади + * `B` [Швидке піднесення до степеня](src/algorithms/math/fast-powering) + * `A` [Перестановка](src/algorithms/sets/permutations) (з повтореннями та без) + * `A` [Комбінації](src/algorithms/sets/combinations) (з повтореннями та без) +* **Динамічне програмування** - розділ математики, який присвячено теорії і методам розв'язання багатокрокових задач оптимального управління + * `B` [Послідовність Фібоначчі](src/algorithms/math/fibonacci) - класична та закриті версії + * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади + * `B` [Проблема унікальних шляхів](src/algorithms/uncategorized/unique-paths) - зворотне відстеження, динамічне програмування та приклади на основі Трикутника Паскаля + * `B` [Дощові тераси](src/algorithms/uncategorized/rain-terraces) - проблема захоплення дощової води (динамічне програмування та версії грубої сили) + * `B` [Завдання про рекурсивні сходи](src/algorithms/uncategorized/recursive-staircase) - підрахунок кількості способів досягти вершини (4 рішення) + * `A` [Відстань Левенштейна](src/algorithms/string/levenshtein-distance) - міра відмінності двох послідовностей символів (рядків) + * `A` [Пошук найдовшої спільної підпослідовності](src/algorithms/sets/longest-common-subsequence) + * `A` [Найбільший загальний підрядок](src/algorithms/string/longest-common-substring) + * `A` [Завдання пошуку найбільшою збільшується підпослідовності](src/algorithms/sets/longest-increasing-subsequence) + * `A` [Найменша загальна супер-послідовність](src/algorithms/sets/shortest-common-supersequence) + * `A` [Задача пакування рюкзака](src/algorithms/sets/knapsack-problem) - приклади "0/1" та "Необмежений" + * `A` [Розбиття числа](src/algorithms/math/integer-partition) + * `A` [Максимальний підмасив](src/algorithms/sets/maximum-subarray) + * `A` [Алгоритм Беллмана — Форда](src/algorithms/graph/bellman-ford) - алгоритм пошуку найкоротшого шляху в зваженому графі + * `A` [Алгоритм Флойда — Воршелла](src/algorithms/graph/floyd-warshall) - знаходження найкоротшого шляху в зваженому графі з додатними або від'ємними вагами ребер (але без від'ємнозначних циклів) + * `A` [Підбирання регулярного виразу](src/algorithms/string/regular-expression-matching) +* **Пошук із зворотом** - подібно до грубої сили, намагайтеся генерувати всі можливі рішення, але кожного разу, коли ви створюєте наступне рішення, тестуєте чи він задовольняє всім умовам, і лише потім продовжуєте генерувати наступні рішення. В іншому випадку поверніться назад і рухайтесь далі іншим шляхом пошуку рішення. + * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади + * `B` [Проблема унікальних шляхів](src/algorithms/uncategorized/unique-paths) - зворотне відстеження, динамічне програмування та приклади на основі Трикутника Паскаля + * `B` [Булеан](src/algorithms/sets/power-set) - множина всіх підмножин даної множини (бітові та зворотні рішення) + * `A` [Гамільтонів граф](src/algorithms/graph/hamiltonian-cycle) - шлях, що містить кожну вершину графа рівно один раз + * `A` [Задача про вісім ферзів](src/algorithms/uncategorized/n-queens) + * `A` [Задача про хід коня](src/algorithms/uncategorized/knight-tour) + * `A` [Комбінована сума](src/algorithms/sets/combination-sum) - знайти всі комбінації, що утворюють конкретну суму +* **Метод гілок і меж** - один з поширених методів дискретної оптимізації. Метод працює на дереві рішень та визначає принципи роботи конкретних алгоритмів пошуку розв'язків, тобто, є мета-алгоритмом. Для різних задач комбінаторної оптимізації створюють спеціалізовані алгоритми гілок та меж. + +## Як користуватися цим репозиторієм + +**Встановіть усі залежності** +``` +npm install +``` + +**Запустіть ESLint** + +Запустіть для перевірки якості коду + +``` +npm run lint +``` + +**Запустіть усі тести** +``` +npm test +``` + +**Запустіть тести за назвою** +``` +npm test -- 'LinkedList' +``` + +**Ігрище** + +Ви можете побавитись зі структурами даних та алгоритмами в файлі `./src/playground/playground.js` та писати тести до них в даному файлі `./src/playground/__test__/playground.test.js`. + +Для перевірки, чи працює ваш код належним чином запустіть команду: + +``` +npm test -- 'playground' +``` + +## Корисна інформація + +### Список літератури + +[▶ Структури даних та алгоритми на YouTube](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) + +### Асимптотична нотація великого О (нотація Ландау) + +*Асимптотична нотація великого О (нотація Ландау)* розповсюджена математична нотація для формального запису асимптотичної поведінки функцій. Широко вживається в теорії складності обчислень, інформатиці та математиці. +![Асимптотична нотація великого О](./assets/big-o-graph.png) + +Джерело: [Асимптотична нотація великого О](http://bigocheatsheet.com/). + +Нижче наведено список деяких найбільш часто використовуваних позначень нотації Ландаута їх порівняння продуктивності з різними розмірами вхідних даних. + +| Нотація Ландау | Обчислення для 10 елементів | Обчислення для 100 елементів | Обчислення для 1000 елементів | +| -------------- | ---------------------------- | ----------------------------- | ------------------------------- | +| **O(1)** | 1 | 1 | 1 | +| **O(log N)** | 3 | 6 | 9 | +| **O(N)** | 10 | 100 | 1000 | +| **O(N log N)** | 30 | 600 | 9000 | +| **O(N^2)** | 100 | 10000 | 1000000 | +| **O(2^N)** | 1024 | 1.26e+29 | 1.07e+301 | +| **O(N!)** | 3628800 | 9.3e+157 | 4.02e+2567 | + +### Складність операцій в структурі даних + +| Структура даних | Доступ | Пошук | Вставка | Видалення | Коментарі | +| ----------------------- | :-------: | :-------: | :-------: | :-------: | :-------- | +| **Масив** | 1 | n | n | n | | +| **Купа** | n | n | 1 | 1 | | +| **Черга** | n | n | 1 | 1 | | +| **Зв’язаний список** | n | n | 1 | n | | +| **Хеш-таблиця** | - | n | n | n | У разі ідеальної хеш-функції - O(1) | +| **Бінарне дерево пошуку** | n | n | n | n | У разі збалансованого дерева витрати становитимуть O (log (n)) | +| **Б-дерево** | log(n) | log(n) | log(n) | log(n) | | +| **Червоно-чорне дерево** | log(n) | log(n) | log(n) | log(n) | | +| **АВЛ-дерево** | log(n) | log(n) | log(n) | log(n) | | +| **Фільтр Блума** | - | 1 | 1 | - | Під час пошуку можливі помилкові спрацьовування | + +### Складність алгоритмів сортування масивів + +| Назва | Найкращий | Середній | Найгірший | Пам'ять | Стабільність | Коментарі | +| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | +| **Сортування бульбашкою** | n | n2 | n2 | 1 | Так | | +| **Сортування включенням** | n | n2 | n2 | 1 | Так | | +| **Сортування вибором** | n2 | n2 | n2 | 1 | Ні | | +| **Пірамідальне сортування** | n log(n) | n log(n) | n log(n) | 1 | Ні | | +| **Сортування злиттям** | n log(n) | n log(n) | n log(n) | n | Так | | +| **Швидке сортування** | n log(n) | n log(n) | n2 | log(n) | Ні | Швидке сортування зазвичай виконується на місці з використанням O (log (n)) додаткової пам'яті | +| **Сортування Шелла** | n log(n) | залежить від послідовності проміжків | n (log(n))2 | 1 | Ні | | +| **Сортування підрахунком** | n + r | n + r | n + r | n + r | Так | Де r - найбільше число в масиві | +| **Сортування за розрядами** | n * k | n * k | n * k | n + k | Так | Де k - довжина найдовшого ключа | + +## Патронати проекту + +> Ви можете підтримати цей проект через ❤️️ [GitHub](https://github.com/sponsors/trekhleb) або ❤️️ [Patreon](https://www.patreon.com/trekhleb). + +[Люди, які підтримують цей проект](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1` diff --git a/README.zh-CN.md b/README.zh-CN.md index c039524447..c1f7027b6e 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -19,7 +19,8 @@ _Read this in other languages:_ [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), -[_Bahasa Indonesia_](README.id-ID.md) +[_Bahasa Indonesia_](README.id-ID.md), +[_Українська_](README.uk-UA.md) *注意:这个项目仅用于学习和研究,**不是**用于生产环境。* diff --git a/README.zh-TW.md b/README.zh-TW.md index 69df9717cb..f341482f56 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -18,7 +18,8 @@ _Read this in other languages:_ [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), -[_Bahasa Indonesia_](README.id-ID.md) +[_Bahasa Indonesia_](README.id-ID.md), +[_Українська_](README.uk-UA.md) ## 資料結構 From 711204f13a825cbe2dac25fdc5493f9991ede5f0 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Mon, 28 Dec 2020 09:16:33 +0100 Subject: [PATCH 071/264] Update CI workflow. --- .github/workflows/CI.yml | 35 +++++++++++++++++++++++++++++++++++ .github/workflows/ci.yml | 37 ------------------------------------- 2 files changed, 35 insertions(+), 37 deletions(-) create mode 100644 .github/workflows/CI.yml delete mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000000..912c719df3 --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,35 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [ 14.x ] + + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Setup Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + + - name: Install dependencies + run: npm i + + - name: Run linting + run: npm run lint + + - name: Run tests + run: npm run coverage + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 1499ea368e..0000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: CI - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - build: - - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [14.x] - - steps: - - name: Checkout repository - uses: actions/checkout@v2 - - - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - - name: Install dependencies - run: npm i - - - name: Run linting - run: npm run lint - - - name: Run tests - run: npm run coverage - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v1 From a0a9c35e3ffd78d14de70a53c305aaf888113a1b Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sat, 2 Jan 2021 13:49:00 +0100 Subject: [PATCH 072/264] Update Bakers. --- BACKERS.md | 17 ++++++++++------- README.md | 2 +- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/BACKERS.md b/BACKERS.md index 71020a9e99..62c397a38c 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -1,27 +1,30 @@ # Project Backers -> You may support this project via ❤️️ [GitHub](https://github.com/sponsors/trekhleb) or ❤️️ [Patreon](https://www.patreon.com/trekhleb). +> You may support this project via ❤️️ [GitHub](https://github.com/sponsors/trekhleb) or ❤️️ [Patreon](https://www.patreon.com/trekhleb). ## `O(2ⁿ)` Backers -⏳ +`null` ## `O(n²)` Backers -⏳ +`null` ## `O(n×log(n))` Backers +`null` + + diff --git a/README.md b/README.md index fca1760314..f44142fcba 100644 --- a/README.md +++ b/README.md @@ -325,4 +325,4 @@ Below is the list of some of the most used Big O notations and their performance > You may support this project via ❤️️ [GitHub](https://github.com/sponsors/trekhleb) or ❤️️ [Patreon](https://www.patreon.com/trekhleb). -[Folks who are backing this project](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1` +[Folks who are backing this project](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0` From 81240342c257a78cfafc0fd0a419af30479be447 Mon Sep 17 00:00:00 2001 From: Abdessamad Bensaad <43497143+B3ns44d@users.noreply.github.com> Date: Sun, 3 Jan 2021 01:23:17 -0800 Subject: [PATCH 073/264] Add an Arabic version of the README file (#622) * add the DS link * Finish translating math * add Arabic version of the README FILE * add Arabic version of the README FILE * add the arabic readme file link to main readme file * add the arabic readme file link to main readme file * add the arabic readme file link to main readme file Co-authored-by: Oleksii Trekhleb --- README.ar.AR.md | 324 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 3 +- 2 files changed, 326 insertions(+), 1 deletion(-) create mode 100644 README.ar.AR.md diff --git a/README.ar.AR.md b/README.ar.AR.md new file mode 100644 index 0000000000..d11b3d98de --- /dev/null +++ b/README.ar.AR.md @@ -0,0 +1,324 @@ +# جافا سكريبت خوارزميات وهياكل البيانات + +[![Build Status](https://travis-ci.org/trekhleb/javascript-algorithms.svg?branch=master)](https://travis-ci.org/trekhleb/javascript-algorithms) +[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) + +تحتوي هذا مقالة على أمثلة عديدة تستند إلى الخوارزميات الشائعة وهياكل البيانات في الجافا سكريبت. + +كل خوارزمية وهياكل البيانات لها برنامج README منفصل خاص بها +مع التفسيرات والروابط ذات الصلة لمزيد من القراءة (بما في ذلك تلك +إلى مقاطع فيديو YouTube). + + +_اقرأ هذا في لغات أخرى:_ +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_한국어_](README.ko-KR.md), +[_日本語_](README.ja-JP.md), +[_Polski_](README.pl-PL.md), +[_Français_](README.fr-FR.md), +[_Español_](README.es-ES.md), +[_Português_](README.pt-BR.md), +[_Русский_](README.ru-RU.md), +[_Türk_](README.tr-TR.md), +[_Italiana_](README.it-IT.md) + + ☝ ملاحضة هذا المشروع مخصص للاستخدام لأغراض التعلم والبحث +فقط ، و ** ليست ** معدة للاستخدام في **الإنتاج** + +## هياكل البيانات + +هياكل البيانات هي طريقة خاصة لتنظيم البيانات وتخزينها في جهاز الكمبيوتر بحيث +يمكن الوصول إليها وتعديلها بكفاءة. بتعبير أدق ، هيكل البيانات هو مجموعة من البيانات +القيم والعلاقات فيما بينها والوظائف أو العمليات التي يمكن تطبيقها عليها +البيانات. + + +`B` - مبتدئ, `A` - المتقدمة + +* `B` [قائمة مرتبطة](src/data-structures/linked-list) +* `B` [قائمة مرتبطة بشكل مضاعف](src/data-structures/doubly-linked-list) +* `B` [طابور, Queue](src/data-structures/queue) +* `B` [كومة](src/data-structures/stack) +* `B` [جدول التجزئة](src/data-structures/hash-table) +* `B` [كومة](src/data-structures/heap) -الحد الأقصى والحد الأدنى من إصدارات الكومة +* `B` [طابور الأولوية](src/data-structures/priority-queue) +* `A` [تري](src/data-structures/trie) +* `A` [شجرة](src/data-structures/tree) + * `A` [شجرة البحث الثنائية](src/data-structures/tree/binary-search-tree) + * `A` [شجرة AVL](src/data-structures/tree/avl-tree) + * `A` [شجرة الأحمر والأسود](src/data-structures/tree/red-black-tree) + * `A` [شجرة القطعة](src/data-structures/tree/segment-tree) - مع أمثلة على استفسارات النطاق الأدنى / الأقصى / المجموع + * `A` [شجرة فينويك](src/data-structures/tree/fenwick-tree) (شجرة ثنائية مفهرسة) +* `A` [Graph](src/data-structures/graph) (كلاهما موجه وغير موجه) +* `A` [مجموعة منفصلة](src/data-structures/disjoint-set) +* `A` [مرشح بلوم](src/data-structures/bloom-filter) + + +## الخوارزميات + +الخوارزمية هي تحديد لا لبس فيه لكيفية حل فئة من المشاكل. أنه +مجموعة من القواعد التي تحدد بدقة تسلسل العمليات. + +`B` - مبتدئ ، `A` - متقدم + + +### الخوارزميات حسب الموضوع + +* **رياضيات** + * `B` [معالجة البت](src/algorithms/math/bits) + * `B` [عاملي](src/algorithms/math/factorial) + * `B` [رقم فيبوناتشي](src/algorithms/math/fibonacci) - الإصدارات الكلاسيكية والمغلقة + * `B` [اختبار البدائية](src/algorithms/math/primality-test) (طريقة تقسيم المحاكمة) + * `B` [الخوارزمية الإقليدية](src/algorithms/math/euclidean-algorithm) - احسب القاسم المشترك الأكبر (GCD) + * `B` [أقل مضاعف مشترك](src/algorithms/math/least-common-multiple) (LCM) + * `B` [منخل إراتوستينس](src/algorithms/math/sieve-of-eratosthenes) - إيجاد جميع الأعداد الأولية حتى أي حد معين + * `B` [هي قوة اثنين](src/algorithms/math/is-power-of-two) - تحقق مما إذا كان الرقم هو قوة اثنين (الخوارزميات الساذجة والبتية) + * `B` [مثلث باسكال](src/algorithms/math/pascal-triangle) + * `B` [عدد مركب](src/algorithms/math/complex-number) - الأعداد المركبة والعمليات الأساسية معهم + * `B` [راديان ودرجة](src/algorithms/math/radian) - راديان لدرجة التحويل والعكس + * `B` [تشغيل سريع](src/algorithms/math/fast-powering) + * `B` [طريقة هورنر](src/algorithms/math/horner-method) - تقييم متعدد الحدود + * `A` [قسم صحيح](src/algorithms/math/integer-partition) + * `A` [الجذر التربيعي](src/algorithms/math/square-root) - طريقة نيوتن + * `A` [خوارزمية ليو هوي π](src/algorithms/math/liu-hui) - π حسابات تقريبية على أساس N-gons + * `A` [تحويل فورييه المنفصل](src/algorithms/math/fourier-transform) - حلل وظيفة الوقت (إشارة) في الترددات التي يتكون منها +* **مجموعات** + * `B` [المنتج الديكارتي](src/algorithms/sets/cartesian-product) - منتج من مجموعات متعددة + * `B` [فيشر ييتس شافل](src/algorithms/sets/fisher-yates) - التقليب العشوائي لتسلسل محدود + * `A` [مجموعة الطاقة](src/algorithms/sets/power-set) - جميع المجموعات الفرعية للمجموعة (حلول البت والتتبع التراجعي) + * `A` [التباديل](src/algorithms/sets/permutations) (مع وبدون التكرار) + * `A` [مجموعات](src/algorithms/sets/combinations) (مع وبدون التكرار) + * `A` [أطول نتيجة مشتركة](src/algorithms/sets/longest-common-subsequence) (LCS) + * `A` [أطول زيادة متتالية](src/algorithms/sets/longest-increasing-subsequence) + * `A` [أقصر تسلسل فائق مشترك](src/algorithms/sets/shortest-common-supersequence) (SCS) + * `A` [مشكلة حقيبة الظهر](src/algorithms/sets/knapsack-problem) - "0/1" و "غير منضم" + * `A` [الحد الأقصى من Subarray](src/algorithms/sets/maximum-subarray) -إصدارات "القوة الغاشمة" و "البرمجة الديناميكية" (كادان) + * `A` [مجموع الجمع](src/algorithms/sets/combination-sum) - ابحث عن جميع التركيبات التي تشكل مبلغًا محددًا +* **سلاسل** + * `B` [مسافة هامنج](src/algorithms/string/hamming-distance) - عدد المواقف التي تختلف فيها الرموز + * `A` [المسافة ليفنشتاين](src/algorithms/string/levenshtein-distance) - الحد الأدنى لمسافة التحرير بين تسلسلين + * `A` [خوارزمية كنوث - موريس - برات](src/algorithms/string/knuth-morris-pratt) (خوارزمية KMP) - بحث السلسلة الفرعية (مطابقة النمط) + * `A` [خوارزمية Z](src/algorithms/string/z-algorithm) - بحث سلسلة فرعية (مطابقة النمط) + * `A` [خوارزمية رابين كارب](src/algorithms/string/rabin-karp) - بحث السلسلة الفرعية + * `A` [أطول سلسلة فرعية مشتركة](src/algorithms/string/longest-common-substring) + * `A` [مطابقة التعبير العادي](src/algorithms/string/regular-expression-matching) +* **عمليات البحث** + * `B` [البحث الخطي](src/algorithms/search/linear-search) + * `B` [بحث سريع](src/algorithms/search/jump-search) (أو حظر البحث) - ابحث في مصفوفة مرتبة + * `B` [بحث ثنائي](src/algorithms/search/binary-search) - البحث في مجموعة مرتبة + * `B` [بحث الاستيفاء](src/algorithms/search/interpolation-search) - البحث في مجموعة مرتبة موزعة بشكل موحد + +* **فرز** + * `B` [Bubble Sort](src/algorithms/sorting/bubble-sort) + * `B` [Selection Sort](src/algorithms/sorting/selection-sort) + * `B` [Insertion Sort](src/algorithms/sorting/insertion-sort) + * `B` [Heap Sort](src/algorithms/sorting/heap-sort) + * `B` [Merge Sort](src/algorithms/sorting/merge-sort) + * `B` [Quicksort](src/algorithms/sorting/quick-sort) - عمليات التنفيذ في المكان وغير في المكان + * `B` [Shellsort](src/algorithms/sorting/shell-sort) + * `B` [Counting Sort](src/algorithms/sorting/counting-sort) + * `B` [Radix Sort](src/algorithms/sorting/radix-sort) +* **القوائم المرتبطة** + * `B` [Straight Traversal](src/algorithms/linked-list/traversal) + * `B` [Reverse Traversal](src/algorithms/linked-list/reverse-traversal) +* **الأشجار** + * `B` [Depth-First Search](src/algorithms/tree/depth-first-search) (DFS) + * `B` [Breadth-First Search](src/algorithms/tree/breadth-first-search) (BFS) +* **الرسوم البيانية** + * `B` [Depth-First Search](src/algorithms/graph/depth-first-search) (DFS) + * `B` [Breadth-First Search](src/algorithms/graph/breadth-first-search) (BFS) + * `B` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - إيجاد الحد الأدنى من شجرة الامتداد (MST) للرسم البياني الموزون غير الموجه + * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) -إيجاد أقصر المسارات لجميع رؤوس الرسم البياني من رأس واحد + * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - إيجاد أقصر المسارات لجميع رؤوس الرسم البياني من رأس واحد + * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - إيجاد أقصر المسارات بين جميع أزواج الرؤوس + * `A` [Detect Cycle](src/algorithms/graph/detect-cycle) - لكل من الرسوم البيانية الموجهة وغير الموجهة (الإصدارات القائمة على DFS و Disjoint Set) + * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - إيجاد الحد الأدنى من شجرة الامتداد (MST) للرسم البياني الموزون غير الموجه + * `A` [Topological Sorting](src/algorithms/graph/topological-sorting) - طريقة البحث العمق الأول (DFS) + * `A` [Articulation Points](src/algorithms/graph/articulation-points) - خوارزمية تارجان (تعتمد على DFS) + * `A` [Bridges](src/algorithms/graph/bridges) - خوارزمية تعتمد على DFS + * `A` [Eulerian Path and Eulerian Circuit](src/algorithms/graph/eulerian-path) - خوارزمية فلوري - قم بزيارة كل حافة مرة واحدة بالضبط + * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - قم بزيارة كل قمة مرة واحدة بالضبط + * `A` [Strongly Connected Components](src/algorithms/graph/strongly-connected-components) - خوارزمية Kosaraju + * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - أقصر طريق ممكن يزور كل مدينة ويعود إلى المدينة الأصلية +* **التشفير + * `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - المتداول دالة التجزئة على أساس متعدد الحدود + * `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - استبدال بسيط للشفرات +* **التعلم الالي** + * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 وظائف JS بسيطة توضح كيف يمكن للآلات أن تتعلم بالفعل (الانتشار إلى الأمام / الخلف) +* **غير مصنف** + * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower) + * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - خوارزمية في المكان + * `B` [Jump Game](src/algorithms/uncategorized/jump-game) - التراجع ، البرمجة الديناميكية (من أعلى إلى أسفل + من أسفل إلى أعلى) والأمثلة الجشعة + * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) - التراجع والبرمجة الديناميكية والأمثلة القائمة على مثلث باسكال + * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - محاصرة مشكلة مياه الأمطار (البرمجة الديناميكية وإصدارات القوة الغاشمة) + * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - احسب عدد الطرق للوصول إلى القمة (4 حلول) + * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens) + * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour) + +### الخوارزميات حسب النموذج + +النموذج الحسابي هو طريقة أو نهج عام يكمن وراء تصميم الفصل +من الخوارزميات. إنه تجريد أعلى من مفهوم الخوارزمية ، تمامًا مثل +الخوارزمية هي تجريد أعلى من برنامج الكمبيوتر. + +* **القوة الغاشمة** - انظر في جميع الاحتمالات وحدد الحل الأفضل + * `B` [Linear Search](src/algorithms/search/linear-search) + * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - محاصرة مشكلة مياه الأمطار + * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - احسب عدد الطرق للوصول إلى القمة + * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray) + * `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - أقصر طريق ممكن يزور كل مدينة ويعود إلى المدينة الأصلية + * `A` [Discrete Fourier Transform](src/algorithms/math/fourier-transform) - حلل وظيفة الوقت (إشارة) في الترددات التي يتكون منها +* **جشع** - اختر الخيار الأفضل في الوقت الحالي ، دون أي اعتبار للمستقبل + * `B` [Jump Game](src/algorithms/uncategorized/jump-game) + * `A` [Unbound Knapsack Problem](src/algorithms/sets/knapsack-problem) + * `A` [Dijkstra Algorithm](src/algorithms/graph/dijkstra) - إيجاد أقصر مسار لجميع رؤوس الرسم البياني + * `A` [Prim’s Algorithm](src/algorithms/graph/prim) - إيجاد الحد الأدنى من شجرة الامتداد (MST) للرسم البياني الموزون غير الموجه + * `A` [Kruskal’s Algorithm](src/algorithms/graph/kruskal) - إيجاد الحد الأدنى من شجرة الامتداد (MST) للرسم البياني الموزون غير الموجه +* **فرق تسد** - قسّم المشكلة إلى أجزاء أصغر ثم حل تلك الأجزاء + * `B` [Binary Search](src/algorithms/search/binary-search) + * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower) + * `B` [Pascal's Triangle](src/algorithms/math/pascal-triangle) + * `B` [Euclidean Algorithm](src/algorithms/math/euclidean-algorithm) - حساب القاسم المشترك الأكبر (GCD) + * `B` [Merge Sort](src/algorithms/sorting/merge-sort) + * `B` [Quicksort](src/algorithms/sorting/quick-sort) + * `B` [Tree Depth-First Search](src/algorithms/tree/depth-first-search) (DFS) + * `B` [Graph Depth-First Search](src/algorithms/graph/depth-first-search) (DFS) + * `B` [Jump Game](src/algorithms/uncategorized/jump-game) + * `B` [Fast Powering](src/algorithms/math/fast-powering) + * `A` [Permutations](src/algorithms/sets/permutations) (مع التكرار وبدونه) + * `A` [Combinations](src/algorithms/sets/combinations) (مع التكرار وبدونه) +* **البرمجة الديناميكية** - بناء حل باستخدام الحلول الفرعية التي تم العثور عليها مسبقًا + * `B` [Fibonacci Number](src/algorithms/math/fibonacci) + * `B` [Jump Game](src/algorithms/uncategorized/jump-game) + * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) + * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - محاصرة مشكلة مياه الأمطار + * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - احسب عدد الطرق للوصول إلى القمة + * `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - الحد الأدنى لمسافة التحرير بين تسلسلين + * `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS) + * `A` [Longest Common Substring](src/algorithms/string/longest-common-substring) + * `A` [Longest Increasing Subsequence](src/algorithms/sets/longest-increasing-subsequence) + * `A` [Shortest Common Supersequence](src/algorithms/sets/shortest-common-supersequence) + * `A` [0/1 Knapsack Problem](src/algorithms/sets/knapsack-problem) + * `A` [Integer Partition](src/algorithms/math/integer-partition) + * `A` [Maximum Subarray](src/algorithms/sets/maximum-subarray) + * `A` [Bellman-Ford Algorithm](src/algorithms/graph/bellman-ford) - إيجاد أقصر مسار لجميع رؤوس الرسم البياني + * `A` [Floyd-Warshall Algorithm](src/algorithms/graph/floyd-warshall) - إيجاد أقصر المسارات بين جميع أزواج الرؤوس + * `A` [Regular Expression Matching](src/algorithms/string/regular-expression-matching) +* **التراجع** - على غرار القوة الغاشمة ، حاول إنشاء جميع الحلول الممكنة ، ولكن في كل مرة تقوم فيها بإنشاء الحل التالي الذي تختبره +إذا استوفت جميع الشروط ، وعندها فقط استمر في إنشاء الحلول اللاحقة. خلاف ذلك ، تراجع ، واذهب إلى +طريق مختلف لإيجاد حل. عادةً ما يتم استخدام اجتياز DFS لمساحة الدولة. + * `B` [Jump Game](src/algorithms/uncategorized/jump-game) + * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) + * `B` [Power Set](src/algorithms/sets/power-set) - جميع المجموعات الفرعية للمجموعة + * `A` [Hamiltonian Cycle](src/algorithms/graph/hamiltonian-cycle) - قم بزيارة كل قمة مرة واحدة بالضبط + * `A` [N-Queens Problem](src/algorithms/uncategorized/n-queens) + * `A` [Knight's Tour](src/algorithms/uncategorized/knight-tour) + * `A` [Combination Sum](src/algorithms/sets/combination-sum) - ابحث عن جميع التركيبات التي تشكل مبلغًا محددًا + + +* ** Branch & Bound ** - تذكر الحل الأقل تكلفة الموجود في كل مرحلة من مراحل التراجع +البحث ، واستخدام تكلفة الحل الأقل تكلفة الموجود حتى الآن بحد أدنى لتكلفة +الحل الأقل تكلفة للمشكلة ، من أجل تجاهل الحلول الجزئية بتكاليف أكبر من +تم العثور على حل بأقل تكلفة حتى الآن. اجتياز BFS عادةً بالاشتراك مع اجتياز DFS لمساحة الحالة +يتم استخدام الشجرة. + +## كيفية استخدام هذا المستودع + +**تثبيت كل التبعيات** +``` +npm install +``` + +**قم بتشغيل ESLint** + +قد ترغب في تشغيله للتحقق من جودة الكود. + +``` +npm run lint +``` + +**قم بإجراء جميع الاختبارات** +``` +npm test +``` + +**قم بإجراء الاختبارات بالاسم** +``` +npm test -- 'LinkedList' +``` + +**ملعب** + +يمكنك اللعب بهياكل البيانات والخوارزميات في ملف `. /src/playground/playground.js` والكتابة +اختبارات لها في `./src/playground/__test__/playground.test.js`. + +ثم قم ببساطة بتشغيل الأمر التالي لاختبار ما إذا كان كود الملعب الخاص بك يعمل كما هو متوقع: + +``` +npm test -- 'playground' +``` + +## معلومات مفيدة + +### المراجع + +[▶ هياكل البيانات والخوارزميات على موقع يوتيوب](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) + +[▶ دورة كاملة في هياكل البيانات باللغة العربية](https://youtu.be/owCqVRbZlbg) + +### Big O Notation + +* يتم استخدام **Big O notation** لتصنيف الخوارزميات وفقًا لكيفية نمو متطلبات وقت التشغيل أو المساحة مع نمو حجم الإدخال. +قد تجد في الرسم البياني أدناه الأوامر الأكثر شيوعًا لنمو الخوارزميات المحددة في تBig O notation. + +![Big O graphs](./assets/big-o-graph.png) + +مصدر: [Big O Cheat Sheet](http://bigocheatsheet.com/). + +فيما يلي قائمة ببعض رموز Big O notation الأكثر استخدامًا ومقارنات أدائها مقابل أحجام مختلفة من بيانات الإدخال. + +| Big O Notation | Computations for 10 elements | Computations for 100 elements | Computations for 1000 elements | +| -------------- | ---------------------------- | ----------------------------- | ------------------------------- | +| **O(1)** | 1 | 1 | 1 | +| **O(log N)** | 3 | 6 | 9 | +| **O(N)** | 10 | 100 | 1000 | +| **O(N log N)** | 30 | 600 | 9000 | +| **O(N^2)** | 100 | 10000 | 1000000 | +| **O(2^N)** | 1024 | 1.26e+29 | 1.07e+301 | +| **O(N!)** | 3628800 | 9.3e+157 | 4.02e+2567 | + +### تعقيد عمليات بنية البيانات + +| Data Structure | Access | Search | Insertion | Deletion | Comments | +| ----------------------- | :-------: | :-------: | :-------: | :-------: | :-------- | +| **Array** | 1 | n | n | n | | +| **Stack** | n | n | 1 | 1 | | +| **Queue** | n | n | 1 | 1 | | +| **Linked List** | n | n | 1 | n | | +| **Hash Table** | - | n | n | n |في حالة وجود تكاليف دالة تجزئة مثالية ستكون O (1)| +| **Binary Search Tree** | n | n | n | n | في حالة توازن تكاليف الشجرة ستكون O (log (n))| +| **B-Tree** | log(n) | log(n) | log(n) | log(n) | | +| **Red-Black Tree** | log(n) | log(n) | log(n) | log(n) | | +| **AVL Tree** | log(n) | log(n) | log(n) | log(n) | | +| **Bloom Filter** | - | 1 | 1 | - |الإيجابيات الكاذبة ممكنة أثناء البحث| + +### تعقيد خوارزميات فرز الصفيف + +| Name | Best | Average | Worst | Memory | Stable | Comments | +| --------------------- | :-------------: | :-----------------: | :-----------------: | :-------: | :-------: | :-------- | +| **Bubble sort** | n | n2 | n2 | 1 | نعم | | +| **Insertion sort** | n | n2 | n2 | 1 | نعم | | +| **Selection sort** | n2 | n2 | n2 | 1 | لا | | +| **Heap sort** | n log(n) | n log(n) | n log(n) | 1 | لا | | +| **Merge sort** | n log(n) | n log(n) | n log(n) | n | نعم | | +| **Quick sort** | n log(n) | n log(n) | n2 | log(n) | No | عادةً ما يتم إجراء الفرز السريع في مكانه مع مساحة مكدس O (log (n))| +| **Shell sort** | n log(n) | depends on gap sequence | n (log(n))2 | 1 | لا | | +| **Counting sort** | n + r | n + r | n + r | n + r | Yes |r - أكبر رقم في المجموعة| +| **Radix sort** | n * k | n * k | n * k | n + k | Yes | ك - طول أطول مفتاح | + +## مؤيدو المشروع + +> يمكنك دعم هذا المشروع عبر ❤️️ [GitHub] (https://github.com/sponsors/trekhleb) أو ❤️️ [Patreon] (https://www.patreon.com/trekhleb). + +[الناس الذين يدعمون هذا المشروع](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1` diff --git a/README.md b/README.md index f44142fcba..fd5ae7f342 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,8 @@ _Read this in other languages:_ [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), -[_Українська_](README.uk-UA.md) +[_Українська_](README.uk-UA.md), +[_Arabic_](README.ar.AR.md) *☝ Note that this project is meant to be used for learning and researching purposes only, and it is **not** meant to be used for production.* From cf61af59c532ad180fd9b65a21a11e88413e6ebc Mon Sep 17 00:00:00 2001 From: Austin Theriot Date: Sun, 3 Jan 2021 03:26:14 -0600 Subject: [PATCH 074/264] optimized for loop & corrected comments (#617) The existing insertion sort implementation began by iterating from 0 until the end of the array, but it is only necessary to iterate from 1 until the end of the array, since at the 0th index, there is nothing to compare to the left of the element. In order to complete this change, I also had to update the tests to reflect the fact that the algorithm visits each index 1 less time. Finally, I corrected the grammar/wording of the comments. Co-authored-by: Oleksii Trekhleb --- src/algorithms/sorting/insertion-sort/InsertionSort.js | 6 +++--- .../sorting/insertion-sort/__test__/InsertionSort.test.js | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/algorithms/sorting/insertion-sort/InsertionSort.js b/src/algorithms/sorting/insertion-sort/InsertionSort.js index aa44754243..7a80161379 100644 --- a/src/algorithms/sorting/insertion-sort/InsertionSort.js +++ b/src/algorithms/sorting/insertion-sort/InsertionSort.js @@ -5,14 +5,14 @@ export default class InsertionSort extends Sort { const array = [...originalArray]; // Go through all array elements... - for (let i = 0; i < array.length; i += 1) { + for (let i = 1; i < array.length; i += 1) { let currentIndex = i; // Call visiting callback. this.callbacks.visitingCallback(array[i]); - // Go and check if previous elements and greater then current one. - // If this is the case then swap that elements. + // Check if previous element is greater than current element. + // If so, swap the two elements. while ( array[currentIndex - 1] !== undefined && this.comparator.lessThan(array[currentIndex], array[currentIndex - 1]) diff --git a/src/algorithms/sorting/insertion-sort/__test__/InsertionSort.test.js b/src/algorithms/sorting/insertion-sort/__test__/InsertionSort.test.js index 588472e222..8453b7db16 100644 --- a/src/algorithms/sorting/insertion-sort/__test__/InsertionSort.test.js +++ b/src/algorithms/sorting/insertion-sort/__test__/InsertionSort.test.js @@ -8,10 +8,10 @@ import { } from '../../SortTester'; // Complexity constants. -const SORTED_ARRAY_VISITING_COUNT = 20; -const NOT_SORTED_ARRAY_VISITING_COUNT = 101; -const REVERSE_SORTED_ARRAY_VISITING_COUNT = 210; -const EQUAL_ARRAY_VISITING_COUNT = 20; +const SORTED_ARRAY_VISITING_COUNT = 19; +const NOT_SORTED_ARRAY_VISITING_COUNT = 100; +const REVERSE_SORTED_ARRAY_VISITING_COUNT = 209; +const EQUAL_ARRAY_VISITING_COUNT = 19; describe('InsertionSort', () => { it('should sort array', () => { From 4eb66047ed9d4e67965faf4a5d5ec38c7d556523 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sun, 3 Jan 2021 10:34:41 +0100 Subject: [PATCH 075/264] Add Arabic translation. --- README.ar.AR.md => README.ar-AR.md | 6 ++---- README.es-ES.md | 3 ++- README.fr-FR.md | 3 ++- README.id-ID.md | 4 +++- README.it-IT.md | 3 ++- README.ja-JP.md | 3 ++- README.ko-KR.md | 3 ++- README.md | 2 +- README.pl-PL.md | 3 ++- README.pt-BR.md | 3 ++- README.ru-RU.md | 3 ++- README.tr-TR.md | 3 ++- README.uk-UA.md | 14 ++++++++------ README.zh-CN.md | 3 ++- README.zh-TW.md | 3 ++- 15 files changed, 36 insertions(+), 23 deletions(-) rename README.ar.AR.md => README.ar-AR.md (99%) diff --git a/README.ar.AR.md b/README.ar-AR.md similarity index 99% rename from README.ar.AR.md rename to README.ar-AR.md index d11b3d98de..1676dfc40d 100644 --- a/README.ar.AR.md +++ b/README.ar-AR.md @@ -67,7 +67,7 @@ _اقرأ هذا في لغات أخرى:_ * **رياضيات** * `B` [معالجة البت](src/algorithms/math/bits) - * `B` [عاملي](src/algorithms/math/factorial) + * `B` [عاملي](src/algorithms/math/factorial) * `B` [رقم فيبوناتشي](src/algorithms/math/fibonacci) - الإصدارات الكلاسيكية والمغلقة * `B` [اختبار البدائية](src/algorithms/math/primality-test) (طريقة تقسيم المحاكمة) * `B` [الخوارزمية الإقليدية](src/algorithms/math/euclidean-algorithm) - احسب القاسم المشترك الأكبر (GCD) @@ -265,8 +265,6 @@ npm test -- 'playground' [▶ هياكل البيانات والخوارزميات على موقع يوتيوب](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) -[▶ دورة كاملة في هياكل البيانات باللغة العربية](https://youtu.be/owCqVRbZlbg) - ### Big O Notation * يتم استخدام **Big O notation** لتصنيف الخوارزميات وفقًا لكيفية نمو متطلبات وقت التشغيل أو المساحة مع نمو حجم الإدخال. @@ -321,4 +319,4 @@ npm test -- 'playground' > يمكنك دعم هذا المشروع عبر ❤️️ [GitHub] (https://github.com/sponsors/trekhleb) أو ❤️️ [Patreon] (https://www.patreon.com/trekhleb). -[الناس الذين يدعمون هذا المشروع](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1` +[الناس الذين يدعمون هذا المشروع](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0` diff --git a/README.es-ES.md b/README.es-ES.md index 927848640c..fa1fd340c6 100644 --- a/README.es-ES.md +++ b/README.es-ES.md @@ -22,7 +22,8 @@ _Léelo en otros idiomas:_ [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), -[_Українська_](README.uk-UA.md) +[_Українська_](README.uk-UA.md), +[_Arabic_](README.ar-AR.md) *☝ Nótese que este proyecto está pensado con fines de aprendizaje e investigación, y **no** para ser usado en producción.* diff --git a/README.fr-FR.md b/README.fr-FR.md index d5f11815ce..024a3b1904 100644 --- a/README.fr-FR.md +++ b/README.fr-FR.md @@ -23,7 +23,8 @@ _Lisez ceci dans d'autres langues:_ [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), -[_Українська_](README.uk-UA.md) +[_Українська_](README.uk-UA.md), +[_Arabic_](README.ar-AR.md) ## Data Structures diff --git a/README.id-ID.md b/README.id-ID.md index 5a31ff8b35..2a258f973c 100644 --- a/README.id-ID.md +++ b/README.id-ID.md @@ -19,7 +19,9 @@ _Baca ini dalam bahasa yang lain:_ [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), -[_Italiana_](README.it-IT.md) +[_Italiana_](README.it-IT.md), +[_Українська_](README.uk-UA.md), +[_Arabic_](README.ar-AR.md) _☝ Perhatikan bahwa proyek ini hanya dimaksudkan untuk tujuan pembelajaran dan riset, dan **tidak** dimaksudkan untuk digunakan sebagai produksi._ diff --git a/README.it-IT.md b/README.it-IT.md index 4db5a4c2b7..9d8c664f6a 100644 --- a/README.it-IT.md +++ b/README.it-IT.md @@ -19,7 +19,8 @@ _Leggilo in altre lingue:_ [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), [_Bahasa Indonesia_](README.id-ID.md), -[_Українська_](README.uk-UA.md) +[_Українська_](README.uk-UA.md), +[_Arabic_](README.ar-AR.md) *☝ Si noti che questo progetto è destinato ad essere utilizzato solo per l'apprendimento e la ricerca e non è destinato ad essere utilizzato per il commercio.* diff --git a/README.ja-JP.md b/README.ja-JP.md index 627ce10079..af2c887c2c 100644 --- a/README.ja-JP.md +++ b/README.ja-JP.md @@ -22,7 +22,8 @@ _Read this in other languages:_ [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), -[_Українська_](README.uk-UA.md) +[_Українська_](README.uk-UA.md), +[_Arabic_](README.ar-AR.md) ## データ構造 diff --git a/README.ko-KR.md b/README.ko-KR.md index 4e7e39be1d..02f35d0250 100644 --- a/README.ko-KR.md +++ b/README.ko-KR.md @@ -21,7 +21,8 @@ _Read this in other languages:_ [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), -[_Українська_](README.uk-UA.md) +[_Українська_](README.uk-UA.md), +[_Arabic_](README.ar-AR.md) ## 자료 구조 diff --git a/README.md b/README.md index fd5ae7f342..8bb2bf3cdf 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ _Read this in other languages:_ [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), [_Українська_](README.uk-UA.md), -[_Arabic_](README.ar.AR.md) +[_Arabic_](README.ar-AR.md) *☝ Note that this project is meant to be used for learning and researching purposes only, and it is **not** meant to be used for production.* diff --git a/README.pl-PL.md b/README.pl-PL.md index f6cfbbfeb4..08dc09b6aa 100644 --- a/README.pl-PL.md +++ b/README.pl-PL.md @@ -23,7 +23,8 @@ _Read this in other languages:_ [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), -[_Українська_](README.uk-UA.md) +[_Українська_](README.uk-UA.md), +[_Arabic_](README.ar-AR.md) ## Struktury Danych diff --git a/README.pt-BR.md b/README.pt-BR.md index 512d44a670..baffbc3179 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -23,7 +23,8 @@ _Leia isto em outros idiomas:_ [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), -[_Українська_](README.uk-UA.md) +[_Українська_](README.uk-UA.md), +[_Arabic_](README.ar-AR.md) ## Estrutura de Dados diff --git a/README.ru-RU.md b/README.ru-RU.md index f491dff108..32f4b2f526 100644 --- a/README.ru-RU.md +++ b/README.ru-RU.md @@ -20,7 +20,8 @@ _Читать на других языках:_ [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), -[_Українська_](README.uk-UA.md) +[_Українська_](README.uk-UA.md), +[_Arabic_](README.ar-AR.md) *☝ Замечание: этот репозиторий предназначен для учебно-исследовательских целей (**не** для использования в продакшн-системах).* diff --git a/README.tr-TR.md b/README.tr-TR.md index 940f79e29d..f7ed57fc91 100644 --- a/README.tr-TR.md +++ b/README.tr-TR.md @@ -21,7 +21,8 @@ _Read this in other languages:_ [_Русский_](README.ru-RU.md), [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), -[_Українська_](README.uk-UA.md) +[_Українська_](README.uk-UA.md), +[_Arabic_](README.ar-AR.md) *☝ Not, bu proje araştırma ve öğrenme amacı ile yapılmış olup üretim için **yaplılmamıştır**.* diff --git a/README.uk-UA.md b/README.uk-UA.md index cc51025480..4391ed1992 100644 --- a/README.uk-UA.md +++ b/README.uk-UA.md @@ -19,13 +19,15 @@ _Вивчення матеріалу на інших мовах:_ [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), -[_Italiana_](README.it-IT.md) +[_Italiana_](README.it-IT.md), +[_Bahasa Indonesia_](README.id-ID.md), +[_Arabic_](README.ar-AR.md) *☝ Зверніть увагу! Даний проект призначений лише для навчальних та дослідницьких цілей, і він **не** призначений для виробництва (продакшн).* ## Структури даних -Структура даних (в програмуванні) - це спосіб організації даних в комп'ютерах. Часто разом зі структурою даних пов'язується і специфічний перелік операцій, що можуть бути виконаними над даними, організованими в таку структуру. +Структура даних (в програмуванні) - це спосіб організації даних в комп'ютерах. Часто разом зі структурою даних пов'язується і специфічний перелік операцій, що можуть бути виконаними над даними, організованими в таку структуру. Точніше, структура даних - це сукупність даних цінності, взаємозв'язки між ними та функції або операції, до яких можна застосувати дані. `B` - Початківець, `A` - Просунутий рівень @@ -107,7 +109,7 @@ _Вивчення матеріалу на інших мовах:_ * `B` [Сортування включенням](src/algorithms/sorting/insertion-sort) * `B` [Пірамідальне сортування](src/algorithms/sorting/heap-sort) * `B` [Сортування злиттям](src/algorithms/sorting/merge-sort) - * `B` [Швидке сортування](src/algorithms/sorting/quick-sort) + * `B` [Швидке сортування](src/algorithms/sorting/quick-sort) * `B` [Сортування Шелла](src/algorithms/sorting/shell-sort) * `B` [Сортування підрахунком](src/algorithms/sorting/counting-sort) * `B` [Сортування за розрядами](src/algorithms/sorting/radix-sort) @@ -174,7 +176,7 @@ _Вивчення матеріалу на інших мовах:_ * `B` [Трикутник Паскаля](src/algorithms/math/pascal-triangle) * `B` [Алгоритм Евкліда](src/algorithms/math/euclidean-algorithm) - метод обчислення найбільшого спільного дільника (НСД) * `B` [Сортування злиттям](src/algorithms/sorting/merge-sort) - * `B` [Швидке сортування](src/algorithms/sorting/quick-sort) + * `B` [Швидке сортування](src/algorithms/sorting/quick-sort) * `B` [Пошук у глибину](src/algorithms/tree/depth-first-search) * `B` [Пошук у ширину](src/algorithms/tree/breadth-first-search) * `B` [Гра стрибків](src/algorithms/uncategorized/jump-game) - зворотне відстеження, динамічне програмування (зверху вниз + знизу вгору) та жадібні приклади @@ -207,7 +209,7 @@ _Вивчення матеріалу на інших мовах:_ * `A` [Задача про хід коня](src/algorithms/uncategorized/knight-tour) * `A` [Комбінована сума](src/algorithms/sets/combination-sum) - знайти всі комбінації, що утворюють конкретну суму * **Метод гілок і меж** - один з поширених методів дискретної оптимізації. Метод працює на дереві рішень та визначає принципи роботи конкретних алгоритмів пошуку розв'язків, тобто, є мета-алгоритмом. Для різних задач комбінаторної оптимізації створюють спеціалізовані алгоритми гілок та меж. - + ## Як користуватися цим репозиторієм **Встановіть усі залежності** @@ -268,7 +270,7 @@ npm test -- 'playground' | **O(2^N)** | 1024 | 1.26e+29 | 1.07e+301 | | **O(N!)** | 3628800 | 9.3e+157 | 4.02e+2567 | -### Складність операцій в структурі даних +### Складність операцій в структурі даних | Структура даних | Доступ | Пошук | Вставка | Видалення | Коментарі | | ----------------------- | :-------: | :-------: | :-------: | :-------: | :-------- | diff --git a/README.zh-CN.md b/README.zh-CN.md index c1f7027b6e..35a3733fc3 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -20,7 +20,8 @@ _Read this in other languages:_ [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), -[_Українська_](README.uk-UA.md) +[_Українська_](README.uk-UA.md), +[_Arabic_](README.ar-AR.md) *注意:这个项目仅用于学习和研究,**不是**用于生产环境。* diff --git a/README.zh-TW.md b/README.zh-TW.md index f341482f56..4a09b8433e 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -19,7 +19,8 @@ _Read this in other languages:_ [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), -[_Українська_](README.uk-UA.md) +[_Українська_](README.uk-UA.md), +[_Arabic_](README.ar-AR.md) ## 資料結構 From 89a86140098e46eb1636a6122fb906d1c854829d Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sun, 3 Jan 2021 10:37:11 +0100 Subject: [PATCH 076/264] Add Arabic translation. --- README.ar-AR.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.ar-AR.md b/README.ar-AR.md index 1676dfc40d..378334fab0 100644 --- a/README.ar-AR.md +++ b/README.ar-AR.md @@ -317,6 +317,6 @@ npm test -- 'playground' ## مؤيدو المشروع -> يمكنك دعم هذا المشروع عبر ❤️️ [GitHub] (https://github.com/sponsors/trekhleb) أو ❤️️ [Patreon] (https://www.patreon.com/trekhleb). +> يمكنك دعم هذا المشروع عبر ❤️️ [GitHub](https://github.com/sponsors/trekhleb) أو ❤️️ [Patreon](https://www.patreon.com/trekhleb). [الناس الذين يدعمون هذا المشروع](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0` From 848dc351f94557c819dd57f2063bc20800aad7af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=91=A3=E5=87=AF?= <958059970@qq.com> Date: Sun, 3 Jan 2021 17:42:12 +0800 Subject: [PATCH 077/264] Add chinesre translation. (#615) * Add chinesre translation of math/bits README.md * Add chinese translation of math/fibonacii README.md * Add chinesre translation of math/prime-factors README.md * fix * fix Co-authored-by: zackdk Co-authored-by: Oleksii Trekhleb --- src/algorithms/math/bits/README.md | 2 +- src/algorithms/math/bits/README.zh-CN.md | 236 ++++++++++++++++++ src/algorithms/math/fibonacci/README.md | 3 +- src/algorithms/math/fibonacci/README.zh-CN.md | 22 ++ src/algorithms/math/prime-factors/README.md | 3 + .../math/prime-factors/README.zh-CN.md | 38 +++ 6 files changed, 302 insertions(+), 2 deletions(-) create mode 100644 src/algorithms/math/bits/README.zh-CN.md create mode 100644 src/algorithms/math/fibonacci/README.zh-CN.md create mode 100644 src/algorithms/math/prime-factors/README.zh-CN.md diff --git a/src/algorithms/math/bits/README.md b/src/algorithms/math/bits/README.md index 7c0bac48d7..0f870f8995 100644 --- a/src/algorithms/math/bits/README.md +++ b/src/algorithms/math/bits/README.md @@ -1,7 +1,7 @@ # Bit Manipulation _Read this in other languages:_ -[français](README.fr-FR.md). +[français](README.fr-FR.md),[简体中文](README.zh-CN.md). #### Get Bit diff --git a/src/algorithms/math/bits/README.zh-CN.md b/src/algorithms/math/bits/README.zh-CN.md new file mode 100644 index 0000000000..8b71ddc21a --- /dev/null +++ b/src/algorithms/math/bits/README.zh-CN.md @@ -0,0 +1,236 @@ +# 位运算 + +_Read this in other languages:_ +[français](README.fr-FR.md), +[english](README.md) + +#### Get Bit + +该方法向右移动目标位到最右边,即位数组的第0个位置上。然后在该数上与形如 `0001`的二进制形式的数进行`ADD`操作。这会清理掉除了目标位的所有其它位的数据。如果目标位是1,那么结果就是`1`,反之,结果是`0`; + +> 查看[getBit.js](getBit.js)了解更多细节。 + +#### Set Bit + +该方法把`1`向左移动了`bitPosition`位,生成了一个二进制形如`00100`的值。然后我们拿该值与目标数字进行`OR`操作,就能把目标位设置位`1`而不影响其它位。 + +> 查看[setBit.js](setBit.js)了解更多细节。 + +#### Clear Bit + +该方法把`1`向左移动了`bitPosition`位,生成了一个二进制形如`00100`的值。然后反转每一位的数字,得到一个二进制形如`11011`的值。接着与目标值进行`ADD`操作,就能清除掉目标位的值。 + +> 查看[clearBit.js](clearBit.js)了解更多细节。 + +#### Update Bit + +该方法组合了“Clear Bit”和“Set Bit” + +> 查看[updateBit.js](updateBit.js)了解更多细节。 + +#### isEven + +该方法检测传入的number是否是偶数。它的实现基于奇数的最右边的位永远是`1`这个事实。 + +```text +Number: 5 = 0b0101 +isEven: false + +Number: 4 = 0b0100 +isEven: true +``` + +> 查看[isEven.js](isEven.js)了解更多细节。 + +#### isPositive + +该方法检测传入的number是否是正数。它的实现基于正数最左边的位永远是`0`这个事实。然而如果传入的number是0或者-0,它也应该返回false。 + +```text +Number: 1 = 0b0001 +isPositive: true + +Number: -1 = -0b0001 +isPositive: false +``` + +> 查看[isPositive.js](isPositive.js)了解更多细节。 + +#### Multiply By Two + +该方法将原始数字向左移动一位。因此所有位都将乘以2,因此数字本身也将乘以2。 + +``` +Before the shift +Number: 0b0101 = 5 +Powers of two: 0 + 2^2 + 0 + 2^0 + +After the shift +Number: 0b1010 = 10 +Powers of two: 2^3 + 0 + 2^1 + 0 +``` + +> 查看[multiplyByTwo.js](multiplyByTwo.js)了解更多细节。 + +#### Divide By Two + +该方法将原始数字向右移动一位。因此所有位都将除以2,因此数字本身也将除以2,且不会产生余数。 + +``` +Before the shift +Number: 0b0101 = 5 +Powers of two: 0 + 2^2 + 0 + 2^0 + +After the shift +Number: 0b0010 = 2 +Powers of two: 0 + 0 + 2^1 + 0 +``` + +> 查看[divideByTwo.js](divideByTwo.js)了解更多细节。 + +#### Switch Sign + +该方法将正数变成负数,反之亦然。为了做到这一点,它使用了“二进制补码”的方法,即取反所有位然后加1. + +``` +1101 -3 +1110 -2 +1111 -1 +0000 0 +0001 1 +0010 2 +0011 3 +``` + +> 查看[switchSign.js](switchSign.js)了解更多细节。 + +#### Multiply Two Signed Numbers + +该方法使用位运算符计算两个有符号数的乘积。实现基于以下事实: + +```text +a * b 可以被改写成如下形式: + 0 a为0,b为0,或者a,b都为0 + 2a * (b/2) b是偶数 + 2a * (b - 1)/2 + a b是奇数,正数 + 2a * (b + 1)/2 - a b是奇数,负数 +``` + +这样转换的优势在于,递归的每一步,递归的操作数的值都减少了一半。因此,运行时的时间复杂度为`O(log(b))`,其中b是在每个递归步骤上减少为一半的操作数。 + + +> 查看[multiply.js](multiply.js)了解更多细节。 + +#### Multiply Two Unsigned Numbers + +该方法使用位运算符计算两个无符号数的乘积。实现基于“每个数字都可以表示为一系列2的幂的和”。 + +逐位乘法的主要思想是,每个数字都可以拆分为两个乘方的和: + +比如: + +```text +19 = 2^4 + 2^1 + 2^0 +``` + +然后`19`乘`x`就等价于: + +```text +x * 19 = x * 2^4 + x * 2^1 + x * 2^0 +``` + +接着我们应该意识到`x*2^4`是等价于`x`向左移动`4`位(`x << 4`)的; + +> 查看[multiplyUnsigned.js](multiplyUnsigned.js)了解更多细节。 + +#### Count Set Bits + +该方法使用位运算符对一个数字里设置为`1`的位进行记数。主要方法是,把数字每次向右移动1位,然后使用`&`操作符取出最右边一位的值,`1`则记数加1,`0`则不计。 + +```text +Number: 5 = 0b0101 +Count of set bits = 2 +``` + +> 查看[countSetBits.js](countSetBits.js)了解更多细节。 + +#### Count Bits to Flip One Number to Another + + +该方法输出把一个数字转换为另一个数字所需要转换的位数。这利用了以下特性:当数字进行`XOR`异或运算时,结果将是不同位数的数量(即异或的结果中所有被设置为1的位的数量)。 + +``` +5 = 0b0101 +1 = 0b0001 +Count of Bits to be Flipped: 1 +``` + +> 查看[bitsDiff.js](bitsDiff.js)了解更多细节。 + +#### Count Bits of a Number + +为了计算数字的有效位数,我们需要把`1`每次向左移动一位,然后检查产生的值是否大于输入的数字。 + +``` +5 = 0b0101 +有效位数: 3 +当我们把1向左移动4位的时候,会大于5. +``` + +> 查看[bitLength.js](bitLength.js)了解更多细节。 + +#### Is Power of Two + +该方法检测数字是否可以表示为2的幂。它使用了以下特性,我们定义`powerNumber`是可以写成2的幂的形式的数(2,4,8,16 etc.)。然后我们会把`powerNumber`和`powerNumber - 1`进行`&`操作,它会返回`0`(如果该数字可以表示为2的幂)。 + +``` +Number: 4 = 0b0100 +Number: 3 = (4 - 1) = 0b0011 +4 & 3 = 0b0100 & 0b0011 = 0b0000 <-- Equal to zero, is power of two. + +Number: 10 = 0b01010 +Number: 9 = (10 - 1) = 0b01001 +10 & 9 = 0b01010 & 0b01001 = 0b01000 <-- Not equal to zero, not a power of two. +``` + +> 查看[isPowerOfTwo.js](isPowerOfTwo.js)了解更多细节。 + +#### Full Adder + +该方法使用位运算符计算两个数的和。 + +它实现了[完整的加法器]()电子电路逻辑,以补码的形式计算两个32位数字的和。它使用布尔逻辑来覆盖了两个位相加的所有情况:从前一位相加的时候,产没产生进位“carry bit”。 + +Legend: + +- `A`: 数字 `A` +- `B`: 数字 `B` +- `ai`: 数字`A`以二进制表示时的位下标 +- `bi`: 数字`B`以二进制表示时的位下标 +- `carryIn`: 本次计算产生的进位 +- `carryOut`: 带入此次计算的进位 +- `bitSum`: `ai`, `bi`, 和 `carryIn` 的和 +- `resultBin`: 当前计算的结果(二进制形式) +- `resultDec`: 当前计算的结果(十进制形式) + +``` +A = 3: 011 +B = 6: 110 +┌──────┬────┬────┬─────────┬──────────┬─────────┬───────────┬───────────┐ +│ bit │ ai │ bi │ carryIn │ carryOut │ bitSum │ resultBin │ resultDec │ +├──────┼────┼────┼─────────┼──────────┼─────────┼───────────┼───────────┤ +│ 0 │ 1 │ 0 │ 0 │ 0 │ 1 │ 1 │ 1 │ +│ 1 │ 1 │ 1 │ 0 │ 1 │ 0 │ 01 │ 1 │ +│ 2 │ 0 │ 1 │ 1 │ 1 │ 0 │ 001 │ 1 │ +│ 3 │ 0 │ 0 │ 1 │ 0 │ 1 │ 1001 │ 9 │ +└──────┴────┴────┴─────────┴──────────┴─────────┴───────────┴───────────┘ +``` + +> 查看[fullAdder.js](fullAdder.js)了解更多细节。 +> 查看[Full Adder on YouTube](https://www.youtube.com/watch?v=wvJc9CZcvBc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8). + +## References + +- [Bit Manipulation on YouTube](https://www.youtube.com/watch?v=NLKQEOgBAnw&t=0s&index=28&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) +- [Negative Numbers in binary on YouTube](https://www.youtube.com/watch?v=4qH4unVtJkE&t=0s&index=30&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) +- [Bit Hacks on stanford.edu](https://graphics.stanford.edu/~seander/bithacks.html) diff --git a/src/algorithms/math/fibonacci/README.md b/src/algorithms/math/fibonacci/README.md index 47f571762b..9a36887f71 100644 --- a/src/algorithms/math/fibonacci/README.md +++ b/src/algorithms/math/fibonacci/README.md @@ -1,7 +1,8 @@ # Fibonacci Number _Read this in other languages:_ -[français](README.fr-FR.md). +[français](README.fr-FR.md), +[简体中文](README.zh-CN.md). In mathematics, the Fibonacci numbers are the numbers in the following integer sequence, called the Fibonacci sequence, and characterized by diff --git a/src/algorithms/math/fibonacci/README.zh-CN.md b/src/algorithms/math/fibonacci/README.zh-CN.md new file mode 100644 index 0000000000..70f74b533c --- /dev/null +++ b/src/algorithms/math/fibonacci/README.zh-CN.md @@ -0,0 +1,22 @@ +# 斐波那契数 + +_Read this in other languages:_ +[français](README.fr-FR.md), +[english](README.md). + +在数学中,斐波那契数是以下整数序列(称为斐波那契数列)中的数字,其特征在于前两个数字之后的每个数字都是前两个数字的和: + +`0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...` + +边长为连续斐波纳契数的正方形平铺 + +![Fibonacci](https://upload.wikimedia.org/wikipedia/commons/d/db/34%2A21-FibonacciBlocks.png) + + +斐波那契螺旋:通过绘制连接斐波那契平铺中正方形的相对角的圆弧而创建的金色螺旋的近似值; [4]该三角形使用大小为1、1、2、3、5、8、13和21的正方形。 + +![Fibonacci Spiral](https://upload.wikimedia.org/wikipedia/commons/2/2e/FibonacciSpiral.svg) + +## References + +- [Wikipedia](https://en.wikipedia.org/wiki/Fibonacci_number) diff --git a/src/algorithms/math/prime-factors/README.md b/src/algorithms/math/prime-factors/README.md index a0f1d1535d..d8e0f96e3f 100644 --- a/src/algorithms/math/prime-factors/README.md +++ b/src/algorithms/math/prime-factors/README.md @@ -1,5 +1,8 @@ # Prime Factors +_Read this in other languages:_ +[简体中文](README.zh-CN.md). + **Prime number** is a whole number greater than `1` that **cannot** be made by multiplying other whole numbers. The first few prime numbers are: `2`, `3`, `5`, `7`, `11`, `13`, `17`, `19` and so on. If we **can** make it by multiplying other whole numbers it is a **Composite Number**. diff --git a/src/algorithms/math/prime-factors/README.zh-CN.md b/src/algorithms/math/prime-factors/README.zh-CN.md new file mode 100644 index 0000000000..c6ab82e39b --- /dev/null +++ b/src/algorithms/math/prime-factors/README.zh-CN.md @@ -0,0 +1,38 @@ +# 质数因子 + +_Read this in other languages:_ +[english](README.md). + +**质数** 是一个比 `1` 大的整数,且 **不能**由其它整数相乘得出。前几个质数是: `2`, `3`, `5`, `7`, `11`, `13`, `17`, `19`,依此类推。 + +如果我们**能**通过其它整数相乘得出,我们则称它为**合数** + +![Composite numbers](https://www.mathsisfun.com/numbers/images/prime-composite.svg) + +_Image source: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_ + + +**质数因子**是那些相乘得到原始数的[质数](https://en.wikipedia.org/wiki/Prime_number)。例如`39`的质数因子是`3`和`13`,`15`的质数因子是`3`和`5`。 + +![Factors](https://www.mathsisfun.com/numbers/images/factor-2x3.svg) + +_Image source: [Math is Fun](https://www.mathsisfun.com/prime-factorization.html)_ + +## 正确计算所有的质数因子及其数量 + +这个方法将自然数`n`从`i = 2`除到`i = n`(仅按质数索引)。且每次循环后`n`的值被`(n / i)`的值替换。 + +在最坏的情况下,即循环从`i = 2`执行到 `i = n`,上述方法的时间复杂度为`O(n)`。时间复杂度其实可以从`O(n)`减少到`O(sqrt(n))`,通过减少循环的执行次数,从`i = 2`执行到 `i = sqrt(n)`。因为可以确认,当`i`大于`sqrt(n)`时,除了`n`本身,再没有数可以被整除了。 + +## Hardy-Ramanujan公式用于计算质数因子的个数 + +1917年,G.H Hardy和Srinivasa Ramanujan提出了一个定理,该定理指出,自然数 `n` 的不同素数的数 `ω(n)` 的正态次序是`log(log(n))`。 + +粗略地讲,这意味着大多数数字具有这个数量的质数因子。 + +## References + +- [Prime numbers on Math is Fun](https://www.mathsisfun.com/prime-factorization.html) +- [Prime numbers on Wikipedia](https://en.wikipedia.org/wiki/Prime_number) +- [Hardy–Ramanujan theorem on Wikipedia](https://en.wikipedia.org/wiki/Hardy%E2%80%93Ramanujan_theorem) +- [Prime factorization of a number on Youtube](https://www.youtube.com/watch?v=6PDtgHhpCHo&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=82) From 83357075c4698f487af733e6e0bf9567ba94c266 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Sun, 3 Jan 2021 10:45:41 +0100 Subject: [PATCH 078/264] Add Chinese translation for Math sections. --- src/algorithms/math/bits/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/algorithms/math/bits/README.md b/src/algorithms/math/bits/README.md index 0f870f8995..1218094287 100644 --- a/src/algorithms/math/bits/README.md +++ b/src/algorithms/math/bits/README.md @@ -1,7 +1,8 @@ # Bit Manipulation _Read this in other languages:_ -[français](README.fr-FR.md),[简体中文](README.zh-CN.md). +[français](README.fr-FR.md), +[简体中文](README.zh-CN.md). #### Get Bit @@ -263,7 +264,7 @@ B = 6: 110 └──────┴────┴────┴─────────┴──────────┴─────────┴───────────┴───────────┘ ``` -> See [fullAdder.js](fullAdder.js) for further details. +> See [fullAdder.js](fullAdder.js) for further details. > See [Full Adder on YouTube](https://www.youtube.com/watch?v=wvJc9CZcvBc&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8). ## References From 028ffa6e9a0379c5ca9d11ae74901534b9f5edf6 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Tue, 20 Apr 2021 07:18:24 +0200 Subject: [PATCH 079/264] Getting rid of "React version not specified" warning while linting. --- .eslintrc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.eslintrc b/.eslintrc index 076399682c..e1c40a0adb 100644 --- a/.eslintrc +++ b/.eslintrc @@ -11,5 +11,10 @@ "class-methods-use-this": "off", "arrow-body-style": "off", "no-loop-func": "off" + }, + "settings": { + "react": { + "version": "latest" + } } } From f0b246a5214f6f392ea4ec19a9fd550a8b26fcbb Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Tue, 20 Apr 2021 17:47:33 +0200 Subject: [PATCH 080/264] Adding a Seam Carving algorithm with Dynamic Programming implementation. (#693) * Adding a Seam Carving algorithm with Dynamic Programming implementation. * Adding a Seam Carving algorithm with Dynamic Programming implementation. * Adding a Seam Carving algorithm with Dynamic Programming implementation. * Testing Husky integration. * Testing Husky integration. --- .husky/.gitignore | 1 + .husky/pre-commit | 5 + .huskyrc.json | 5 - README.md | 3 + package-lock.json | 2650 +++++++++-------- package.json | 6 +- .../image-processing/seam-carving/README.md | 509 ++++ .../seam-carving/README.ru-RU.md | 509 ++++ .../__tests__/resizeImageWidth.test.js | 51 + .../__tests__/test-image-after.jpg | Bin 0 -> 6088 bytes .../__tests__/test-image-before.jpg | Bin 0 -> 3395 bytes .../seam-carving/resizeImageWidth.js | 253 ++ .../image-processing/utils/imageData.js | 39 + 13 files changed, 2838 insertions(+), 1193 deletions(-) create mode 100644 .husky/.gitignore create mode 100755 .husky/pre-commit delete mode 100644 .huskyrc.json create mode 100644 src/algorithms/image-processing/seam-carving/README.md create mode 100644 src/algorithms/image-processing/seam-carving/README.ru-RU.md create mode 100644 src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js create mode 100644 src/algorithms/image-processing/seam-carving/__tests__/test-image-after.jpg create mode 100644 src/algorithms/image-processing/seam-carving/__tests__/test-image-before.jpg create mode 100644 src/algorithms/image-processing/seam-carving/resizeImageWidth.js create mode 100644 src/algorithms/image-processing/utils/imageData.js diff --git a/.husky/.gitignore b/.husky/.gitignore new file mode 100644 index 0000000000..31354ec138 --- /dev/null +++ b/.husky/.gitignore @@ -0,0 +1 @@ +_ diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000000..bec1c08a1a --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,5 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +# npm run lint +# npm run test diff --git a/.huskyrc.json b/.huskyrc.json deleted file mode 100644 index 6e9b7b23b7..0000000000 --- a/.huskyrc.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "hooks": { - "pre-commit": "npm run lint && npm run test" - } -} diff --git a/README.md b/README.md index 8bb2bf3cdf..71b0798fbe 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,8 @@ a set of rules that precisely define a sequence of operations. * `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation) * `B` [k-NN](src/algorithms/ml/knn) - k-nearest neighbors classification algorithm * `B` [k-Means](src/algorithms/ml/k-means) - k-Means clustering algorithm +* **Image Processing** + * `B` [Seam Carving](src/algorithms/image-processing/seam-carving) - content-aware image resizing algorithm * **Uncategorized** * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower) * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm @@ -203,6 +205,7 @@ algorithm is an abstraction higher than a computer program. * `B` [Unique Paths](src/algorithms/uncategorized/unique-paths) * `B` [Rain Terraces](src/algorithms/uncategorized/rain-terraces) - trapping rain water problem * `B` [Recursive Staircase](src/algorithms/uncategorized/recursive-staircase) - count the number of ways to reach to the top + * `B` [Seam Carving](src/algorithms/image-processing/seam-carving) - content-aware image resizing algorithm * `A` [Levenshtein Distance](src/algorithms/string/levenshtein-distance) - minimum edit distance between two sequences * `A` [Longest Common Subsequence](src/algorithms/sets/longest-common-subsequence) (LCS) * `A` [Longest Common Substring](src/algorithms/string/longest-common-substring) diff --git a/package-lock.json b/package-lock.json index aeeed97b47..93de7f66c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,41 +23,40 @@ } }, "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", + "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", "dev": true, "requires": { - "@babel/highlight": "^7.10.4" + "@babel/highlight": "^7.12.13" } }, "@babel/compat-data": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.7.tgz", - "integrity": "sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.15.tgz", + "integrity": "sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA==", "dev": true }, "@babel/core": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", - "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helpers": "^7.12.5", - "@babel/parser": "^7.12.7", - "@babel/template": "^7.12.7", - "@babel/traverse": "^7.12.9", - "@babel/types": "^7.12.7", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.15.tgz", + "integrity": "sha512-6GXmNYeNjS2Uz+uls5jalOemgIhnTMeaXo+yBUA72kC2uX/8VW6XyhVIo2L8/q0goKQA3EVKx0KOQpVKSeWadQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.13.9", + "@babel/helper-compilation-targets": "^7.13.13", + "@babel/helper-module-transforms": "^7.13.14", + "@babel/helpers": "^7.13.10", + "@babel/parser": "^7.13.15", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.15", + "@babel/types": "^7.13.14", "convert-source-map": "^1.7.0", "debug": "^4.1.0", - "gensync": "^1.0.0-beta.1", + "gensync": "^1.0.0-beta.2", "json5": "^2.1.2", - "lodash": "^4.17.19", - "resolve": "^1.3.2", - "semver": "^5.4.1", + "semver": "^6.3.0", "source-map": "^0.5.0" }, "dependencies": { @@ -71,9 +70,9 @@ } }, "json5": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", - "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "dev": true, "requires": { "minimist": "^1.2.5" @@ -84,222 +83,206 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true } } }, "@babel/generator": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", - "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", + "version": "7.13.9", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", + "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", "dev": true, "requires": { - "@babel/types": "^7.12.5", + "@babel/types": "^7.13.0", "jsesc": "^2.5.1", "source-map": "^0.5.0" } }, "@babel/helper-annotate-as-pure": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.10.tgz", - "integrity": "sha512-XplmVbC1n+KY6jL8/fgLVXXUauDIB+lD5+GsQEh6F6GBF1dq1qy4DP4yXWzDKcoqXB3X58t61e85Fitoww4JVQ==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz", + "integrity": "sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==", "dev": true, "requires": { - "@babel/types": "^7.12.10" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.11.tgz", - "integrity": "sha512-ukA9SQtKThINm++CX1CwmliMrE54J6nIYB5XTwL5f/CLFW9owfls+YSU8tVW15RQ2w+a3fSbPjC6HdQNtWZkiA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } + "@babel/types": "^7.12.13" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", - "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz", + "integrity": "sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA==", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-explode-assignable-expression": "^7.12.13", + "@babel/types": "^7.12.13" } }, "@babel/helper-compilation-targets": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz", - "integrity": "sha512-+qH6NrscMolUlzOYngSBMIOQpKUGPPsc61Bu5W10mg84LxZ7cmvnBHzARKbDoFxVvqqAbj6Tg6N7bSrWSPXMyw==", + "version": "7.13.13", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.13.tgz", + "integrity": "sha512-q1kcdHNZehBwD9jYPh3WyXcsFERi39X4I59I3NadciWtNDyZ6x+GboOxncFK0kXlKIv6BJm5acncehXWUjWQMQ==", "dev": true, "requires": { - "@babel/compat-data": "^7.12.5", - "@babel/helper-validator-option": "^7.12.1", + "@babel/compat-data": "^7.13.12", + "@babel/helper-validator-option": "^7.12.17", "browserslist": "^4.14.5", - "semver": "^5.5.0" + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "@babel/helper-create-class-features-plugin": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz", - "integrity": "sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==", + "version": "7.13.11", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.11.tgz", + "integrity": "sha512-ays0I7XYq9xbjCSvT+EvysLgfc3tOkwCULHjrnscGT3A9qD4sk3wXnJ3of0MAWsWGjdinFvajHU2smYuqXKMrw==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-member-expression-to-functions": "^7.12.1", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.10.4" + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-member-expression-to-functions": "^7.13.0", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/helper-replace-supers": "^7.13.0", + "@babel/helper-split-export-declaration": "^7.12.13" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.7.tgz", - "integrity": "sha512-idnutvQPdpbduutvi3JVfEgcVIHooQnhvhx0Nk9isOINOIGYkZea1Pk2JlJRiUnMefrlvr0vkByATBY/mB4vjQ==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz", + "integrity": "sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-annotate-as-pure": "^7.12.13", "regexpu-core": "^4.7.1" } }, - "@babel/helper-define-map": { - "version": "7.10.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", - "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/types": "^7.10.5", - "lodash": "^4.17.19" - } - }, "@babel/helper-explode-assignable-expression": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz", - "integrity": "sha512-dmUwH8XmlrUpVqgtZ737tK88v07l840z9j3OEhCLwKTkjlvKpfqXVIZ0wpK3aeOxspwGrf/5AP5qLx4rO3w5rA==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz", + "integrity": "sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA==", "dev": true, "requires": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.13.0" } }, "@babel/helper-function-name": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", - "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", + "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-get-function-arity": "^7.12.13", + "@babel/template": "^7.12.13", + "@babel/types": "^7.12.13" } }, "@babel/helper-get-function-arity": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", - "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", + "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", "dev": true, "requires": { - "@babel/types": "^7.10.4" + "@babel/types": "^7.12.13" } }, "@babel/helper-hoist-variables": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", - "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.0.tgz", + "integrity": "sha512-0kBzvXiIKfsCA0y6cFEIJf4OdzfpRuNk4+YTeHZpGGc666SATFKTz6sRncwFnQk7/ugJ4dSrCj6iJuvW4Qwr2g==", "dev": true, "requires": { - "@babel/types": "^7.10.4" + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz", - "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==", + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz", + "integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==", "dev": true, "requires": { - "@babel/types": "^7.12.7" + "@babel/types": "^7.13.12" } }, "@babel/helper-module-imports": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", - "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz", + "integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==", "dev": true, "requires": { - "@babel/types": "^7.12.5" + "@babel/types": "^7.13.12" } }, "@babel/helper-module-transforms": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", - "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-simple-access": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/helper-validator-identifier": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.1", - "@babel/types": "^7.12.1", - "lodash": "^4.17.19" + "version": "7.13.14", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz", + "integrity": "sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.13.12", + "@babel/helper-replace-supers": "^7.13.12", + "@babel/helper-simple-access": "^7.13.12", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/helper-validator-identifier": "^7.12.11", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.13", + "@babel/types": "^7.13.14" } }, "@babel/helper-optimise-call-expression": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.7.tgz", - "integrity": "sha512-I5xc9oSJ2h59OwyUqjv95HRyzxj53DAubUERgQMrpcCEYQyToeHA+NEcUEsVWB4j53RDeskeBJ0SgRAYHDBckw==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", + "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", "dev": true, "requires": { - "@babel/types": "^7.12.7" + "@babel/types": "^7.12.13" } }, "@babel/helper-plugin-utils": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", - "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", + "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", "dev": true }, "@babel/helper-remap-async-to-generator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz", - "integrity": "sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz", + "integrity": "sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-wrap-function": "^7.10.4", - "@babel/types": "^7.12.1" + "@babel/helper-annotate-as-pure": "^7.12.13", + "@babel/helper-wrap-function": "^7.13.0", + "@babel/types": "^7.13.0" } }, "@babel/helper-replace-supers": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz", - "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==", + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz", + "integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.12.1", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/traverse": "^7.12.5", - "@babel/types": "^7.12.5" + "@babel/helper-member-expression-to-functions": "^7.13.12", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.12" } }, "@babel/helper-simple-access": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", - "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz", + "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==", "dev": true, "requires": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.13.12" } }, "@babel/helper-skip-transparent-expression-wrappers": { @@ -312,197 +295,199 @@ } }, "@babel/helper-split-export-declaration": { - "version": "7.11.0", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", - "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", + "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", "dev": true, "requires": { - "@babel/types": "^7.11.0" + "@babel/types": "^7.12.13" } }, "@babel/helper-validator-identifier": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", - "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.11.tgz", - "integrity": "sha512-TBFCyj939mFSdeX7U7DDj32WtzYY7fDcalgq8v3fBZMNOJQNn7nOYzMaUCiPxPYfCup69mtIpqlKgMZLvQ8Xhw==", + "version": "7.12.17", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", + "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", "dev": true }, "@babel/helper-wrap-function": { - "version": "7.12.3", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.12.3.tgz", - "integrity": "sha512-Cvb8IuJDln3rs6tzjW3Y8UeelAOdnpB8xtQ4sme2MSZ9wOxrbThporC0y/EtE16VAtoyEfLM404Xr1e0OOp+ow==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz", + "integrity": "sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.10.4", - "@babel/types": "^7.10.4" + "@babel/helper-function-name": "^7.12.13", + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0" } }, "@babel/helpers": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", - "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.10.tgz", + "integrity": "sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==", "dev": true, "requires": { - "@babel/template": "^7.10.4", - "@babel/traverse": "^7.12.5", - "@babel/types": "^7.12.5" + "@babel/template": "^7.12.13", + "@babel/traverse": "^7.13.0", + "@babel/types": "^7.13.0" } }, "@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", + "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-validator-identifier": "^7.12.11", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz", - "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.15.tgz", + "integrity": "sha512-b9COtcAlVEQljy/9fbcMHpG+UIW9ReF+gpaxDHTlZd0c6/UU9ng8zdySAW9sRTzpvcdCHn6bUcbuYUgGzLAWVQ==", "dev": true }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz", - "integrity": "sha512-d+/o30tJxFxrA1lhzJqiUcEJdI6jKlNregCv5bASeGf2Q4MXmnwH7viDo7nhx1/ohf09oaH8j1GVYG/e3Yqk6A==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.15.tgz", + "integrity": "sha512-VapibkWzFeoa6ubXy/NgV5U2U4MVnUlvnx6wo1XhlsaTrLYWE0UFpDQsVrmn22q5CzeloqJ8gEMHSKxuee6ZdA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.12.1", - "@babel/plugin-syntax-async-generators": "^7.8.0" + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-remap-async-to-generator": "^7.13.0", + "@babel/plugin-syntax-async-generators": "^7.8.4" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz", - "integrity": "sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz", + "integrity": "sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-class-features-plugin": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0" } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz", - "integrity": "sha512-a4rhUSZFuq5W8/OO8H7BL5zspjnc1FLd9hlOxIK/f7qG4a0qsqk8uvF/ywgBA8/OmjsapjpvaEOYItfGG1qIvQ==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.13.8.tgz", + "integrity": "sha512-ONWKj0H6+wIRCkZi9zSbZtE/r73uOhMVHh256ys0UzfM7I3d4n+spZNWjOnJv2gzopumP2Wxi186vI8N0Y2JyQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-dynamic-import": "^7.8.0" + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.1.tgz", - "integrity": "sha512-6CThGf0irEkzujYS5LQcjBx8j/4aQGiVv7J9+2f7pGfxqyKh3WnmVJYW3hdrQjyksErMGBPQrCnHfOtna+WLbw==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.13.tgz", + "integrity": "sha512-INAgtFo4OnLN3Y/j0VwAgw3HDXcDtX+C/erMvWzuV9v71r7urb6iyMXu7eM9IgLr1ElLlOkaHjJ0SbCmdOQ3Iw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-plugin-utils": "^7.12.13", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.12.1.tgz", - "integrity": "sha512-GoLDUi6U9ZLzlSda2Df++VSqDJg3CG+dR0+iWsv6XRw1rEq+zwt4DirM9yrxW6XWaTpmai1cWJLMfM8qQJf+yw==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.13.8.tgz", + "integrity": "sha512-w4zOPKUFPX1mgvTmL/fcEqy34hrQ1CRcGxdphBc6snDnnqJ47EZDIyop6IwXzAC8G916hsIuXB2ZMBCExC5k7Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-json-strings": "^7.8.0" + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-json-strings": "^7.8.3" } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.12.1.tgz", - "integrity": "sha512-k8ZmVv0JU+4gcUGeCDZOGd0lCIamU/sMtIiX3UWnUc5yzgq6YUGyEolNYD+MLYKfSzgECPcqetVcJP9Afe/aCA==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.13.8.tgz", + "integrity": "sha512-aul6znYB4N4HGweImqKn59Su9RS8lbUIqxtXTOcAGtNIDczoEFv+l1EhmX8rUBp3G1jMjKJm8m0jXVp63ZpS4A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-plugin-utils": "^7.13.0", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz", - "integrity": "sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.13.8.tgz", + "integrity": "sha512-iePlDPBn//UhxExyS9KyeYU7RM9WScAG+D3Hhno0PLJebAEpDZMocbDe64eqynhNAnwz/vZoL/q/QB2T1OH39A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" } }, "@babel/plugin-proposal-numeric-separator": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.7.tgz", - "integrity": "sha512-8c+uy0qmnRTeukiGsjLGy6uVs/TFjJchGXUeBqlG4VWYOdJWkhhVPdQ3uHwbmalfJwv2JsV0qffXP4asRfL2SQ==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.13.tgz", + "integrity": "sha512-O1jFia9R8BUCl3ZGB7eitaAPu62TXJRHn7rh+ojNERCFyqRwJMTmhz+tJ+k0CwI6CLjX/ee4qW74FSqlq9I35w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-plugin-utils": "^7.12.13", "@babel/plugin-syntax-numeric-separator": "^7.10.4" } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", - "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.8.tgz", + "integrity": "sha512-DhB2EuB1Ih7S3/IRX5AFVgZ16k3EzfRbq97CxAVI1KSYcW+lexV8VZb7G7L8zuPVSdQMRn0kiBpf/Yzu9ZKH0g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-transform-parameters": "^7.12.1" + "@babel/compat-data": "^7.13.8", + "@babel/helper-compilation-targets": "^7.13.8", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.13.0" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.1.tgz", - "integrity": "sha512-hFvIjgprh9mMw5v42sJWLI1lzU5L2sznP805zeT6rySVRA0Y18StRhDqhSxlap0oVgItRsB6WSROp4YnJTJz0g==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.13.8.tgz", + "integrity": "sha512-0wS/4DUF1CuTmGo+NiaHfHcVSeSLj5S3e6RivPTg/2k3wOv3jO35tZ6/ZWsQhQMvdgI7CwphjQa/ccarLymHVA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.7.tgz", - "integrity": "sha512-4ovylXZ0PWmwoOvhU2vhnzVNnm88/Sm9nx7V8BPgMvAzn5zDou3/Awy0EjglyubVHasJj+XCEkr/r1X3P5elCA==", + "version": "7.13.12", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.12.tgz", + "integrity": "sha512-fcEdKOkIB7Tf4IxrgEVeFC4zeJSTr78no9wTdBuZZbqF64kzllU0ybo2zrzm7gUQfxGhBgq4E39oRs8Zx/RMYQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-plugin-utils": "^7.13.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", - "@babel/plugin-syntax-optional-chaining": "^7.8.0" + "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, "@babel/plugin-proposal-private-methods": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.12.1.tgz", - "integrity": "sha512-mwZ1phvH7/NHK6Kf8LP7MYDogGV+DKB1mryFOEwx5EBNQrosvIczzZFTUmWaeujd5xT6G1ELYWUz3CutMhjE1w==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz", + "integrity": "sha512-MXyyKQd9inhx1kDYPkFRVOBXQ20ES8Pto3T7UZ92xj2mY0EVD8oAVzeyYuVfy/mxAdTSIayOvg+aVzcHV2bn6Q==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-class-features-plugin": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz", - "integrity": "sha512-MYq+l+PvHuw/rKUz1at/vb6nCnQ2gmJBNaM62z0OgH7B2W1D9pvkpYtlti9bGtizNIU1K3zm4bZF9F91efVY0w==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz", + "integrity": "sha512-XyJmZidNfofEkqFV5VC/bLabGmO5QzenPO/YOfGuEbgU+2sSwMmio3YLb4WtBgcmmdwZHyVyv8on77IUjQ5Gvg==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-regexp-features-plugin": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-syntax-async-generators": { @@ -524,12 +509,12 @@ } }, "@babel/plugin-syntax-class-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz", - "integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-syntax-dynamic-import": { @@ -623,325 +608,324 @@ } }, "@babel/plugin-syntax-top-level-await": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz", - "integrity": "sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz", + "integrity": "sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz", - "integrity": "sha512-5QB50qyN44fzzz4/qxDPQMBCTHgxg3n0xRBLJUmBlLoU/sFvxVWGZF/ZUfMVDQuJUKXaBhbupxIzIfZ6Fwk/0A==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz", + "integrity": "sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.13.0" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz", - "integrity": "sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz", + "integrity": "sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-remap-async-to-generator": "^7.12.1" + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-remap-async-to-generator": "^7.13.0" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.1.tgz", - "integrity": "sha512-5OpxfuYnSgPalRpo8EWGPzIYf0lHBWORCkj5M0oLBwHdlux9Ri36QqGW3/LR13RSVOAoUUMzoPI/jpE4ABcHoA==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz", + "integrity": "sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.11.tgz", - "integrity": "sha512-atR1Rxc3hM+VPg/NvNvfYw0npQEAcHuJ+MGZnFn6h3bo+1U3BWXMdFMlvVRApBTWKQMX7SOwRJZA5FBF/JQbvA==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.13.tgz", + "integrity": "sha512-Pxwe0iqWJX4fOOM2kEZeUuAxHMWb9nK+9oh5d11bsLoB0xMg+mkDpt0eYuDZB7ETrY9bbcVlKUGTOGWy7BHsMQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-classes": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz", - "integrity": "sha512-/74xkA7bVdzQTBeSUhLLJgYIcxw/dpEpCdRDiHgPJ3Mv6uC11UhjpOhl72CgqbBCmt1qtssCyB2xnJm1+PFjog==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.13.0.tgz", + "integrity": "sha512-9BtHCPUARyVH1oXGcSJD3YpsqRLROJx5ZNP6tN5vnk17N0SVf9WCtf8Nuh1CFmgByKKAIMstitKduoCmsaDK5g==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.10.4", - "@babel/helper-define-map": "^7.10.4", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-optimise-call-expression": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.12.1", - "@babel/helper-split-export-declaration": "^7.10.4", + "@babel/helper-annotate-as-pure": "^7.12.13", + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-optimise-call-expression": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-replace-supers": "^7.13.0", + "@babel/helper-split-export-declaration": "^7.12.13", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.12.1.tgz", - "integrity": "sha512-vVUOYpPWB7BkgUWPo4C44mUQHpTZXakEqFjbv8rQMg7TC6S6ZhGZ3otQcRH6u7+adSlE5i0sp63eMC/XGffrzg==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz", + "integrity": "sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.13.0" } }, "@babel/plugin-transform-destructuring": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.12.1.tgz", - "integrity": "sha512-fRMYFKuzi/rSiYb2uRLiUENJOKq4Gnl+6qOv5f8z0TZXg3llUwUhsNNwrwaT/6dUhJTzNpBr+CUvEWBtfNY1cw==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.0.tgz", + "integrity": "sha512-zym5em7tePoNT9s964c0/KU3JPPnuq7VhIxPRefJ4/s82cD+q1mgKfuGRDMCPL0HTyKz4dISuQlCusfgCJ86HA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.13.0" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.1.tgz", - "integrity": "sha512-B2pXeRKoLszfEW7J4Hg9LoFaWEbr/kzo3teWHmtFCszjRNa/b40f9mfeqZsIDLLt/FjwQ6pz/Gdlwy85xNckBA==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz", + "integrity": "sha512-foDrozE65ZFdUC2OfgeOCrEPTxdB3yjqxpXh8CH+ipd9CHd4s/iq81kcUpyH8ACGNEPdFqbtzfgzbT/ZGlbDeQ==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-regexp-features-plugin": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.1.tgz", - "integrity": "sha512-iRght0T0HztAb/CazveUpUQrZY+aGKKaWXMJ4uf9YJtqxSUe09j3wteztCUDRHs+SRAL7yMuFqUsLoAKKzgXjw==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz", + "integrity": "sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.1.tgz", - "integrity": "sha512-7tqwy2bv48q+c1EHbXK0Zx3KXd2RVQp6OC7PbwFNt/dPTAV3Lu5sWtWuAj8owr5wqtWnqHfl2/mJlUmqkChKug==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz", + "integrity": "sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-for-of": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz", - "integrity": "sha512-Zaeq10naAsuHo7heQvyV0ptj4dlZJwZgNAtBYBnu5nNKJoW62m0zKcIEyVECrUKErkUkg6ajMy4ZfnVZciSBhg==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz", + "integrity": "sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.13.0" } }, "@babel/plugin-transform-function-name": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.1.tgz", - "integrity": "sha512-JF3UgJUILoFrFMEnOJLJkRHSk6LUSXLmEFsA23aR2O5CSLUxbeUX1IZ1YQ7Sn0aXb601Ncwjx73a+FVqgcljVw==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz", + "integrity": "sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.1.tgz", - "integrity": "sha512-+PxVGA+2Ag6uGgL0A5f+9rklOnnMccwEBzwYFL3EUaKuiyVnUipyXncFcfjSkbimLrODoqki1U9XxZzTvfN7IQ==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz", + "integrity": "sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.1.tgz", - "integrity": "sha512-1sxePl6z9ad0gFMB9KqmYofk34flq62aqMt9NqliS/7hPEpURUCMbyHXrMPlo282iY7nAvUB1aQd5mg79UD9Jg==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz", + "integrity": "sha512-kxLkOsg8yir4YeEPHLuO2tXP9R/gTjpuTOjshqSpELUN3ZAg2jfDnKUvzzJxObun38sw3wm4Uu69sX/zA7iRvg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.12.1.tgz", - "integrity": "sha512-tDW8hMkzad5oDtzsB70HIQQRBiTKrhfgwC/KkJeGsaNFTdWhKNt/BiE8c5yj19XiGyrxpbkOfH87qkNg1YGlOQ==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.13.0.tgz", + "integrity": "sha512-EKy/E2NHhY/6Vw5d1k3rgoobftcNUmp9fGjb9XZwQLtTctsRBOTRO7RHHxfIky1ogMN5BxN7p9uMA3SzPfotMQ==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.12.1.tgz", - "integrity": "sha512-dY789wq6l0uLY8py9c1B48V8mVL5gZh/+PQ5ZPrylPYsnAvnEMjqsUXkuoDVPeVK+0VyGar+D08107LzDQ6pag==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.13.8.tgz", + "integrity": "sha512-9QiOx4MEGglfYZ4XOnU79OHr6vIWUakIj9b4mioN8eQIoEh+pf5p/zEB36JpDFWA12nNMiRf7bfoRvl9Rn79Bw==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-simple-access": "^7.12.1", + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-simple-access": "^7.12.13", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.1.tgz", - "integrity": "sha512-Hn7cVvOavVh8yvW6fLwveFqSnd7rbQN3zJvoPNyNaQSvgfKmDBO9U1YL9+PCXGRlZD9tNdWTy5ACKqMuzyn32Q==", + "version": "7.13.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.13.8.tgz", + "integrity": "sha512-hwqctPYjhM6cWvVIlOIe27jCIBgHCsdH2xCJVAYQm7V5yTMoilbVMi9f6wKg0rpQAOn6ZG4AOyvCqFF/hUh6+A==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.10.4", - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-hoist-variables": "^7.13.0", + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-validator-identifier": "^7.12.11", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.12.1.tgz", - "integrity": "sha512-aEIubCS0KHKM0zUos5fIoQm+AZUMt1ZvMpqz0/H5qAQ7vWylr9+PLYurT+Ic7ID/bKLd4q8hDovaG3Zch2uz5Q==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.13.0.tgz", + "integrity": "sha512-D/ILzAh6uyvkWjKKyFE/W0FzWwasv6vPTSqPcjxFqn6QpX3u8DjRVliq4F2BamO2Wee/om06Vyy+vPkNrd4wxw==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-module-transforms": "^7.13.0", + "@babel/helper-plugin-utils": "^7.13.0" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.1.tgz", - "integrity": "sha512-tB43uQ62RHcoDp9v2Nsf+dSM8sbNodbEicbQNA53zHz8pWUhsgHSJCGpt7daXxRydjb0KnfmB+ChXOv3oADp1Q==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz", + "integrity": "sha512-Xsm8P2hr5hAxyYblrfACXpQKdQbx4m2df9/ZZSQ8MAhsadw06+jW7s9zsSw6he+mJZXRlVMyEnVktJo4zjk1WA==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1" + "@babel/helper-create-regexp-features-plugin": "^7.12.13" } }, "@babel/plugin-transform-new-target": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.1.tgz", - "integrity": "sha512-+eW/VLcUL5L9IvJH7rT1sT0CzkdUTvPrXC2PXTn/7z7tXLBuKvezYbGdxD5WMRoyvyaujOq2fWoKl869heKjhw==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz", + "integrity": "sha512-/KY2hbLxrG5GTQ9zzZSc3xWiOy379pIETEhbtzwZcw9rvuaVV4Fqy7BYGYOWZnaoXIQYbbJ0ziXLa/sKcGCYEQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-object-super": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.1.tgz", - "integrity": "sha512-AvypiGJH9hsquNUn+RXVcBdeE3KHPZexWRdimhuV59cSoOt5kFBmqlByorAeUlGG2CJWd0U+4ZtNKga/TB0cAw==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz", + "integrity": "sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-replace-supers": "^7.12.1" + "@babel/helper-plugin-utils": "^7.12.13", + "@babel/helper-replace-supers": "^7.12.13" } }, "@babel/plugin-transform-parameters": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz", - "integrity": "sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.13.0.tgz", + "integrity": "sha512-Jt8k/h/mIwE2JFEOb3lURoY5C85ETcYPnbuAJ96zRBzh1XHtQZfs62ChZ6EP22QlC8c7Xqr9q+e1SU5qttwwjw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.13.0" } }, "@babel/plugin-transform-property-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.1.tgz", - "integrity": "sha512-6MTCR/mZ1MQS+AwZLplX4cEySjCpnIF26ToWo942nqn8hXSm7McaHQNeGx/pt7suI1TWOWMfa/NgBhiqSnX0cQ==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz", + "integrity": "sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-regenerator": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz", - "integrity": "sha512-gYrHqs5itw6i4PflFX3OdBPMQdPbF4bj2REIUxlMRUFk0/ZOAIpDFuViuxPjUL7YC8UPnf+XG7/utJvqXdPKng==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.13.15.tgz", + "integrity": "sha512-Bk9cOLSz8DiurcMETZ8E2YtIVJbFCPGW28DJWUakmyVWtQSm6Wsf0p4B4BfEr/eL2Nkhe/CICiUiMOCi1TPhuQ==", "dev": true, "requires": { "regenerator-transform": "^0.14.2" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.1.tgz", - "integrity": "sha512-pOnUfhyPKvZpVyBHhSBoX8vfA09b7r00Pmm1sH+29ae2hMTKVmSp4Ztsr8KBKjLjx17H0eJqaRC3bR2iThM54A==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz", + "integrity": "sha512-xhUPzDXxZN1QfiOy/I5tyye+TRz6lA7z6xaT4CLOjPRMVg1ldRf0LHw0TDBpYL4vG78556WuHdyO9oi5UmzZBg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz", - "integrity": "sha512-GFZS3c/MhX1OusqB1MZ1ct2xRzX5ppQh2JU1h2Pnfk88HtFTM+TWQqJNfwkmxtPQtb/s1tk87oENfXJlx7rSDw==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz", + "integrity": "sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-spread": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.12.1.tgz", - "integrity": "sha512-vuLp8CP0BE18zVYjsEBZ5xoCecMK6LBMMxYzJnh01rxQRvhNhH1csMMmBfNo5tGpGO+NhdSNW2mzIvBu3K1fng==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz", + "integrity": "sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-plugin-utils": "^7.13.0", "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.7.tgz", - "integrity": "sha512-VEiqZL5N/QvDbdjfYQBhruN0HYjSPjC4XkeqW4ny/jNtH9gcbgaqBIXYEZCNnESMAGs0/K/R7oFGMhOyu/eIxg==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz", + "integrity": "sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-template-literals": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz", - "integrity": "sha512-b4Zx3KHi+taXB1dVRBhVJtEPi9h1THCeKmae2qP0YdUHIFhVjtpqqNfxeVAa1xeHVhAy4SbHxEwx5cltAu5apw==", + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz", + "integrity": "sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.13.0" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.10.tgz", - "integrity": "sha512-JQ6H8Rnsogh//ijxspCjc21YPd3VLVoYtAwv3zQmqAt8YGYUtdo5usNhdl4b9/Vir2kPFZl6n1h0PfUz4hJhaA==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz", + "integrity": "sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.1.tgz", - "integrity": "sha512-I8gNHJLIc7GdApm7wkVnStWssPNbSRMPtgHdmH3sRM1zopz09UWPS4x5V4n1yz/MIWTVnJ9sp6IkuXdWM4w+2Q==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz", + "integrity": "sha512-0bHEkdwJ/sN/ikBHfSmOXPypN/beiGqjo+o4/5K+vxEFNPRPdImhviPakMKG4x96l85emoa0Z6cDflsdBusZbw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.1.tgz", - "integrity": "sha512-SqH4ClNngh/zGwHZOOQMTD+e8FGWexILV+ePMyiDJttAWRh5dhDL8rcl5lSgU3Huiq6Zn6pWTMvdPAb21Dwdyg==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz", + "integrity": "sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.1", - "@babel/helper-plugin-utils": "^7.10.4" + "@babel/helper-create-regexp-features-plugin": "^7.12.13", + "@babel/helper-plugin-utils": "^7.12.13" } }, "@babel/preset-env": { @@ -1016,25 +1000,6 @@ "@babel/types": "^7.12.11", "core-js-compat": "^3.8.0", "semver": "^5.5.0" - }, - "dependencies": { - "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "@babel/types": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.11.tgz", - "integrity": "sha512-ukA9SQtKThINm++CX1CwmliMrE54J6nIYB5XTwL5f/CLFW9owfls+YSU8tVW15RQ2w+a3fSbPjC6HdQNtWZkiA==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", - "to-fast-properties": "^2.0.0" - } - } } }, "@babel/preset-modules": { @@ -1051,18 +1016,18 @@ } }, "@babel/runtime": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", - "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.13.10.tgz", + "integrity": "sha512-4QPkjJq6Ns3V/RgpEahRk+AGfL0eO6RHHtTWoNNr5mO49G6B5+X6d6THgWEAvTrznU5xYpbAlVKRYcsCgh/Akw==", "dev": true, "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/runtime-corejs3": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.12.5.tgz", - "integrity": "sha512-roGr54CsTmNPPzZoCP1AmDXuBoNao7tnSA83TXTwt+UK5QVyh1DIJnrgYRPWKCF2flqZQXwa7Yr8v7VmLzF0YQ==", + "version": "7.13.10", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.13.10.tgz", + "integrity": "sha512-x/XYVQ1h684pp1mJwOV4CyvqZXqbc8CMsMGUnAbuc82ZCdv1U63w5RSUzgDSXQHG5Rps/kiksH6g2D5BuaKyXg==", "dev": true, "requires": { "core-js-pure": "^3.0.0", @@ -1070,31 +1035,30 @@ } }, "@babel/template": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", - "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", + "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", "dev": true, "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/parser": "^7.12.7", - "@babel/types": "^7.12.7" + "@babel/code-frame": "^7.12.13", + "@babel/parser": "^7.12.13", + "@babel/types": "^7.12.13" } }, "@babel/traverse": { - "version": "7.12.9", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz", - "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==", + "version": "7.13.15", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.15.tgz", + "integrity": "sha512-/mpZMNvj6bce59Qzl09fHEs8Bt8NnpEDQYleHUPZQ3wXUMvXi+HJPLars68oAbmp839fGoOkv2pSL2z9ajCIaQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.10.4", - "@babel/generator": "^7.12.5", - "@babel/helper-function-name": "^7.10.4", - "@babel/helper-split-export-declaration": "^7.11.0", - "@babel/parser": "^7.12.7", - "@babel/types": "^7.12.7", + "@babel/code-frame": "^7.12.13", + "@babel/generator": "^7.13.9", + "@babel/helper-function-name": "^7.12.13", + "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/parser": "^7.13.15", + "@babel/types": "^7.13.14", "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.19" + "globals": "^11.1.0" }, "dependencies": { "debug": { @@ -1115,12 +1079,12 @@ } }, "@babel/types": { - "version": "7.12.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz", - "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==", + "version": "7.13.14", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.14.tgz", + "integrity": "sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.10.4", + "@babel/helper-validator-identifier": "^7.12.11", "lodash": "^4.17.19", "to-fast-properties": "^2.0.0" } @@ -1182,6 +1146,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true } } }, @@ -1256,9 +1226,9 @@ } }, "@istanbuljs/schema": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", - "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, "@jest/console": { @@ -1433,13 +1403,13 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" } }, "rimraf": { @@ -1457,6 +1427,15 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -1742,13 +1721,13 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" } }, "slash": { @@ -1868,35 +1847,35 @@ } }, "@nodelib/fs.scandir": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", - "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", + "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.3", + "@nodelib/fs.stat": "2.0.4", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", - "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", + "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", - "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", + "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.3", + "@nodelib/fs.scandir": "2.1.4", "fastq": "^1.6.0" } }, "@sinonjs/commons": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.1.tgz", - "integrity": "sha512-892K+kWUUi3cl+LlqEWIDrhvLgdL79tECi8JZUyq6IviKy/DNhuzCRlbHUjxK89f4ypPMMaFnFuR9Ie6DoIMsw==", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", "dev": true, "requires": { "type-detect": "4.0.8" @@ -1912,9 +1891,9 @@ } }, "@types/babel__core": { - "version": "7.1.12", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz", - "integrity": "sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ==", + "version": "7.1.14", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", + "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -1944,18 +1923,18 @@ } }, "@types/babel__traverse": { - "version": "7.0.16", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.16.tgz", - "integrity": "sha512-S63Dt4CZOkuTmpLGGWtT/mQdVORJOpx6SZWGVaP56dda/0Nx5nEe82K7/LAm8zYr6SfMq+1N2OreIOrHAx656w==", + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", + "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", "dev": true, "requires": { "@babel/types": "^7.3.0" } }, "@types/graceful-fs": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.4.tgz", - "integrity": "sha512-mWA/4zFQhfvOA8zWkXobwJvBD7vzcxgrOQ0J5CH1votGqdq9m7+FwtGaqyCZqC3NyyBkc9z4m+iry4LlqcMWJg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz", + "integrity": "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==", "dev": true, "requires": { "@types/node": "*" @@ -1996,9 +1975,9 @@ } }, "@types/json-schema": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", - "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==", + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", + "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", "dev": true }, "@types/json5": { @@ -2008,9 +1987,9 @@ "dev": true }, "@types/node": { - "version": "14.14.10", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.10.tgz", - "integrity": "sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ==", + "version": "14.14.41", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.41.tgz", + "integrity": "sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g==", "dev": true }, "@types/normalize-package-data": { @@ -2019,16 +1998,10 @@ "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", "dev": true }, - "@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, "@types/prettier": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.5.tgz", - "integrity": "sha512-UEyp8LwZ4Dg30kVU2Q3amHHyTn1jEdhCIE59ANed76GaT1Vp76DD3ZWSAxgCrw6wJ0TqeoBpqmfUHiUDPs//HQ==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", + "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", "dev": true }, "@types/stack-utils": { @@ -2038,62 +2011,61 @@ "dev": true }, "@types/yargs": { - "version": "15.0.11", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.11.tgz", - "integrity": "sha512-jfcNBxHFYJ4nPIacsi3woz1+kvUO6s1CyeEhtnDHBjHUMNj5UlW2GynmnSgiJJEdNg9yW5C8lfoNRZrHGv5EqA==", + "version": "15.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", + "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", "dev": true, "requires": { "@types/yargs-parser": "*" } }, "@types/yargs-parser": { - "version": "15.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz", - "integrity": "sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw==", + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", + "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", "dev": true }, "@typescript-eslint/experimental-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.9.0.tgz", - "integrity": "sha512-0p8GnDWB3R2oGhmRXlEnCvYOtaBCijtA5uBfH5GxQKsukdSQyI4opC4NGTUb88CagsoNQ4rb/hId2JuMbzWKFQ==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.0.tgz", + "integrity": "sha512-xJXHHl6TuAxB5AWiVrGhvbGL8/hbiCQ8FiWwObO3r0fnvBdrbWEDy1hlvGQOAWc6qsCWuWMKdVWlLAEMpxnddg==", "dev": true, "requires": { "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.9.0", - "@typescript-eslint/types": "4.9.0", - "@typescript-eslint/typescript-estree": "4.9.0", + "@typescript-eslint/scope-manager": "4.22.0", + "@typescript-eslint/types": "4.22.0", + "@typescript-eslint/typescript-estree": "4.22.0", "eslint-scope": "^5.0.0", "eslint-utils": "^2.0.0" } }, "@typescript-eslint/scope-manager": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.9.0.tgz", - "integrity": "sha512-q/81jtmcDtMRE+nfFt5pWqO0R41k46gpVLnuefqVOXl4QV1GdQoBWfk5REcipoJNQH9+F5l+dwa9Li5fbALjzg==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.22.0.tgz", + "integrity": "sha512-OcCO7LTdk6ukawUM40wo61WdeoA7NM/zaoq1/2cs13M7GyiF+T4rxuA4xM+6LeHWjWbss7hkGXjFDRcKD4O04Q==", "dev": true, "requires": { - "@typescript-eslint/types": "4.9.0", - "@typescript-eslint/visitor-keys": "4.9.0" + "@typescript-eslint/types": "4.22.0", + "@typescript-eslint/visitor-keys": "4.22.0" } }, "@typescript-eslint/types": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.9.0.tgz", - "integrity": "sha512-luzLKmowfiM/IoJL/rus1K9iZpSJK6GlOS/1ezKplb7MkORt2dDcfi8g9B0bsF6JoRGhqn0D3Va55b+vredFHA==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.22.0.tgz", + "integrity": "sha512-sW/BiXmmyMqDPO2kpOhSy2Py5w6KvRRsKZnV0c4+0nr4GIcedJwXAq+RHNK4lLVEZAJYFltnnk1tJSlbeS9lYA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.9.0.tgz", - "integrity": "sha512-rmDR++PGrIyQzAtt3pPcmKWLr7MA+u/Cmq9b/rON3//t5WofNR4m/Ybft2vOLj0WtUzjn018ekHjTsnIyBsQug==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.0.tgz", + "integrity": "sha512-TkIFeu5JEeSs5ze/4NID+PIcVjgoU3cUQUIZnH3Sb1cEn1lBo7StSV5bwPuJQuoxKXlzAObjYTilOEKRuhR5yg==", "dev": true, "requires": { - "@typescript-eslint/types": "4.9.0", - "@typescript-eslint/visitor-keys": "4.9.0", + "@typescript-eslint/types": "4.22.0", + "@typescript-eslint/visitor-keys": "4.22.0", "debug": "^4.1.1", "globby": "^11.0.1", "is-glob": "^4.0.1", - "lodash": "^4.17.15", "semver": "^7.3.2", "tsutils": "^3.17.1" }, @@ -2114,9 +2086,9 @@ "dev": true }, "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -2125,12 +2097,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.9.0.tgz", - "integrity": "sha512-sV45zfdRqQo1A97pOSx3fsjR+3blmwtdCt8LDrXgCX36v4Vmz4KHrhpV6Fo2cRdXmyumxx11AHw0pNJqCNpDyg==", + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.0.tgz", + "integrity": "sha512-nnMu4F+s4o0sll6cBSsTeVsT4cwxB7zECK3dFxzEjPBii9xLpq4yqqsy/FU5zMfan6G60DKZSCXAa3sHJZrcYw==", "dev": true, "requires": { - "@typescript-eslint/types": "4.9.0", + "@typescript-eslint/types": "4.22.0", "eslint-visitor-keys": "^2.0.0" } }, @@ -2140,6 +2112,12 @@ "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", "dev": true }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -2187,18 +2165,18 @@ "dev": true }, "ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, "requires": { - "type-fest": "^0.11.0" + "type-fest": "^0.21.3" }, "dependencies": { "type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true } } @@ -2239,6 +2217,22 @@ } } }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -2277,15 +2271,15 @@ "dev": true }, "array-includes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.2.tgz", - "integrity": "sha512-w2GspexNQpx+PutG3QpT437/BenZBj0M/MZGn5mzv/MofYqo0xmRHzn4lFsoDlWJ+THYsGJmFlW68WlDFx7VRw==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "get-intrinsic": "^1.0.1", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", "is-string": "^1.0.5" } }, @@ -2389,9 +2383,9 @@ "dev": true }, "axe-core": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.1.tgz", - "integrity": "sha512-5Kgy8Cz6LPC9DJcNb3yjAXTu3XihQgEdnIg50c//zOC/MyLP0Clg+Y8Sh9ZjjnvBrDZU4DgXS9C3T9r4/scGZQ==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.4.tgz", + "integrity": "sha512-Pdgfv6iP0gNx9ejRGa3zE7Xgkj/iclXqLfe7BnatdZz0QnLZ3jrRHUVH8wNSdN68w05Sk3ShGTb3ydktMTooig==", "dev": true }, "axobject-query": { @@ -2508,9 +2502,9 @@ } }, "babel-preset-current-node-syntax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.0.tgz", - "integrity": "sha512-mGkvkpocWJes1CmMKtgGUwCeeq0pOhALyymozzDWYomHTbDLwueDYG6p4TK1YOeYHCzBzYPsWkgTto10JubI1Q==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, "requires": { "@babel/plugin-syntax-async-generators": "^7.8.4", @@ -2538,9 +2532,9 @@ } }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "base": { @@ -2660,16 +2654,16 @@ "dev": true }, "browserslist": { - "version": "4.16.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.0.tgz", - "integrity": "sha512-/j6k8R0p3nxOC6kx5JGAxsnhc9ixaWJfYc+TNTzxg6+ARaESAvQGV7h0uNOB4t+pLQJZWzcrMxXOxjgsCj3dqQ==", + "version": "4.16.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.4.tgz", + "integrity": "sha512-d7rCxYV8I9kj41RH8UKYnvDYCRENUlHRgyXy/Rhr/1BaeLGfiCptEdFE8MIrvGfWbBFNjVYx76SQWvNX1j+/cQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001165", - "colorette": "^1.2.1", - "electron-to-chromium": "^1.3.621", + "caniuse-lite": "^1.0.30001208", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.712", "escalade": "^3.1.1", - "node-releases": "^1.1.67" + "node-releases": "^1.1.71" } }, "bser": { @@ -2705,13 +2699,13 @@ } }, "call-bind": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", - "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "dev": true, "requires": { "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.0" + "get-intrinsic": "^1.0.2" } }, "callsites": { @@ -2727,11 +2721,22 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001170", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001170.tgz", - "integrity": "sha512-Dd4d/+0tsK0UNLrZs3CvNukqalnVTRrxb5mcQm8rHL49t7V5ZaTygwXkrq+FB+dVDf++4ri8eJnFEJAB8332PA==", + "version": "1.0.30001214", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001214.tgz", + "integrity": "sha512-O2/SCpuaU3eASWVaesQirZv1MSjUNOvmugaD8zNSJqw6Vv5SGwoOpA9LJs3pNPfM745nxqPvfZY3MQKY4AKHYg==", "dev": true }, + "canvas": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.7.0.tgz", + "integrity": "sha512-pzCxtkHb+5su5MQjTtepMDlIOtaXo277x0C0u3nMOxtkhTyQ+h2yNKhlROAaDllWgRyePAUitC08sXw26Eb6aw==", + "dev": true, + "requires": { + "nan": "^2.14.0", + "node-pre-gyp": "^0.15.0", + "simple-get": "^3.0.3" + } + }, "capture-exit": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", @@ -2765,15 +2770,15 @@ "dev": true }, "chokidar": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz", - "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", + "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", "dev": true, "optional": true, "requires": { "anymatch": "~3.1.1", "braces": "~3.0.2", - "fsevents": "~2.1.2", + "fsevents": "~2.3.1", "glob-parent": "~5.1.0", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", @@ -2782,9 +2787,9 @@ }, "dependencies": { "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "optional": true, "requires": { @@ -2793,9 +2798,9 @@ } }, "binary-extensions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", - "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true, "optional": true }, @@ -2820,9 +2825,9 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "optional": true, "requires": { @@ -2868,6 +2873,12 @@ } } }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true + }, "ci-info": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", @@ -2914,12 +2925,6 @@ "wrap-ansi": "^6.2.0" }, "dependencies": { - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -2927,15 +2932,24 @@ "dev": true }, "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.0" } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } } } }, @@ -2945,6 +2959,12 @@ "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, "collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", @@ -2977,9 +2997,9 @@ "dev": true }, "colorette": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", - "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", "dev": true }, "combined-stream": { @@ -2997,12 +3017,6 @@ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true }, - "compare-versions": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", - "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", - "dev": true - }, "component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", @@ -3021,6 +3035,12 @@ "integrity": "sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA==", "dev": true }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, "contains-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", @@ -3043,12 +3063,12 @@ "dev": true }, "core-js-compat": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.1.tgz", - "integrity": "sha512-a16TLmy9NVD1rkjUGbwuyWkiDoN0FDpAwrfLONvHFQx0D9k7J9y0srwMT8QP/Z6HE3MIFaVynEeYwZwPX1o5RQ==", + "version": "3.10.2", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.10.2.tgz", + "integrity": "sha512-IGHnpuaM1N++gLSPI1F1wu3WXICPxSyj/Q++clcwsIOnUVp5uKUIPl/+6h0TQ112KU3fMiSxqJuM+OrCyKj5+A==", "dev": true, "requires": { - "browserslist": "^4.15.0", + "browserslist": "^4.16.4", "semver": "7.0.0" }, "dependencies": { @@ -3061,9 +3081,9 @@ } }, "core-js-pure": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.8.0.tgz", - "integrity": "sha512-fRjhg3NeouotRoIV0L1FdchA6CK7ZD+lyINyMoz19SyV+ROpC4noS1xItWHFtwZdlqfMfVPJEyEGdfri2bD1pA==", + "version": "3.10.2", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.10.2.tgz", + "integrity": "sha512-uu18pVHQ21n4mzfuSlCXpucu5VKsck3j2m5fjrBOBqqdgWAxwdCgUuGWj6cDDPN1zLj/qtiqKvBMxWgDeeu49Q==", "dev": true }, "core-util-is": { @@ -3072,39 +3092,6 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, - "cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", - "dev": true, - "requires": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "dependencies": { - "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - } - } - }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3192,6 +3179,21 @@ "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", "dev": true }, + "decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "dev": true, + "requires": { + "mimic-response": "^2.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, "deep-is": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", @@ -3260,10 +3262,22 @@ "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", "dev": true }, - "detect-newline": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", - "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "dev": true + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true }, "diff-sequences": { @@ -3326,9 +3340,9 @@ } }, "electron-to-chromium": { - "version": "1.3.631", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.631.tgz", - "integrity": "sha512-mPEG/52142po0XK1jQkZtbMmp38MZtQ3JDFItYxV65WXyhxDYEQ54tP4rb93m0RbMlZqQ+4zBw2N7UumSgGfbA==", + "version": "1.3.717", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.717.tgz", + "integrity": "sha512-OfzVPIqD1MkJ7fX+yTl2nKyOE4FReeVfMCzzxQS+Kp43hZYwHwThlGP+EGIZRXJsxCM7dqo8Y65NOX/HP12iXQ==", "dev": true }, "emittery": { @@ -3371,23 +3385,27 @@ } }, "es-abstract": { - "version": "1.18.0-next.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz", - "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", + "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", "dev": true, "requires": { + "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-negative-zero": "^2.0.0", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.2", + "is-string": "^1.0.5", + "object-inspect": "^1.9.0", "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.0" } }, "es-to-primitive": { @@ -3414,18 +3432,24 @@ "dev": true }, "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz", + "integrity": "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==", "dev": true, "requires": { "esprima": "^4.0.1", - "estraverse": "^4.2.0", + "estraverse": "^5.2.0", "esutils": "^2.0.2", "optionator": "^0.8.1", "source-map": "~0.6.1" }, "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -3563,9 +3587,9 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -3593,14 +3617,29 @@ "dev": true }, "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" } }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3716,9 +3755,9 @@ }, "dependencies": { "emoji-regex": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.0.tgz", - "integrity": "sha512-DNc3KFPK18bPdElMJnf/Pkv5TXhxFU3YFDEuGLDRtPmV4rkmCjBkCSEp22u6rBHdSN9Vlp/GK7k98prmE1Jgug==", + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true } } @@ -3812,9 +3851,9 @@ "dev": true }, "esquery": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz", - "integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { "estraverse": "^5.1.0" @@ -3858,9 +3897,9 @@ "dev": true }, "exec-sh": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz", - "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", + "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", "dev": true }, "execa": { @@ -4109,9 +4148,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz", - "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", + "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -4141,9 +4180,9 @@ } }, "glob-parent": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", - "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { "is-glob": "^4.0.1" @@ -4156,13 +4195,13 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" } }, "to-regex-range": { @@ -4189,9 +4228,9 @@ "dev": true }, "fastq": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz", - "integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", + "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -4207,9 +4246,9 @@ } }, "file-entry-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.0.tgz", - "integrity": "sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "requires": { "flat-cache": "^3.0.4" @@ -4247,15 +4286,6 @@ "locate-path": "^2.0.0" } }, - "find-versions": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", - "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", - "dev": true, - "requires": { - "semver-regex": "^2.0.0" - } - }, "flat-cache": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", @@ -4264,12 +4294,23 @@ "requires": { "flatted": "^3.1.0", "rimraf": "^3.0.2" + }, + "dependencies": { + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "flatted": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.0.tgz", - "integrity": "sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", + "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", "dev": true }, "for-in": { @@ -4304,6 +4345,15 @@ "map-cache": "^0.2.2" } }, + "fs-minipass": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", + "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "dev": true, + "requires": { + "minipass": "^2.6.0" + } + }, "fs-readdir-recursive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz", @@ -4317,9 +4367,9 @@ "dev": true }, "fsevents": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", - "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "optional": true }, @@ -4335,6 +4385,22 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -4348,9 +4414,9 @@ "dev": true }, "get-intrinsic": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", - "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", "dev": true, "requires": { "function-bind": "^1.1.1", @@ -4432,9 +4498,9 @@ "dev": true }, "globby": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz", - "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==", + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", + "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", "dev": true, "requires": { "array-union": "^2.1.0", @@ -4460,9 +4526,9 @@ } }, "graceful-fs": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", - "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", "dev": true }, "growly": { @@ -4497,6 +4563,12 @@ "function-bind": "^1.1.1" } }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -4504,9 +4576,15 @@ "dev": true }, "has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true }, "has-value": { @@ -4542,9 +4620,9 @@ } }, "hosted-git-info": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", - "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", "dev": true }, "html-encoding-sniffer": { @@ -4580,137 +4658,10 @@ "dev": true }, "husky": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.6.tgz", - "integrity": "sha512-o6UjVI8xtlWRL5395iWq9LKDyp/9TE7XMOTvIpEVzW638UcGxTmV5cfel6fsk/jbZSTlvfGVJf2svFtybcIZag==", - "dev": true, - "requires": { - "chalk": "^4.0.0", - "ci-info": "^2.0.0", - "compare-versions": "^3.6.0", - "cosmiconfig": "^7.0.0", - "find-versions": "^3.2.0", - "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^4.2.0", - "please-upgrade-node": "^3.2.0", - "slash": "^3.0.0", - "which-pm-runs": "^1.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz", + "integrity": "sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ==", + "dev": true }, "iconv-lite": { "version": "0.4.24", @@ -4727,6 +4678,15 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "ignore-walk": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", + "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -4829,44 +4789,23 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "internal-slot": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.2.tgz", - "integrity": "sha512-2cQNfwhAfJIkU4KZPkDI+Gj5yNNnbqi40W9Gge6dfnk4TocEVm00B3bdiL+JINrbGJil2TeHvM4rETGzk/f/0g==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", "dev": true, "requires": { - "es-abstract": "^1.17.0-next.1", + "get-intrinsic": "^1.1.0", "has": "^1.0.3", - "side-channel": "^1.0.2" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", - "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "side-channel": "^1.0.4" } }, - "ip-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", - "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", - "dev": true - }, "is-accessor-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", @@ -4893,6 +4832,12 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "is-bigint": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", + "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==", + "dev": true + }, "is-binary-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", @@ -4903,6 +4848,15 @@ "binary-extensions": "^1.0.0" } }, + "is-boolean-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", + "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", + "dev": true, + "requires": { + "call-bind": "^1.0.0" + } + }, "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", @@ -4910,9 +4864,9 @@ "dev": true }, "is-callable": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", - "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", "dev": true }, "is-ci": { @@ -4979,9 +4933,9 @@ } }, "is-docker": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", - "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, "optional": true }, @@ -4998,10 +4952,13 @@ "dev": true }, "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } }, "is-generator-fn": { "version": "2.1.0", @@ -5019,9 +4976,9 @@ } }, "is-negative-zero": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", - "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", "dev": true }, "is-number": { @@ -5044,6 +5001,12 @@ } } }, + "is-number-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", + "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", + "dev": true + }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -5054,17 +5017,18 @@ } }, "is-potential-custom-element-name": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", - "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, "is-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", - "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", + "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", "dev": true, "requires": { + "call-bind": "^1.0.2", "has-symbols": "^1.0.1" } }, @@ -5476,13 +5440,13 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" } }, "supports-color": { @@ -5699,9 +5663,9 @@ }, "dependencies": { "anymatch": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", - "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { "normalize-path": "^3.0.0", @@ -5733,13 +5697,13 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" } }, "to-regex-range": { @@ -5985,13 +5949,13 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" } }, "slash": { @@ -6142,9 +6106,9 @@ "dev": true }, "parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", @@ -6470,9 +6434,9 @@ "dev": true }, "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -6568,13 +6532,13 @@ "dev": true }, "micromatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", - "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { "braces": "^3.0.1", - "picomatch": "^2.0.5" + "picomatch": "^2.2.3" } }, "supports-color": { @@ -6769,9 +6733,9 @@ "dev": true }, "js-yaml": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", - "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -6785,37 +6749,45 @@ "dev": true }, "jsdom": { - "version": "16.4.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.4.0.tgz", - "integrity": "sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==", + "version": "16.5.3", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.5.3.tgz", + "integrity": "sha512-Qj1H+PEvUsOtdPJ056ewXM4UJPCi4hhLA8wpiz9F2YvsRBhuFsXxtrIFAgGBDynQA9isAMGE91PfUYbdMPXuTA==", "dev": true, "requires": { - "abab": "^2.0.3", - "acorn": "^7.1.1", + "abab": "^2.0.5", + "acorn": "^8.1.0", "acorn-globals": "^6.0.0", "cssom": "^0.4.4", - "cssstyle": "^2.2.0", + "cssstyle": "^2.3.0", "data-urls": "^2.0.0", - "decimal.js": "^10.2.0", + "decimal.js": "^10.2.1", "domexception": "^2.0.1", - "escodegen": "^1.14.1", + "escodegen": "^2.0.0", "html-encoding-sniffer": "^2.0.1", "is-potential-custom-element-name": "^1.0.0", "nwsapi": "^2.2.0", - "parse5": "5.1.1", + "parse5": "6.0.1", "request": "^2.88.2", - "request-promise-native": "^1.0.8", - "saxes": "^5.0.0", + "request-promise-native": "^1.0.9", + "saxes": "^5.0.1", "symbol-tree": "^3.2.4", - "tough-cookie": "^3.0.1", + "tough-cookie": "^4.0.0", "w3c-hr-time": "^1.0.2", "w3c-xmlserializer": "^2.0.0", "webidl-conversions": "^6.1.0", "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0", - "ws": "^7.2.3", + "whatwg-url": "^8.5.0", + "ws": "^7.4.4", "xml-name-validator": "^3.0.0" + }, + "dependencies": { + "acorn": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.1.tgz", + "integrity": "sha512-xYiIVjNuqtKXMxlRMDc6mZUhXehod4a3gbZ1qRlM7icK4EbxUFNLhWoPblCvFtB2Y9CIqHP3CF/rdxLItaQv8g==", + "dev": true + } } }, "jsesc": { @@ -6876,13 +6848,13 @@ } }, "jsx-ast-utils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.1.0.tgz", - "integrity": "sha512-d4/UOjg+mxAWxCiF0c5UTSwyqbchkbqCvK87aBovhnh8GtysTjWmgC63tY0cJx/HzGgm9qnA147jVBdpOiQ2RA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz", + "integrity": "sha512-EIsmt3O3ljsU6sot/J4E1zDRxfBNrhjyf/OKjlydwgEimQuznlM4Wv7U+ueONJMyEn1WRE0K8dhi3dVAXYT24Q==", "dev": true, "requires": { - "array-includes": "^3.1.1", - "object.assign": "^4.1.1" + "array-includes": "^3.1.2", + "object.assign": "^4.1.2" } }, "kind-of": { @@ -6965,15 +6937,27 @@ } }, "lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", "dev": true }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, "loose-envify": { @@ -6992,7 +6976,15 @@ "dev": true, "requires": { "yallist": "^4.0.0" - } + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } }, "make-dir": { "version": "2.1.0", @@ -7062,18 +7054,18 @@ } }, "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", + "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", "dev": true }, "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "version": "2.1.30", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", + "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", "dev": true, "requires": { - "mime-db": "1.44.0" + "mime-db": "1.47.0" } }, "mimic-fn": { @@ -7082,6 +7074,12 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "dev": true + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -7097,6 +7095,25 @@ "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", "dev": true }, + "minipass": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", + "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", + "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", + "dev": true, + "requires": { + "minipass": "^2.9.0" + } + }, "mixin-deep": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", @@ -7118,12 +7135,27 @@ } } }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "dev": true + }, "nanomatch": { "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", @@ -7149,6 +7181,34 @@ "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "needle": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.6.0.tgz", + "integrity": "sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg==", + "dev": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -7168,9 +7228,9 @@ "dev": true }, "node-notifier": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.1.tgz", - "integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", + "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", "dev": true, "optional": true, "requires": { @@ -7183,9 +7243,9 @@ }, "dependencies": { "semver": { - "version": "7.3.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz", - "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "optional": true, "requires": { @@ -7194,12 +7254,40 @@ } } }, + "node-pre-gyp": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.15.0.tgz", + "integrity": "sha512-7QcZa8/fpaU/BKenjcaeFF9hLz2+7S9AqyXFhlH/rilsQ/hPZKK32RtR5EQHJElgu+q5RfbJ34KriI79UWaorA==", + "dev": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.3", + "needle": "^2.5.0", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4.4.2" + } + }, "node-releases": { - "version": "1.1.67", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.67.tgz", - "integrity": "sha512-V5QF9noGFl3EymEwUYzO+3NTDpGfQB4ve6Qfnzf3UNydMhjQRVPR1DZTuvWiLzaFJYw2fmDwAfnRNEVb64hSIg==", + "version": "1.1.71", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", + "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==", "dev": true }, + "nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dev": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -7218,6 +7306,32 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, + "npm-bundled": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", + "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "npm-packlist": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", + "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", + "dev": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -7235,6 +7349,24 @@ } } }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, "nwsapi": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", @@ -7285,9 +7417,9 @@ } }, "object-inspect": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", - "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.2.tgz", + "integrity": "sha512-gz58rdPpadwztRrPjZE9DZLOABUpTGdcANUgOwBFO1C+HZZhePoP83M65WGDmbpwFYJSWqavbl4SgDn4k8RYTA==", "dev": true }, "object-keys": { @@ -7330,14 +7462,14 @@ } }, "object.fromentries": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.3.tgz", - "integrity": "sha512-IDUSMXs6LOSJBWE++L0lzIbSqHl9KDCfff2x/JSEIDtEUavUnyMYC2ZGay/04Zq4UT8lvd4xNhU4/YHKibAOlw==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz", + "integrity": "sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", + "es-abstract": "^1.18.0-next.2", "has": "^1.0.3" } }, @@ -7351,14 +7483,14 @@ } }, "object.values": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.2.tgz", - "integrity": "sha512-MYC0jvJopr8EK6dPBiO8Nb9mvjdypOachO5REGk6MXzujbBrAisKo3HmdEI6kZDL6fC31Mwee/5YbtMebixeag==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", + "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", + "es-abstract": "^1.18.0-next.2", "has": "^1.0.3" } }, @@ -7380,12 +7512,6 @@ "mimic-fn": "^2.1.0" } }, - "opencollective-postinstall": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz", - "integrity": "sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==", - "dev": true - }, "optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -7400,6 +7526,28 @@ "word-wrap": "^1.2.3" } }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, "p-each-series": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", @@ -7455,9 +7603,9 @@ } }, "parse5": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz", - "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, "pascalcase": { @@ -7521,9 +7669,9 @@ "dev": true }, "picomatch": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", - "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", + "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", "dev": true }, "pify": { @@ -7550,15 +7698,6 @@ "find-up": "^2.1.0" } }, - "please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", - "dev": true, - "requires": { - "semver-compare": "^1.0.0" - } - }, "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", @@ -7613,8 +7752,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true, - "optional": true + "dev": true }, "progress": { "version": "2.0.3", @@ -7623,9 +7761,9 @@ "dev": true }, "prompts": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.0.tgz", - "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", + "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==", "dev": true, "requires": { "kleur": "^3.0.3", @@ -7679,10 +7817,28 @@ "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", "dev": true }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, "react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, "read-pkg": { @@ -7711,7 +7867,6 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, - "optional": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -7775,34 +7930,13 @@ } }, "regexp.prototype.flags": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", - "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", + "integrity": "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==", "dev": true, "requires": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - }, - "dependencies": { - "es-abstract": { - "version": "1.17.7", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", - "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.2.2", - "is-regex": "^1.1.1", - "object-inspect": "^1.8.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.1", - "string.prototype.trimend": "^1.0.1", - "string.prototype.trimstart": "^1.0.1" - } - } + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" } }, "regexpp": { @@ -7832,9 +7966,9 @@ "dev": true }, "regjsparser": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", - "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "version": "0.6.9", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz", + "integrity": "sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==", "dev": true, "requires": { "jsesc": "~0.5.0" @@ -7855,9 +7989,9 @@ "dev": true }, "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", + "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", "dev": true }, "repeat-string": { @@ -7950,6 +8084,12 @@ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, "require-main-filename": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", @@ -7957,12 +8097,12 @@ "dev": true }, "resolve": { - "version": "1.19.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", - "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", "dev": true, "requires": { - "is-core-module": "^2.1.0", + "is-core-module": "^2.2.0", "path-parse": "^1.0.6" } }, @@ -8008,9 +8148,9 @@ "dev": true }, "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, "requires": { "glob": "^7.1.3" @@ -8023,10 +8163,13 @@ "dev": true }, "run-parallel": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz", - "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==", - "dev": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } }, "safe-buffer": { "version": "5.1.2", @@ -8066,6 +8209,12 @@ "walker": "~1.0.5" } }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, "saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", @@ -8081,18 +8230,6 @@ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", "dev": true }, - "semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true - }, - "semver-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", - "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", - "dev": true - }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -8145,13 +8282,14 @@ "optional": true }, "side-channel": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.3.tgz", - "integrity": "sha512-A6+ByhlLkksFoUepsGxfj5x1gTSrs+OydsRptUxeNCabQpCFUvcwIczgOigI8vhY/OJCnPnyE9rGiwgvr9cS1g==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", "dev": true, "requires": { - "es-abstract": "^1.18.0-next.0", - "object-inspect": "^1.8.0" + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" } }, "signal-exit": { @@ -8160,6 +8298,23 @@ "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", "dev": true }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true + }, + "simple-get": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz", + "integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==", + "dev": true, + "requires": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", @@ -8206,6 +8361,12 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true } } }, @@ -8354,9 +8515,9 @@ } }, "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", "dev": true }, "spdx-correct": { @@ -8468,58 +8629,69 @@ "dev": true }, "string-length": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz", - "integrity": "sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, "requires": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" + }, + "dependencies": { + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } } }, "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", "dev": true, "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string.prototype.matchall": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.3.tgz", - "integrity": "sha512-OBxYDA2ifZQ2e13cP82dWFMaCV9CGF8GzmN4fljBVw5O5wep0lu4gacm1OL6MjROoUnB8VbkWRThqkV2YFLNxw==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz", + "integrity": "sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", + "es-abstract": "^1.18.0-next.2", "has-symbols": "^1.0.1", - "internal-slot": "^1.0.2", - "regexp.prototype.flags": "^1.3.0", - "side-channel": "^1.0.3" + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.3.1", + "side-channel": "^1.0.4" } }, "string.prototype.trimend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", - "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" } }, "string.prototype.trimstart": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", - "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3" } }, @@ -8528,18 +8700,25 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, - "optional": true, "requires": { "safe-buffer": "~5.1.0" } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + } } }, "strip-bom": { @@ -8561,9 +8740,9 @@ "dev": true }, "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, "supports-color": { @@ -8576,9 +8755,9 @@ } }, "supports-hyperlinks": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", - "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz", + "integrity": "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ==", "dev": true, "requires": { "has-flag": "^4.0.0", @@ -8609,15 +8788,81 @@ "dev": true }, "table": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/table/-/table-6.0.4.tgz", - "integrity": "sha512-sBT4xRLdALd+NFBvwOz8bw4b15htyythha+q+DVZqy2RS08PPC8O2sZFgJYEY7bJvbCFKccs+WIZ/cd+xxTWCw==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "lodash": "^4.17.20", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.3.0.tgz", + "integrity": "sha512-gM9kB7aNIuSagW89Fh+SdL49uhKnVSORxMcV72u/dfptFdqExInNn5M21wgq/Uf5UdJpsboFhNe/0SoNKjaxzg==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "lodash.clonedeep": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.truncate": "^4.4.2", "slice-ansi": "^4.0.0", "string-width": "^4.2.0" + }, + "dependencies": { + "ajv": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.1.0.tgz", + "integrity": "sha512-B/Sk2Ix7A36fs/ZkuGLIR86EdjbgR6fsAcbx9lOP/QBSXujDNbVmIS/U4Itz5k8fPFDeVZl/zQ/gJW4Jrq6XjQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "tar": { + "version": "4.4.13", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", + "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "dev": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" } }, "terminal-link": { @@ -8708,14 +8953,14 @@ } }, "tough-cookie": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz", - "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz", + "integrity": "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==", "dev": true, "requires": { - "ip-regex": "^2.1.0", - "psl": "^1.1.28", - "punycode": "^2.1.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.1.2" } }, "tr46": { @@ -8746,9 +8991,9 @@ "dev": true }, "tsutils": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.17.1.tgz", - "integrity": "sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==", + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, "requires": { "tslib": "^1.8.1" @@ -8799,6 +9044,18 @@ "is-typedarray": "^1.0.0" } }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", @@ -8839,6 +9096,12 @@ "set-value": "^2.0.1" } }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -8887,9 +9150,9 @@ "optional": true }, "uri-js": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", - "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "requires": { "punycode": "^2.1.0" @@ -8911,26 +9174,25 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true, - "optional": true + "dev": true }, "uuid": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", - "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true, "optional": true }, "v8-compile-cache": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", - "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, "v8-to-istanbul": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.0.0.tgz", - "integrity": "sha512-fLL2rFuQpMtm9r8hrAV2apXX/WqHJ6+IC4/eQVdMDGBUgH/YMV4Gv3duk3kjmyg6uiQWBAA9nJwue4iJUOkHeA==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.1.tgz", + "integrity": "sha512-p0BB09E5FRjx0ELN6RgusIPsSPhtgexSRcKETybEs6IGOTXJSZqfwxp7r//55nnu0f1AxltY5VvdVqy2vZf9AA==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.1", @@ -9016,12 +9278,12 @@ "dev": true }, "whatwg-url": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz", - "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.5.0.tgz", + "integrity": "sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg==", "dev": true, "requires": { - "lodash.sortby": "^4.7.0", + "lodash": "^4.7.0", "tr46": "^2.0.2", "webidl-conversions": "^6.1.0" } @@ -9035,17 +9297,33 @@ "isexe": "^2.0.0" } }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, "which-module": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", "dev": true }, - "which-pm-runs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", - "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", - "dev": true + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } }, "word-wrap": { "version": "1.2.3", @@ -9088,12 +9366,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -9101,15 +9373,24 @@ "dev": true }, "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.0" } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } } } }, @@ -9132,9 +9413,9 @@ } }, "ws": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", - "integrity": "sha512-pTsP8UAfhy3sk1lSk/O/s4tjD0CRwvMnzvwr4OKGX7ZvqZtUyx4KIJB5JWbkykPoc55tixMGgTNoh3k4FkNGFQ==", + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", + "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==", "dev": true }, "xml-name-validator": { @@ -9150,21 +9431,15 @@ "dev": true }, "y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true }, "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "yaml": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", - "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, "yargs": { @@ -9186,12 +9461,6 @@ "yargs-parser": "^18.1.2" }, "dependencies": { - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -9248,15 +9517,24 @@ "dev": true }, "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.0" } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } } } }, diff --git a/package.json b/package.json index 73da04e0cf..c4ae69b6fd 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "lint": "eslint ./src/**", "test": "jest", "coverage": "npm run test -- --coverage", - "ci": "npm run lint && npm run coverage" + "ci": "npm run lint && npm run coverage", + "prepare": "husky install" }, "repository": { "type": "git", @@ -37,13 +38,14 @@ "@babel/cli": "7.12.10", "@babel/preset-env": "7.12.11", "@types/jest": "26.0.19", + "canvas": "^2.7.0", "eslint": "7.16.0", "eslint-config-airbnb": "18.2.1", "eslint-plugin-import": "2.22.1", "eslint-plugin-jest": "24.1.3", "eslint-plugin-jsx-a11y": "6.4.1", "eslint-plugin-react": "7.21.5", - "husky": "4.3.6", + "husky": "6.0.0", "jest": "26.6.3" }, "dependencies": {} diff --git a/src/algorithms/image-processing/seam-carving/README.md b/src/algorithms/image-processing/seam-carving/README.md new file mode 100644 index 0000000000..87004f7abe --- /dev/null +++ b/src/algorithms/image-processing/seam-carving/README.md @@ -0,0 +1,509 @@ +# Content-aware image resizing in JavaScript + +![Content-aware image resizing in JavaScript](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/01-cover-02.png) + +> There is an [interactive version of this post](https://trekhleb.dev/blog/2021/content-aware-image-resizing-in-javascript/) available where you can upload and resize your custom images. + +## TL;DR + +There are many great articles written about the *Seam Carving algorithm* already, but I couldn't resist the temptation to explore this elegant, powerful, and *yet simple* algorithm on my own, and to write about my personal experience with it. Another point that drew my attention (as a creator of [javascript-algorithms](https://github.com/trekhleb/javascript-algorithms) repo) was the fact that *Dynamic Programming (DP)* approach might be smoothly applied to solve it. And, if you're like me and still on your "learning algorithms" journey, this algorithmic solution may enrich your personal DP arsenal. + +So, with this article I want to do three things: + +1. Provide you with an interactive **content-aware resizer** so that you could play around with resizing your own images +2. Explain the idea behind the **Seam Carving algorithm** +3. Explain the **dynamic programming approach** to implement the algorithm (we'll be using TypeScript for it) + +### Content-aware image resizing + +*Content-aware image resizing* might be applied when it comes to changing the image proportions (i.e. reducing the width while keeping the height) and when losing some parts of the image is not desirable. Doing the straightforward image scaling in this case would distort the objects in it. To preserve the proportions of the objects while changing the image proportions we may use the [Seam Carving algorithm](https://perso.crans.org/frenoy/matlab2012/seamcarving.pdf) that was introduced by *Shai Avidan* and *Ariel Shamir*. + +The example below shows how the original image width was reduced by 50% using *content-aware resizing* (left image) and *straightforward scaling* (right image). In this particular case, the left image looks more natural since the proportions of the balloons were preserved. + +![Content-aware image resizing](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/01-resizing-options.png) + +The Seam Carving algorithm's idea is to find the *seam* (continuous sequence of pixels) with the lowest contribution to the image content and then *carve* (remove) it. This process repeats over and over again until we get the required image width or height. In the example below you may see that the hot air balloon pixels contribute more to the content of the image than the sky pixels. Thus, the sky pixels are being removed first. + +![JS IMAGE CARVER DEMO](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/10-demo-01.gif) + +Finding the seam with the lowest energy is a computationally expensive task (especially for large images). To make the seam search faster the *dynamic programming* approach might be applied (we will go through the implementation details below). + +### Objects removal + +The importance of each pixel (so-called pixel's energy) is being calculated based on its color (`R`, `G`, `B`, `A`) difference between two neighbor pixels. Now, if we set the pixel energy to some really low level artificially (i.e. by drawing a mask on top of them), the Seam Carving algorithm would perform an **object removal** for us for free. + +![JS IMAGE CARVER OBJECT REMOVAL DEMO](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/10-demo-02.gif) + +### JS IMAGE CARVER demo + +I've created the [JS IMAGE CARVER](https://trekhleb.dev/js-image-carver/) web-app (and also [open-sourced it on GitHub](https://github.com/trekhleb/js-image-carver)) that you may use to play around with resizing of your custom images. + +### More examples + +Here are some more examples of how the algorithm copes with more complex backgrounds. + +Mountains on the background are being shrunk smoothly without visible seams. + +![Resizing demo with more complex backgrounds](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/11-demo-01.png) + +The same goes for the ocean waves. The algorithm preserved the wave structure without distorting the surfers. + +![Resizing demo with more complex backgrounds](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/11-demo-02.png) + +We need to keep in mind that the Seam Carving algorithm is not a silver bullet, and it may fail to resize the images where *most of the pixels are edges* (look important to the algorithm). In this case, it starts distorting even the important parts of the image. In the example below the content-aware image resizing looks pretty similar to a straightforward scaling since for the algorithm all the pixels look important, and it is hard for it to distinguish Van Gogh's face from the background. + +![Example when the algorithm does not work as expected](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/12-demo-01.png) + +## How Seam Carving algorithms works + +Imagine we have a `1000 x 500 px` picture, and we want to change its size to `500 x 500 px` to make it square (let's say the square ratio would better fit the Instagram feed). We might want to set up several **requirements to the resizing process** in this case: + +- *Preserve the important parts of the image* (i.e. if there were 5 trees before the resizing we want to have 5 trees after resizing as well). +- *Preserve the proportions* of the important parts of the image (i.e. circle car wheels should not be squeezed to the ellipse wheels) + +To avoid changing the important parts of the image we may find the **continuous sequence of pixels (the seam)**, that goes from top to bottom and has *the lowest contribution to the content* of the image (avoids important parts) and then remove it. The seam removal will shrink the image by 1 pixel. We will then repeat this step until the image will get the desired width. + +The question is how to define *the importance of the pixel* and its contribution to the content (in the original paper the authors are using the term **energy of the pixel**). One of the ways to do it is to treat all the pixels that form the edges as important ones. In case if a pixel is a part of the edge its color would have a greater difference between the neighbors (left and right pixels) than the pixel that isn't a part of the edge. + +![Pixels color difference](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-pixel-energy-comparison.png) + +Assuming that the color of a pixel is represented by *4* numbers (`R` - red, `G` - green, `B` - blue, `A` - alpha) we may use the following formula to calculate the color difference (the pixel energy): + +![Pixel energy formula](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/20-energy-formula.png) + +Where: + +- `mEnergy` - *Energy* (importance) of the *middle* pixel (`[0..626]` if rounded) +- `lR` - *Red* channel value for the *left* pixel (`[0..255]`) +- `mR` - *Red* channel value for the *middle* pixel (`[0..255]`) +- `rR` - *Red* channel value for the *right* pixel (`[0..255]`) +- `lG` - *Green* channel value for the *left* pixel (`[0..255]`) +- and so on... + +In the formula above we're omitting the alpha (transparency) channel, for now, assuming that there are no transparent pixels in the image. Later we will use the alpha channel for masking and for object removal. + +![Example of pixel energy calculation](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-pixel-energy-calculation-example.png) + +Now, since we know how to find the energy of one pixel, we can calculate, so-called, **energy map** which will contain the energies of each pixel of the image. On each resizing step the energy map should be re-calculated (at least partially, more about it below) and would have the same size as the image. + +For example, on the 1st resizing step we will have a `1000 x 500` image and a `1000 x 500` energy map. On the 2nd resizing step we will remove the seam from the image and re-calculate the energy map based on the new shrunk image. Thus, we will get a `999 x 500` image and a `999 x 500` energy map. + +The higher the energy of the pixel the more likely it is a part of an edge, and it is important for the image content and the less likely that we need to remove it. + +To visualize the energy map we may assign a brighter color to the pixels with the higher energy and darker colors to the pixels with the lower energy. Here is an artificial example of how the random part of the energy map might look like. You may see the bright line which represents the edge and which we want to preserve during the resizing. + +![Energy map sketch](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-energy-map-padding.png) + +Here is a real example of the energy map for the demo image you saw above (with hot air balloons). + +![Energy map example](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/40-energy-map.png) + +You may play around with your custom images and see how the energy map would look like in the [interactive version of the post](https://trekhleb.dev/blog/2021/content-aware-image-resizing-in-javascript/). + +We may use the energy map to find the seams (one after another) with the lowest energy and by doing this to decide which pixels should be ultimately deleted. + +![Searching the seam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/41-seam-search.png) + +Finding the seam with the lowest energy is not a trivial task and requires exploring many possible pixel combinations before making the decision. We will apply the dynamic programming approach to speed it up. + +In the example below, you may see the energy map with the first lowest energy seam that was found for it. + +![Energy map example with seam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/40-energy-map-with-seam.png) + +In the examples above we were reducing the width of the image. A similar approach may be taken to reduce the image height. We need to "rotate" the approach though: + +- start using *top* and *bottom* pixel neighbors (instead of *left* and *right* ones) to calculate the pixel energy +- when searching for a seam we need to move from *left* to *right* (instead of from *up* to *bottom*) + +## Implementation in TypeScript + +> You may find the source code, and the functions mentioned below in the [js-image-carver](https://github.com/trekhleb/js-image-carver) repository. + +To implement the algorithm we will be using TypeScript. If you want a JavaScript version, you may ignore (remove) type definitions and their usages. + +For simplicity reasons let's implement the seam carving algorithm only for the image *width* reduction. + +### Content-aware width resizing (the entry function) + +First, let's define some common types that we're going to use while implementing the algorithm. + +```typescript +// Type that describes the image size (width and height). +type ImageSize = { w: number, h: number }; + +// The coordinate of the pixel. +type Coordinate = { x: number, y: number }; + +// The seam is a sequence of pixels (coordinates). +type Seam = Coordinate[]; + +// Energy map is a 2D array that has the same width and height +// as the image the map is being calculated for. +type EnergyMap = number[][]; + +// Type that describes the image pixel's RGBA color. +type Color = [ + r: number, // Red + g: number, // Green + b: number, // Blue + a: number, // Alpha (transparency) +] | Uint8ClampedArray; +``` + +On the high level the algorithm consists of the following steps: + +1. Calculate the **energy map** for the current version of the image. +2. Find the **seam** with the lowest energy based on the energy map (this is where we will apply Dynamic Programming). +3. **Delete the seam** with the lowest energy seam from the image. +4. **Repeat** until the image width is reduced to the desired value. + +```typescript +type ResizeImageWidthArgs = { + img: ImageData, // Image data we want to resize. + toWidth: number, // Final image width we want the image to shrink to. +}; + +type ResizeImageWidthResult = { + img: ImageData, // Resized image data. + size: ImageSize, // Resized image size (w x h). +}; + +// Performs the content-aware image width resizing using the seam carving method. +export const resizeImageWidth = ( + { img, toWidth }: ResizeImageWidthArgs, +): ResizeImageWidthResult => { + // For performance reasons we want to avoid changing the img data array size. + // Instead we'll just keep the record of the resized image width and height separately. + const size: ImageSize = { w: img.width, h: img.height }; + + // Calculating the number of pixels to remove. + const pxToRemove = img.width - toWidth; + if (pxToRemove < 0) { + throw new Error('Upsizing is not supported for now'); + } + + let energyMap: EnergyMap | null = null; + let seam: Seam | null = null; + + // Removing the lowest energy seams one by one. + for (let i = 0; i < pxToRemove; i += 1) { + // 1. Calculate the energy map for the current version of the image. + energyMap = calculateEnergyMap(img, size); + + // 2. Find the seam with the lowest energy based on the energy map. + seam = findLowEnergySeam(energyMap, size); + + // 3. Delete the seam with the lowest energy seam from the image. + deleteSeam(img, seam, size); + + // Reduce the image width, and continue iterations. + size.w -= 1; + } + + // Returning the resized image and its final size. + // The img is actually a reference to the ImageData, so technically + // the caller of the function already has this pointer. But let's + // still return it for better code readability. + return { img, size }; +}; +``` + +The image that needs to be resized is being passed to the function in [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData) format. You may draw the image on the canvas and then extract the ImageData from the canvas like this: + +```javascript +const ctx = canvas.getContext('2d'); +const imgData = ctx.getImageData(0, 0, imgWidth, imgHeight); +``` + +> The way of uploading and drawing images in JavaScript is out of scope for this article, but you may find the complete source code of how it may be done using React in [js-image-carver](https://github.com/trekhleb/js-image-carver) repo. + +Let's break down each step ony be one and implement the `calculateEnergyMap()`, `findLowEnergySeam()` and `deleteSeam()` functions. + +### Calculating the pixel's energy + +Here we apply the color difference formula described above. For the left and right borders (when there are no left or right neighbors), we ignore the neighbors and don't take them into account during the energy calculation. + +```typescript +// Calculates the energy of a pixel. +const getPixelEnergy = (left: Color | null, middle: Color, right: Color | null): number => { + // Middle pixel is the pixel we're calculating the energy for. + const [mR, mG, mB] = middle; + + // Energy from the left pixel (if it exists). + let lEnergy = 0; + if (left) { + const [lR, lG, lB] = left; + lEnergy = (lR - mR) ** 2 + (lG - mG) ** 2 + (lB - mB) ** 2; + } + + // Energy from the right pixel (if it exists). + let rEnergy = 0; + if (right) { + const [rR, rG, rB] = right; + rEnergy = (rR - mR) ** 2 + (rG - mG) ** 2 + (rB - mB) ** 2; + } + + // Resulting pixel energy. + return Math.sqrt(lEnergy + rEnergy); +}; +``` + +### Calculating the energy map + +The image we're working with has the [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData) format. It means that all the pixels (and their colors) are stored in a flat (*1D*) [Uint8ClampedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray) array. For readability purposes let's introduce the couple of helper functions that will allow us to work with the Uint8ClampedArray array as with a *2D* matrix instead. + +```typescript +// Helper function that returns the color of the pixel. +const getPixel = (img: ImageData, { x, y }: Coordinate): Color => { + // The ImageData data array is a flat 1D array. + // Thus we need to convert x and y coordinates to the linear index. + const i = y * img.width + x; + const cellsPerColor = 4; // RGBA + // For better efficiency, instead of creating a new sub-array we return + // a pointer to the part of the ImageData array. + return img.data.subarray(i * cellsPerColor, i * cellsPerColor + cellsPerColor); +}; + +// Helper function that sets the color of the pixel. +const setPixel = (img: ImageData, { x, y }: Coordinate, color: Color): void => { + // The ImageData data array is a flat 1D array. + // Thus we need to convert x and y coordinates to the linear index. + const i = y * img.width + x; + const cellsPerColor = 4; // RGBA + img.data.set(color, i * cellsPerColor); +}; +``` + +To calculate the energy map we go through each image pixel and call the previously described `getPixelEnergy()` function against it. + +```typescript +// Helper function that creates a matrix (2D array) of specific +// size (w x h) and fills it with specified value. +const matrix = (w: number, h: number, filler: T): T[][] => { + return new Array(h) + .fill(null) + .map(() => { + return new Array(w).fill(filler); + }); +}; + +// Calculates the energy of each pixel of the image. +const calculateEnergyMap = (img: ImageData, { w, h }: ImageSize): EnergyMap => { + // Create an empty energy map where each pixel has infinitely high energy. + // We will update the energy of each pixel. + const energyMap: number[][] = matrix(w, h, Infinity); + for (let y = 0; y < h; y += 1) { + for (let x = 0; x < w; x += 1) { + // Left pixel might not exist if we're on the very left edge of the image. + const left = (x - 1) >= 0 ? getPixel(img, { x: x - 1, y }) : null; + // The color of the middle pixel that we're calculating the energy for. + const middle = getPixel(img, { x, y }); + // Right pixel might not exist if we're on the very right edge of the image. + const right = (x + 1) < w ? getPixel(img, { x: x + 1, y }) : null; + energyMap[y][x] = getPixelEnergy(left, middle, right); + } + } + return energyMap; +}; +``` + +> The energy map is going to be recalculated on every resize iteration. It means that it will be recalculated, let's say, 500 times if we need to shrink the image by 500 pixels which is not optimal. To speed up the energy map calculation on the 2nd, 3rd, and further steps, we may re-calculate the energy only for those pixels that are placed around the seam that is going to be removed. For simplicity reasons this optimization is omitted here, but you may find the example source-code in [js-image-carver](https://github.com/trekhleb/js-image-carver) repo. + +### Finding the seam with the lowest energy (Dynamic Programming approach) + +> I've described some Dynamic Programming basics in [Dynamic Programming vs Divide-and-Conquer](https://trekhleb.dev/blog/2018/dynamic-programming-vs-divide-and-conquer/) article before. There is a DP example based on the minimum edit distance problem. You might want to check it out to get some more context. + +The issue we need to solve now is to find the path (the seam) on the energy map that goes from top to bottom and has the minimum sum of pixel energies. + +#### The naive approach + +The naive approach would be to check all possible paths one after another. + +![The naive approach](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/50-naive-approach.png) + +Going from top to bottom, for each pixel, we have 3 options (↙︎ go down-left, ↓ go down, ↘︎ go down-right). This gives us the time complexity of `O(w * 3^h)` or simply `O(3^h)`, where `w` and `h` are the width and the height of the image. This approach looks slow. + +#### The greedy approach + +We may also try to choose the next pixel as a pixel with the lowest energy, hoping that the resulting seam energy will be the smallest one. + +![The greedy approach](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/51-greedy-approach.png) + +This approach gives not the worst solution, but it cannot guarantee that we will find the best available solution. On the image above you may see how the greedy approach chose `5` instead of `10` at first and missed the chain of optimal pixels. + +The good part about this approach is that it is fast, and it has a time complexity of `O(w + h)`, where `w` and `h` are the width and the height of the image. In this case, the cost of the speed is the low quality of resizing. We need to find a minimum value in the first row (traversing `w` cells) and then we explore only 3 neighbor pixels for each row (traversing `h` rows). + +#### The dynamic programming approach + +You might have noticed that in the naive approach we summed up the same pixel energies over and over again while calculating the resulting seams' energy. + +![Repeated problems](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/52-dp-repeated-problems.png) + +In the example above you see that for the first two seams we are re-using the energy of the shorter seam (which has the energy of `235`). Instead of doing just one operation `235 + 70` to calculate the energy of the 2nd seam we're doing four operations `(5 + 0 + 80 + 150) + 70`. + +> This fact that we're re-using the energy of the previous seam to calculate the current seam's energy might be applied recursively to all the shorter seams up to the very top 1st row seam. When we have such overlapping sub-problems, [it is a sign](https://trekhleb.dev/blog/2018/dynamic-programming-vs-divide-and-conquer/) that the general problem *might* be optimized by dynamic programming approach. + +So, we may **save the energy of the current seam** at the particular pixel in an additional `seamsEnergies` table to make it re-usable for calculating the next seams faster (the `seamsEnergies` table will have the same size as the energy map and the image itself). + +Let's also keep in mind that for one particular pixel on the image (i.e. the bottom left one) we may have *several* values of the previous seams energies. + +![What seam to choose](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/53-dp-what-to-choose.png) + +Since we're looking for a seam with the lowest resulting energy it would make sense to pick the previous seam with the lowest resulting energy as well. + +![Seams energies example](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/56-dp-seams-energies-example.png) + +In general, we have three possible previous seems to choose from: + +![Three options to choose from](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/55-dp-three-options.png) + +You may think about it this way: + +- The cell `[1][x]`: contains the lowest possible energy of the seam that starts somewhere on the row `[0][?]` and ends up at cell `[1][x]` +- **The current cell** `[2][3]`: contains the lowest possible energy of the seam that starts somewhere on the row `[0][?]` and ends up at cell `[2][3]`. To calculate it we need to sum up the energy of the current pixel `[2][3]` (from the energy map) with the `min(seam_energy_1_2, seam_energy_1_3, seam_energy_1_4)` + +If we fill the `seamsEnergies` table completely, then the minimum number in the lowest row would be the lowest possible seam energy. + +Let's try to fill several cells of this table to see how it works. + +![Seams energies map traversal](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/57-dp-seams-energies-traversal.png) + +After filling out the `seamsEnergies` table we may see that the lowest energy pixel has an energy of `50`. For convenience, during the `seamsEnergies` generation for each pixel, we may save not only the energy of the seam but also the coordinates of the previous lowest energy seam. This will give us the possibility to reconstruct the seam path from the bottom to the top easily. + +The time complexity of DP approach would be `O(w * h)`, where `w` and `h` are the width and the height of the image. We need to calculate energies for *every* pixel of the image. + +Here is an example of how this logic might be implemented: + +```typescript +// The metadata for the pixels in the seam. +type SeamPixelMeta = { + energy: number, // The energy of the pixel. + coordinate: Coordinate, // The coordinate of the pixel. + previous: Coordinate | null, // The previous pixel in a seam. +}; + +// Finds the seam (the sequence of pixels from top to bottom) that has the +// lowest resulting energy using the Dynamic Programming approach. +const findLowEnergySeam = (energyMap: EnergyMap, { w, h }: ImageSize): Seam => { + // The 2D array of the size of w and h, where each pixel contains the + // seam metadata (pixel energy, pixel coordinate and previous pixel from + // the lowest energy seam at this point). + const seamsEnergies: (SeamPixelMeta | null)[][] = matrix(w, h, null); + + // Populate the first row of the map by just copying the energies + // from the energy map. + for (let x = 0; x < w; x += 1) { + const y = 0; + seamsEnergies[y][x] = { + energy: energyMap[y][x], + coordinate: { x, y }, + previous: null, + }; + } + + // Populate the rest of the rows. + for (let y = 1; y < h; y += 1) { + for (let x = 0; x < w; x += 1) { + // Find the top adjacent cell with minimum energy. + // This cell would be the tail of a seam with lowest energy at this point. + // It doesn't mean that this seam (path) has lowest energy globally. + // Instead, it means that we found a path with the lowest energy that may lead + // us to the current pixel with the coordinates x and y. + let minPrevEnergy = Infinity; + let minPrevX: number = x; + for (let i = (x - 1); i <= (x + 1); i += 1) { + if (i >= 0 && i < w && seamsEnergies[y - 1][i].energy < minPrevEnergy) { + minPrevEnergy = seamsEnergies[y - 1][i].energy; + minPrevX = i; + } + } + + // Update the current cell. + seamsEnergies[y][x] = { + energy: minPrevEnergy + energyMap[y][x], + coordinate: { x, y }, + previous: { x: minPrevX, y: y - 1 }, + }; + } + } + + // Find where the minimum energy seam ends. + // We need to find the tail of the lowest energy seam to start + // traversing it from its tail to its head (from the bottom to the top). + let lastMinCoordinate: Coordinate | null = null; + let minSeamEnergy = Infinity; + for (let x = 0; x < w; x += 1) { + const y = h - 1; + if (seamsEnergies[y][x].energy < minSeamEnergy) { + minSeamEnergy = seamsEnergies[y][x].energy; + lastMinCoordinate = { x, y }; + } + } + + // Find the lowest energy energy seam. + // Once we know where the tail is we may traverse and assemble the lowest + // energy seam based on the "previous" value of the seam pixel metadata. + const seam: Seam = []; + if (!lastMinCoordinate) { + return seam; + } + + const { x: lastMinX, y: lastMinY } = lastMinCoordinate; + + // Adding new pixel to the seam path one by one until we reach the top. + let currentSeam = seamsEnergies[lastMinY][lastMinX]; + while (currentSeam) { + seam.push(currentSeam.coordinate); + const prevMinCoordinates = currentSeam.previous; + if (!prevMinCoordinates) { + currentSeam = null; + } else { + const { x: prevMinX, y: prevMinY } = prevMinCoordinates; + currentSeam = seamsEnergies[prevMinY][prevMinX]; + } + } + + return seam; +}; +``` + +### Removing the seam with the lowest energy + +Once we found the lowest energy seam, we need to remove (to carve) the pixels that form it from the image. The removal is happening by shifting the pixels to the right of the seam by `1px` to the left. For performance reasons, we don't actually delete the last columns. Instead, the rendering component will just ignore the part of the image that lays beyond the resized image width. + +![Deleting the seam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/60-deleting-example.png) + +```typescript +// Deletes the seam from the image data. +// We delete the pixel in each row and then shift the rest of the row pixels to the left. +const deleteSeam = (img: ImageData, seam: Seam, { w }: ImageSize): void => { + seam.forEach(({ x: seamX, y: seamY }: Coordinate) => { + for (let x = seamX; x < (w - 1); x += 1) { + const nextPixel = getPixel(img, { x: x + 1, y: seamY }); + setPixel(img, { x, y: seamY }, nextPixel); + } + }); +}; +``` + +## Objects removal + +The Seam Carving algorithm tries to remove the seams which consist of low energy pixels first. We could leverage this fact and by assigning low energy to some pixels manually (i.e. by drawing on the image and masking out some areas of it) we could make the Seam Carving algorithm to do *objects removal* for us for free. + +Currently, in `getPixelEnergy()` function we were using only the `R`, `G`, `B` color channels to calculate the pixel's energy. But there is also the `A` (alpha, transparency) parameter of the color that we didn't use yet. We may use the transparency channel to tell the algorithm that transparent pixels are the pixels we want to remove. You may check the [source-code of the energy function](https://github.com/trekhleb/js-image-carver/blob/main/src/utils/contentAwareResizer.ts#L54) that takes transparency into account. + +Here is how the algorithm works for object removal. + +![JS IMAGE CARVER OBJECT REMOVAL DEMO](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/10-demo-02.gif) + +## Issues and what's next + +The [JS IMAGE CARVER](https://github.com/trekhleb/js-image-carver) web app is far from being a production ready resizer of course. Its main purpose was to experiment with the Seam Carving algorithm interactively. So the plan for the future is to continue experimentation. + +The [original paper](https://perso.crans.org/frenoy/matlab2012/seamcarving.pdf) describes how the Seam Carving algorithm might be used not only for the downscaling but also for the **upscaling of the images**. The upscaling, in turn, might be used to **upscale the image back to its original width after the objects' removal**. + +Another interesting area of experimentation might be to make the algorithm work in a **real-time**. + +> Those are the plans for the future, but for now, I hope that the example with image downsizing was interesting and useful for you. I also hope that you've got the idea of using dynamic programming to implement it. +> +> So, good luck with your own experiments! diff --git a/src/algorithms/image-processing/seam-carving/README.ru-RU.md b/src/algorithms/image-processing/seam-carving/README.ru-RU.md new file mode 100644 index 0000000000..444ce6df61 --- /dev/null +++ b/src/algorithms/image-processing/seam-carving/README.ru-RU.md @@ -0,0 +1,509 @@ +# Изменение размеров изображения с учетом его содержимого в JavaScript + +![Content-aware image resizing in JavaScript](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/01-cover-02.png) + +> Доступна [английская интерактивная версия этой статьи](https://trekhleb.dev/blog/2021/content-aware-image-resizing-in-javascript/) в которой вы можете загрузить свои собственные изображения и посмотреть, как алгоритм "справляется" с ними. + +## TL;DR + +Написано много замечательных статей об алгоритме *Seam Carving* ("Вырезание швов"), но я не смог устоять перед соблазном самостоятельно исследовать этот элегантный, мощный и в то же время простой алгоритм и написать о своем личном опыте работы с ним. Мое внимание также привлек тот факт, что для его имплементации мы можем применить *динамическое программирование (DP)*. И, если вы, как и я, все еще находитесь на пути изучения алгоритмов, то это решение может обогатить ваш личный арсенал DP. + +Итак, в этой статье я хочу сделать три вещи: + +1. Предоставить вам возможность "поиграться" с алгоритмом самостоятельно при помощи **интерактивного ресайзера**. +2. Объяснить **идею алгоритма Seam Carving**. +3. Объяснить как можно **применить динамическое программирование** для имплементации алгоритма (мы будем писать на TypeScript). + +### Изменение размеров изображений с учетом их содержимого + +*Изменение размера изображения с учетом содержимого* (content-aware image resizing) может быть применено, когда дело доходит до изменения пропорций изображения (например, уменьшения ширины при сохранении высоты), а также когда потеря некоторых частей изображения нежелательна. Простое масштабирование изображения в этом случае исказит находящиеся в нем объекты. Для сохранения пропорций объектов при изменении пропорций изображения можно использовать [алгоритм Seam Carving](https://perso.crans.org/frenoy/matlab2012/seamcarving.pdf), который был описан *Shai Avidan* и *Ariel Shamir*. + +В приведенном ниже примере показано, как ширина исходного изображения была уменьшена на 50% *с учетом содержимого изображения* (слева) и *без учета содержимого изображения* (справа, простой скейлинг). В данном случае левое изображение выглядит более естественным, так как пропорции воздушных шаров в нем были сохранены. + +![Content-aware image resizing](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/01-resizing-options.png) + +Идея алгоритма Seam Carving заключается в том, чтобы найти *шов* (seam, непрерывную последовательность пикселей) с наименьшим влиянием на содержание изображения, а затем его *вырезать* (carve). Этот процесс повторяется снова и снова, пока мы не получим требуемую ширину или высоту изображения. В примере ниже интуитивно видно, что пиксели воздушных шаров вносят больший "вклад" в содержание и смысл изображения, чем пиксели неба. Таким образом, сначала удаляются пиксели неба. + +![JS IMAGE CARVER DEMO](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/10-demo-01.gif) + +Поиск шва с наименьшей энергией (с наименьшим вкладом в содержимое изображения) является вычислительно дорогостоящей операцией (особенно для больших изображений). Для ускорения поиска шва может быть применено *динамическое программирование* (мы рассмотрим детали реализации ниже). + +### Удаление объектов + +Важность каждого пикселя (так называемая энергия пикселя) вычисляется исходя из его цветовой разницы (`R`, `G`, `B`, `A`) между двумя соседними пикселями. Если же мы вручную зададим некоторым пикселям низкий уровень энергии (например нарисовав маску поверх них), то алгоритм Seam Carving выполнит для нас **удаление помеченного объекта**, как говорится, "забесплатно". + +![JS IMAGE CARVER OBJECT REMOVAL DEMO](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/10-demo-02.gif) + +### Интерактивный ресзайзер + +Для этой статьи я создал приложение [JS IMAGE CARVER](https://trekhleb.dev/js-image-carver/) (доступен также и [исходный код на GitHub](https://github.com/trekhleb/js-image-carver)), которым вы можете воспользоваться для ресайза своих изображений и увидеть в реальном времени, как работает алгоритм. + +### Другие примеры ресайза + +Вот еще несколько примеров того, как алгоритм справляется с более сложным фоном. + +Горы на заднем плане плавно сжимаются, без видимых швов. + +![Resizing demo with more complex backgrounds](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/11-demo-01.png) + +То же самое и с океанскими волнами. Алгоритм сохранил волновую структуру, не искажая серферов. + +![Resizing demo with more complex backgrounds](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/11-demo-02.png) + +Нужно помнить, что алгоритм Seam Carving не является "волшебной таблеткой", и может не сохранить пропорции важных частей изображения в том случае, когда *большая часть пикселей выглядят как края, ребра или границы* (почти все пиксели выглядят одинаково важными с точки зрения алгоритма). В приведенном ниже примере изменение размера изображения с учетом содержимого похоже на простое масштабирование, т.к. для алгоритма все пиксели выглядят важными, и ему трудно отличить лицо Ван Гога от фона. + +![Example when the algorithm does not work as expected](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/12-demo-01.png) + +## Как работает алгоритм Seam Carving + +Представим, что у нас есть картинка размером `1000 x 500 px`, и мы хотим уменьшить ее до `500 x 500 px` (допустим, квадратное изображение больше подходит для Instagram). В этом случае мы, возможно, захотим задать несколько **требований к процессу изменения размера**: + +- *Важные части изображения должны быть сохранены* (если до ресайза на фото было 5 деревьев, то и после ресайза мы хотим увидеть все те же 5 деревьев). +- *Пропорции важных частей изображения должны быть сохранены* (круглые колеса автомобиля не должны стать овальными после ресайза). + +Чтобы избежать изменения важных частей изображения можно найти **непрерывную последовательность пикселей (шов)**, которая будет идти от верхней границы к нижней и иметь *наименьший вклад в содержимое* изображения (шов, который не проходит через важные части изображения), а затем удалить его. Удаление шва сожмет изображение на один пиксель. Далее надо повторять этот шаг до тех пор, пока изображение не станет нужной ширины. + +Вопрос в том, как определить *важность пикселя* и его вклад в содержание изображения (в оригинальной статье авторы используют термин **энергия пикселя**). Один из способов это сделать — рассматривать все пиксели, образующие края (границы, ребра), как важные. В случае, если пиксель является частью ребра, его цвет будет отличаться от соседей (левого и правого пикселей). + +![Pixels color difference](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-pixel-energy-comparison.png) + +Предполагая, что цвет пикселя представлен *4-мя* числами (`R` - красный, `G` - зеленый, `B` - синий, `A` - альфа, прозрачность), мы можем использовать следующую формулу для вычисления разницы в цвете (энергии пикселя): + +![Pixel energy formula](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/20-energy-formula.png) + +Где: + +- `mEnergy` - *Энергия* (важность) *среднего* пикселя (`[0..626]` если округлить) +- `lR` - *Красный* цветовой канал *левого* пикселя (`[0..255]`) +- `mR` - *Красный* цветовой канал *среднего* пикселя (`[0..255]`) +- `rR` - *Красный* цветовой канал *правого* пикселя (`[0..255]`) +- `lG` - *Зеленый* цветовой канал *левого* пикселя (`[0..255]`) +- и так далее... + +В приведенной выше формуле мы пока не используем альфа-канал (прозрачность), предполагая, что изображение не содержит прозрачные пиксели. Позже мы будем использовать альфа-канал для маскировки и удаления объектов. + +![Example of pixel energy calculation](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-pixel-energy-calculation-example.png) + +Поскольку мы знаем, как найти энергию одного пикселя, мы можем вычислить так называемую **энергетическую карту**, которая будет содержать энергии каждого пикселя изображения. На каждом шаге изменения размера изображения карту энергий необходимо пересчитывать (по крайней мере частично, подробнее об этом ниже), и она будет иметь тот же размер, что и изображение. + +Например, на 1-м шаге у нас будет изображение размером `1000 x 500` и энергетическая карта размером `1000 x 500`. На 2-м шаге изменения размера мы удалим шов с изображения и пересчитаем карту энергий на основе нового уменьшенного изображения. Таким образом, мы получим изображение размером `999 x 500` и карту энергий размером `999 x 500`. + +Чем выше энергия пикселя, тем больше вероятность того, что он является частью ребра, важен для содержимого изображения и тем меньше вероятность того, что нам потребуется его удалить. + +Для визуализации карты энергий мы можем присвоить более яркий цвет пикселям с большей энергией и более темные цвета пикселям с меньшей энергией. Вот как может выглядеть часть карты энергий. Вы можете увидеть светлую линию, которая представляет край и которую мы хотим сохранить при изменении размера. + +![Energy map sketch](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/30-energy-map-padding.png) + +Вот реальный пример энергетической карты для изображения, которое вы видели выше (с воздушными шарами). + +![Energy map example](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/40-energy-map.png) + +Вы можете загрузить свое изображение и посмотреть, как будет выглядеть энергетическая карта в [интерактивной версии статьи](https://trekhleb.dev/blog/2021/content-aware-image-resizing-in-javascript/). + +Мы можем использовать энергетическую карту, чтобы найти швы (один за другим) с наименьшей энергией и тем самым решить, какие пиксели в конечном итоге должны быть удалены. + +![Searching the seam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/41-seam-search.png) + +Поиск шва с наименьшими затратами энергии не является тривиальной задачей и требует перебора множества возможных комбинаций пикселей. Мы применим динамическое программирование для оптимизации поиска шва. + +В примере ниже вы можете увидеть карту энергий с первым найденным для нее швом с наименьшей энергией. + +![Energy map example with seam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/40-energy-map-with-seam.png) + +В приведенных выше примерах мы уменьшали ширину изображения. Аналогичный подход может быть использован для уменьшения высоты изображения. Для этого нам нужно: + +- начать использовать соседей *сверху* и *снизу*, а не *слева* и *справа*, для вычисления энергии пикселя +- при поиске шва нам нужно двигаться *слева* *направо*, а не *сверху* *вниз*. + +## Реализация алгоритма на TypeScript + +> Исходный код и функции, упомянутые ниже, можно найти в репозитории [js-image-carver](https://github.com/trekhleb/js-image-carver). + +Для реализации алгоритма мы будем использовать TypeScript. Если вам нужна версия на JavaScript, вы можете игнорировать (удалить) определения типов и их использование. + +Для простоты примеров мы напишем код только для уменьшения *ширины* изображения. + +### Уменьшение ширины с учетом содержимого изображения (исходная функция) + +Для начала определим некоторые общие типы, которые мы будем использовать при реализации алгоритма. + +```typescript +// Type that describes the image size (width and height). +type ImageSize = { w: number, h: number }; + +// The coordinate of the pixel. +type Coordinate = { x: number, y: number }; + +// The seam is a sequence of pixels (coordinates). +type Seam = Coordinate[]; + +// Energy map is a 2D array that has the same width and height +// as the image the map is being calculated for. +type EnergyMap = number[][]; + +// Type that describes the image pixel's RGBA color. +type Color = [ + r: number, // Red + g: number, // Green + b: number, // Blue + a: number, // Alpha (transparency) +] | Uint8ClampedArray; +``` + +Для имплементации алгоритма нам необходимо выполнить следующие шаги: + +1. Рассчитать **карту энергии** для текущей версии изображения. +2. Найти **шов** с наименьшей энергией на основе карты энергий (здесь мы применим динамическое программирование). +3. **Удалить шов** с наименьшей энергией из изображения. +4. **Повторять** до тех пор, пока ширина изображения не будет уменьшена до нужного значения. + +```typescript +type ResizeImageWidthArgs = { + img: ImageData, // Image data we want to resize. + toWidth: number, // Final image width we want the image to shrink to. +}; + +type ResizeImageWidthResult = { + img: ImageData, // Resized image data. + size: ImageSize, // Resized image size (w x h). +}; + +// Performs the content-aware image width resizing using the seam carving method. +export const resizeImageWidth = ( + { img, toWidth }: ResizeImageWidthArgs, +): ResizeImageWidthResult => { + // For performance reasons we want to avoid changing the img data array size. + // Instead we'll just keep the record of the resized image width and height separately. + const size: ImageSize = { w: img.width, h: img.height }; + + // Calculating the number of pixels to remove. + const pxToRemove = img.width - toWidth; + if (pxToRemove < 0) { + throw new Error('Upsizing is not supported for now'); + } + + let energyMap: EnergyMap | null = null; + let seam: Seam | null = null; + + // Removing the lowest energy seams one by one. + for (let i = 0; i < pxToRemove; i += 1) { + // 1. Calculate the energy map for the current version of the image. + energyMap = calculateEnergyMap(img, size); + + // 2. Find the seam with the lowest energy based on the energy map. + seam = findLowEnergySeam(energyMap, size); + + // 3. Delete the seam with the lowest energy seam from the image. + deleteSeam(img, seam, size); + + // Reduce the image width, and continue iterations. + size.w -= 1; + } + + // Returning the resized image and its final size. + // The img is actually a reference to the ImageData, so technically + // the caller of the function already has this pointer. But let's + // still return it for better code readability. + return { img, size }; +}; +``` + +Изображение, которому необходимо изменить размер, передается в функцию в формате [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData). Вы можете отобразить изображение на canvas-е, а затем извлечь ImageData из того же canvas-а следующим образом: + +```javascript +const ctx = canvas.getContext('2d'); +const imgData = ctx.getImageData(0, 0, imgWidth, imgHeight); +``` + +> Загрузка и отрисовка изображений в JavaScript выходит за рамки данной статьи, но вы можете найти полный исходный код того, как это можно сделать с помощью React в репозитории [js-image-carver](https://github.com/trekhleb/js-image-carver). + +Теперь, пошагово реализуем функции `calculateEnergyMap()`, `findLowEnergySeam()` и `deleteSeam()`. + +### Расчет энергии пикселя + +Для расчета воспользуемся формулой разницы цветов, описанной выше. Для левой и правой краев изображения (когда нет левого или правого соседей) мы игнорируем соседей и не учитываем их при расчете энергии. + +```typescript +// Calculates the energy of a pixel. +const getPixelEnergy = (left: Color | null, middle: Color, right: Color | null): number => { + // Middle pixel is the pixel we're calculating the energy for. + const [mR, mG, mB] = middle; + + // Energy from the left pixel (if it exists). + let lEnergy = 0; + if (left) { + const [lR, lG, lB] = left; + lEnergy = (lR - mR) ** 2 + (lG - mG) ** 2 + (lB - mB) ** 2; + } + + // Energy from the right pixel (if it exists). + let rEnergy = 0; + if (right) { + const [rR, rG, rB] = right; + rEnergy = (rR - mR) ** 2 + (rG - mG) ** 2 + (rB - mB) ** 2; + } + + // Resulting pixel energy. + return Math.sqrt(lEnergy + rEnergy); +}; +``` + +### Расчет энергетической карты + +Изображение, с которым мы работаем, имеет формат [ImageData](https://developer.mozilla.org/en-US/docs/Web/API/ImageData). Это означает, что все пиксели (и их цвета) хранятся в одномерном массиве [Uint8ClampedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray). Для удобства чтения введем пару вспомогательных функций, которые позволят работать с массивом Uint8ClampedArray как с *2D* матрицей. + +```typescript +// Helper function that returns the color of the pixel. +const getPixel = (img: ImageData, { x, y }: Coordinate): Color => { + // The ImageData data array is a flat 1D array. + // Thus we need to convert x and y coordinates to the linear index. + const i = y * img.width + x; + const cellsPerColor = 4; // RGBA + // For better efficiency, instead of creating a new sub-array we return + // a pointer to the part of the ImageData array. + return img.data.subarray(i * cellsPerColor, i * cellsPerColor + cellsPerColor); +}; + +// Helper function that sets the color of the pixel. +const setPixel = (img: ImageData, { x, y }: Coordinate, color: Color): void => { + // The ImageData data array is a flat 1D array. + // Thus we need to convert x and y coordinates to the linear index. + const i = y * img.width + x; + const cellsPerColor = 4; // RGBA + img.data.set(color, i * cellsPerColor); +}; +``` + +Для вычисления карты энергии мы проходим через каждый пиксель изображения и вызываем для него описанную ранее функцию `getPixelEnergy()`. + +```typescript +// Helper function that creates a matrix (2D array) of specific +// size (w x h) and fills it with specified value. +const matrix = (w: number, h: number, filler: T): T[][] => { + return new Array(h) + .fill(null) + .map(() => { + return new Array(w).fill(filler); + }); +}; + +// Calculates the energy of each pixel of the image. +const calculateEnergyMap = (img: ImageData, { w, h }: ImageSize): EnergyMap => { + // Create an empty energy map where each pixel has infinitely high energy. + // We will update the energy of each pixel. + const energyMap: number[][] = matrix(w, h, Infinity); + for (let y = 0; y < h; y += 1) { + for (let x = 0; x < w; x += 1) { + // Left pixel might not exist if we're on the very left edge of the image. + const left = (x - 1) >= 0 ? getPixel(img, { x: x - 1, y }) : null; + // The color of the middle pixel that we're calculating the energy for. + const middle = getPixel(img, { x, y }); + // Right pixel might not exist if we're on the very right edge of the image. + const right = (x + 1) < w ? getPixel(img, { x: x + 1, y }) : null; + energyMap[y][x] = getPixelEnergy(left, middle, right); + } + } + return energyMap; +}; +``` + +> Карта энергии будет пересчитываться при каждой итерации изменения размера. Это значит, что она будет пересчитываться, скажем, 500 раз, если нам нужно будет уменьшить изображение на 500 пикселей, что выглядит неоптимально. Чтобы ускорить вычисление карты энергии на 2-м, 3-м и последующих этапах, мы можем пересчитать энергию только для тех пикселей, которые расположены вокруг шва, который будет удален. Для простоты эта оптимизация здесь пропущена, но пример с исходным кодом можно найти в репозитории [js-image-carver](https://github.com/trekhleb/js-image-carver). + +### Нахождение шва с минимальной энергией (применяем динамическое программирование) + +> В статье [Dynamic Programming vs Divide-and-Conquer](https://trekhleb.dev/blog/2018/dynamic-programming-vs-divide-and-conquer/) я описывал некоторые аспекты динамического программирования на примере нахождения "расстояния Левенштейна" (преобразование одной строки в другую). Возможно она будет полезна для ознакомления. + +Проблема, которую нам необходимо решить заключается в нахождении пути (шва) на энергетической карте, который идет от верхней границы изображения к нижней и имеет минимальную энергию (сумма энергий пикселей, составляющих шов должна быть минимальной). + +#### "Наивный" подход (naive) + +Прямолинейный ("наивный") подход — перебрать все возможные пути один за другим. + +![The naive approach](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/50-naive-approach.png) + +Двигаясь сверху вниз, для каждого пикселя у нас есть 3 варианта (↙︎ идти вниз-влево, ↓ вниз, ↘︎ идти вниз-вправо). Это дает нам временную сложность `O (w * 3 ^ h)` или просто `O (3 ^ h)`, где `w` и` h` - ширина и высота изображения. Такой подход выглядит неоптимальным. + +#### "Жадный" подход (greedy) + +Жадный подход — выбирать следующий пиксель как пиксель с наименьшей энергией, надеясь, что результирующая энергия шва будет наименьшей. + +![The greedy approach](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/51-greedy-approach.png) + +Жадный подход приведет нас к не самому худшему решению, но он не сможет гарантировать, что мы найдем наилучшее доступное решение. На картинке выше видно, как мы выбрали `5` вместо `10` и пропустили цепочку оптимальных пикселей. + +Плюс этого подхода в том, что он быстрый и имеет временную сложность `O(w + h)`, где `w` и `h` - это ширина и высота изображения. В этом случае плата за скорость — низкое качество ресайза (много искажений). Временная сложность обусловлена тем, что нужно найти минимальное значение в первом ряду (обход `w` ячеек), а затем исследовать только 3 соседних пикселя для каждого ряда (обход `h` рядов). + +#### Используем динамическое программирование + +Вы, наверное, заметили, что в наивном подходе мы снова и снова суммировали одни и те же энергии пикселей, вычисляя энергию образовавшихся швов. + +![Repeated problems](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/52-dp-repeated-problems.png) + +В примере выше видно, что для первых двух швов мы повторно используем энергию более короткого шва (который имеет энергию `235`). Вместо одной операции `235 + 70` для вычисления энергии 2-го шва мы делаем четыре операции `(5 + 0 + 80 + 150) + 70`. + +> Тот факт, что мы повторно используем энергию предыдущего шва для вычисления энергии текущего шва, может быть применен рекурсивно ко всем более коротким швам до самого верхнего 1-го ряда. Когда у нас есть такие перекрывающиеся под-проблемы, [это признак](https://trekhleb.dev/blog/2018/dynamic-programming-vs-divide-and-conquer/), что общая задача *может* быть оптимизирована с использованием динамического программирования. + +Таким образом, мы можем **сохранить энергию текущего шва** для конкретного пикселя в дополнительной таблице `samsEnergies`, чтобы повторно использовать ее при расчете энергии следующих швов (таблица `samsEnergies` будет иметь тот же размер, что и энергетическая карта и само изображение). + +Обратите также внимание, что для большинства пикселей в изображении (например, для левого нижнего) мы можем иметь *несколько* значений энергий предыдущих швов. + +![What seam to choose](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/53-dp-what-to-choose.png) + +Так как мы ищем шов с наименьшей результирующей энергией, имеет смысл выбирать и предыдущий шов с наименьшей результирующей энергией. + +![Seams energies example](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/56-dp-seams-energies-example.png) + +Как правило, у нас есть три возможных предыдущих шва, которые текущий пиксель продолжает: + +![Three options to choose from](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/55-dp-three-options.png) + +Можем посмотреть на это с такой стороны: + +- Ячейка `[1][x]`: содержит наименьшую возможную энергию шва, который начинается где-то в ряду `[0][?] ` и заканчивается в ячейке `[1][x]`. +- **Текущая ячейка** `[2][3]`: содержит наименьшую возможную энергию шва, который начинается где-то в ряду `[0][?] ` и заканчивается в ячейке `[2][3]`. Для вычисления нужно суммировать энергию текущего пикселя `[2][3]` (из энергетической карты) с `min(seam_energy_1_2, seam_energy_1_3, seam_energy_1_4)`. + +Если мы заполним таблицу `ShesamsEnergies` полностью, то минимальное число в нижнем ряду будет наименьшей возможной энергией шва. + +Попробуем заполнить несколько ячеек этой таблицы, чтобы посмотреть, как это работает. + +![Seams energies map traversal](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/57-dp-seams-energies-traversal.png) + +После заполнения таблицы `ShesamsEnergies` видно, что в нижнем ряду пиксель с самой низкой энергией имеет значение `50`. Для удобства во время генерации `samsEnergies` для каждого пикселя мы можем сохранить не только энергию шва, но и координаты предыдущего шва с наименьшей энергией. Это даст нам возможность легко восстанавливать траекторию шва снизу вверх. + +Временная сложность DP подхода составит `O(w * h)`, где `w` и `h` - это ширина и высота изображения. Обусловлена она тем, что нужно вычислить энергии для *всех* пикселей изображения. + +Вот пример того, как эта логика может быть реализована: + +```typescript +// The metadata for the pixels in the seam. +type SeamPixelMeta = { + energy: number, // The energy of the pixel. + coordinate: Coordinate, // The coordinate of the pixel. + previous: Coordinate | null, // The previous pixel in a seam. +}; + +// Finds the seam (the sequence of pixels from top to bottom) that has the +// lowest resulting energy using the Dynamic Programming approach. +const findLowEnergySeam = (energyMap: EnergyMap, { w, h }: ImageSize): Seam => { + // The 2D array of the size of w and h, where each pixel contains the + // seam metadata (pixel energy, pixel coordinate and previous pixel from + // the lowest energy seam at this point). + const seamsEnergies: (SeamPixelMeta | null)[][] = matrix(w, h, null); + + // Populate the first row of the map by just copying the energies + // from the energy map. + for (let x = 0; x < w; x += 1) { + const y = 0; + seamsEnergies[y][x] = { + energy: energyMap[y][x], + coordinate: { x, y }, + previous: null, + }; + } + + // Populate the rest of the rows. + for (let y = 1; y < h; y += 1) { + for (let x = 0; x < w; x += 1) { + // Find the top adjacent cell with minimum energy. + // This cell would be the tail of a seam with lowest energy at this point. + // It doesn't mean that this seam (path) has lowest energy globally. + // Instead, it means that we found a path with the lowest energy that may lead + // us to the current pixel with the coordinates x and y. + let minPrevEnergy = Infinity; + let minPrevX: number = x; + for (let i = (x - 1); i <= (x + 1); i += 1) { + if (i >= 0 && i < w && seamsEnergies[y - 1][i].energy < minPrevEnergy) { + minPrevEnergy = seamsEnergies[y - 1][i].energy; + minPrevX = i; + } + } + + // Update the current cell. + seamsEnergies[y][x] = { + energy: minPrevEnergy + energyMap[y][x], + coordinate: { x, y }, + previous: { x: minPrevX, y: y - 1 }, + }; + } + } + + // Find where the minimum energy seam ends. + // We need to find the tail of the lowest energy seam to start + // traversing it from its tail to its head (from the bottom to the top). + let lastMinCoordinate: Coordinate | null = null; + let minSeamEnergy = Infinity; + for (let x = 0; x < w; x += 1) { + const y = h - 1; + if (seamsEnergies[y][x].energy < minSeamEnergy) { + minSeamEnergy = seamsEnergies[y][x].energy; + lastMinCoordinate = { x, y }; + } + } + + // Find the lowest energy energy seam. + // Once we know where the tail is we may traverse and assemble the lowest + // energy seam based on the "previous" value of the seam pixel metadata. + const seam: Seam = []; + if (!lastMinCoordinate) { + return seam; + } + + const { x: lastMinX, y: lastMinY } = lastMinCoordinate; + + // Adding new pixel to the seam path one by one until we reach the top. + let currentSeam = seamsEnergies[lastMinY][lastMinX]; + while (currentSeam) { + seam.push(currentSeam.coordinate); + const prevMinCoordinates = currentSeam.previous; + if (!prevMinCoordinates) { + currentSeam = null; + } else { + const { x: prevMinX, y: prevMinY } = prevMinCoordinates; + currentSeam = seamsEnergies[prevMinY][prevMinX]; + } + } + + return seam; +}; +``` + +### Удаление шва с минимальной энергией + +Как только мы нашли шов с наименьшей суммарной энергией, нам нужно удалить (вырезать) пиксели, которые образуют его из изображения. Удаление происходит путем смещения пикселей справа от шва на `1px` влево. Из соображений производительности мы не будем удалять крайний столбик пикселей. Вместо этого, компонент, отвечающий за отрисовку уменьшенного изображения просто проигнорирует ту часть изображения, которая лежит за пределами обрезанной ширины. + +![Deleting the seam](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/60-deleting-example.png) + +```typescript +// Deletes the seam from the image data. +// We delete the pixel in each row and then shift the rest of the row pixels to the left. +const deleteSeam = (img: ImageData, seam: Seam, { w }: ImageSize): void => { + seam.forEach(({ x: seamX, y: seamY }: Coordinate) => { + for (let x = seamX; x < (w - 1); x += 1) { + const nextPixel = getPixel(img, { x: x + 1, y: seamY }); + setPixel(img, { x, y: seamY }, nextPixel); + } + }); +}; +``` + +## Удаление объектов с изображения + +Seam Carving алгоритм пытается сначала удалить швы, состоящие из низкоэнергетических пикселей. Мы могли бы использовать этот факт и, присвоив низкую энергию некоторым пикселям вручную (например, нарисовав на изображении маску), мы могли бы заставить алгоритм удалить отмеченные пиксели (*объекты*). + +В настоящее время в функции `getPixelEnergy()` мы используем только каналы цветов `R`, `G`, `B` для вычисления энергии пикселей. Но есть еще и параметр `A` (альфа, прозрачность), который мы не использовали. Мы можем использовать канал прозрачности, чтобы "сказать" алгоритму, что прозрачные пиксели — это те пиксели, которые мы хотим удалить. Вы можете ознакомиться с [исходным кодом функции getPixelEnergy()](https://github.com/trekhleb/js-image-carver/blob/main/src/utils/contentAwareResizer.ts#L54), которая учитывает прозрачность. + +Вот как при этом будет выглядеть удаление объектов: + +![JS IMAGE CARVER OBJECT REMOVAL DEMO](https://raw.githubusercontent.com/trekhleb/trekhleb.github.io/master/src/posts/2021/content-aware-image-resizing-in-javascript/assets/10-demo-02.gif) + +## Проблемы алгоритма и дальнейшие планы + +Приложение [JS IMAGE CARVER](https://github.com/trekhleb/js-image-carver) далеко от идеала и не является приложением production-ready качества. Основной его целью была возможность интерактивного экспериментирования с алгоритмом. Поэтому в дальнейших планах — использовать его именно для экспериментов. + +В [оригинальной статье](https://perso.crans.org/frenoy/matlab2012/seamcarving.pdf) описывается, как алгоритм может быть использован не только для уменьшения, но и для **увеличения изображения**. Увеличение (расширение) изображения, в свою очередь, может быть использовано для **автоматического расширения изображения до его исходной ширины после удаления объектов**. + +Еще одной интересной областью экспериментов может быть попытка ускорить алгоритм, чтобы он работал в режиме **реального времени**. + +> Таковы планы на будущее, но пока, надеюсь, пример с уменьшением изображения был интересен и полезен для вас. Также надеюсь, что вам было интересно увидеть применение динамического программирования в задачах, приближенных к реальности. +> +> Удачи с вашими собственными экспериментами! diff --git a/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js b/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js new file mode 100644 index 0000000000..b6400a3522 --- /dev/null +++ b/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js @@ -0,0 +1,51 @@ +import { createCanvas, loadImage } from 'canvas'; +import resizeImageWidth from '../resizeImageWidth'; + +const testImageBeforePath = './src/algorithms/image-processing/seam-carving/__tests__/test-image-before.jpg'; +const testImageAfterPath = './src/algorithms/image-processing/seam-carving/__tests__/test-image-after.jpg'; + +describe('resizeImageWidth', () => { + it('should perform content-aware image width reduction', () => { + // @see: https://jestjs.io/docs/asynchronous + return Promise.all([ + loadImage(testImageBeforePath), + loadImage(testImageAfterPath), + ]).then(([imgBefore, imgAfter]) => { + // Original image. + const canvasBefore = createCanvas(imgBefore.width, imgBefore.height); + const ctxBefore = canvasBefore.getContext('2d'); + ctxBefore.drawImage(imgBefore, 0, 0, imgBefore.width, imgBefore.height); + const imgDataBefore = ctxBefore.getImageData(0, 0, imgBefore.width, imgBefore.height); + + // Resized image saved. + const canvasAfter = createCanvas(imgAfter.width, imgAfter.height); + const ctxAfter = canvasAfter.getContext('2d'); + ctxAfter.drawImage(imgAfter, 0, 0, imgAfter.width, imgAfter.height); + + const toWidth = Math.floor(imgBefore.width / 2); + + const { + img: resizedImg, + size: resizedSize, + } = resizeImageWidth({ img: imgDataBefore, toWidth }); + + expect(resizedImg).toBeDefined(); + expect(resizedSize).toBeDefined(); + + // Resized image generated. + const canvasTest = createCanvas(resizedSize.w, resizedSize.h); + const ctxTest = canvasTest.getContext('2d'); + ctxTest.putImageData(resizedImg, 0, 0, 0, 0, resizedSize.w, resizedSize.h); + const imgDataTest = ctxTest.getImageData(0, 0, resizedSize.w, resizedSize.h); + + expect(resizedSize).toEqual({ w: toWidth, h: imgBefore.height }); + expect(imgDataTest.width).toBe(toWidth); + expect(imgDataTest.height).toBe(imgBefore.height); + expect(imgDataTest.width).toBe(imgAfter.width); + expect(imgDataTest.height).toBe(imgAfter.height); + + // @TODO: Check that images are identical. + // expect(canvasTest.toDataURL()).toEqual(canvasAfter.toDataURL()); + }); + }); +}); diff --git a/src/algorithms/image-processing/seam-carving/__tests__/test-image-after.jpg b/src/algorithms/image-processing/seam-carving/__tests__/test-image-after.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9af094e3ea2fc4e5cb70b1291c4a71a33c580ce5 GIT binary patch literal 6088 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 { + return new Array(h) + .fill(null) + .map(() => { + return new Array(w).fill(filler); + }); +}; + +/** + * Calculates the energy of a pixel. + * @param {?PixelColor} left + * @param {PixelColor} middle + * @param {?PixelColor} right + * @returns {number} + */ +const getPixelEnergy = (left, middle, right) => { + // Middle pixel is the pixel we're calculating the energy for. + const [mR, mG, mB] = middle; + + // Energy from the left pixel (if it exists). + let lEnergy = 0; + if (left) { + const [lR, lG, lB] = left; + lEnergy = (lR - mR) ** 2 + (lG - mG) ** 2 + (lB - mB) ** 2; + } + + // Energy from the right pixel (if it exists). + let rEnergy = 0; + if (right) { + const [rR, rG, rB] = right; + rEnergy = (rR - mR) ** 2 + (rG - mG) ** 2 + (rB - mB) ** 2; + } + + // Resulting pixel energy. + return Math.sqrt(lEnergy + rEnergy); +}; + +/** + * Calculates the energy of each pixel of the image. + * @param {ImageData} img + * @param {ImageSize} size + * @returns {EnergyMap} + */ +const calculateEnergyMap = (img, { w, h }) => { + // Create an empty energy map where each pixel has infinitely high energy. + // We will update the energy of each pixel. + const energyMap = matrix(w, h, Infinity); + for (let y = 0; y < h; y += 1) { + for (let x = 0; x < w; x += 1) { + // Left pixel might not exist if we're on the very left edge of the image. + const left = (x - 1) >= 0 ? getPixel(img, { x: x - 1, y }) : null; + // The color of the middle pixel that we're calculating the energy for. + const middle = getPixel(img, { x, y }); + // Right pixel might not exist if we're on the very right edge of the image. + const right = (x + 1) < w ? getPixel(img, { x: x + 1, y }) : null; + energyMap[y][x] = getPixelEnergy(left, middle, right); + } + } + return energyMap; +}; + +/** + * Finds the seam (the sequence of pixels from top to bottom) that has the + * lowest resulting energy using the Dynamic Programming approach. + * @param {EnergyMap} energyMap + * @param {ImageSize} size + * @returns {Seam} + */ +const findLowEnergySeam = (energyMap, { w, h }) => { + // The 2D array of the size of w and h, where each pixel contains the + // seam metadata (pixel energy, pixel coordinate and previous pixel from + // the lowest energy seam at this point). + const seamPixelsMap = matrix(w, h, null); + + // Populate the first row of the map by just copying the energies + // from the energy map. + for (let x = 0; x < w; x += 1) { + const y = 0; + seamPixelsMap[y][x] = { + energy: energyMap[y][x], + coordinate: { x, y }, + previous: null, + }; + } + + // Populate the rest of the rows. + for (let y = 1; y < h; y += 1) { + for (let x = 0; x < w; x += 1) { + // Find the top adjacent cell with minimum energy. + // This cell would be the tail of a seam with lowest energy at this point. + // It doesn't mean that this seam (path) has lowest energy globally. + // Instead, it means that we found a path with the lowest energy that may lead + // us to the current pixel with the coordinates x and y. + let minPrevEnergy = Infinity; + let minPrevX = x; + for (let i = (x - 1); i <= (x + 1); i += 1) { + if (i >= 0 && i < w && seamPixelsMap[y - 1][i].energy < minPrevEnergy) { + minPrevEnergy = seamPixelsMap[y - 1][i].energy; + minPrevX = i; + } + } + + // Update the current cell. + seamPixelsMap[y][x] = { + energy: minPrevEnergy + energyMap[y][x], + coordinate: { x, y }, + previous: { x: minPrevX, y: y - 1 }, + }; + } + } + + // Find where the minimum energy seam ends. + // We need to find the tail of the lowest energy seam to start + // traversing it from its tail to its head (from the bottom to the top). + let lastMinCoordinate = null; + let minSeamEnergy = Infinity; + for (let x = 0; x < w; x += 1) { + const y = h - 1; + if (seamPixelsMap[y][x].energy < minSeamEnergy) { + minSeamEnergy = seamPixelsMap[y][x].energy; + lastMinCoordinate = { x, y }; + } + } + + // Find the lowest energy energy seam. + // Once we know where the tail is we may traverse and assemble the lowest + // energy seam based on the "previous" value of the seam pixel metadata. + const seam = []; + + const { x: lastMinX, y: lastMinY } = lastMinCoordinate; + + // Adding new pixel to the seam path one by one until we reach the top. + let currentSeam = seamPixelsMap[lastMinY][lastMinX]; + while (currentSeam) { + seam.push(currentSeam.coordinate); + const prevMinCoordinates = currentSeam.previous; + if (!prevMinCoordinates) { + currentSeam = null; + } else { + const { x: prevMinX, y: prevMinY } = prevMinCoordinates; + currentSeam = seamPixelsMap[prevMinY][prevMinX]; + } + } + + return seam; +}; + +/** + * Deletes the seam from the image data. + * We delete the pixel in each row and then shift the rest of the row pixels to the left. + * @param {ImageData} img + * @param {Seam} seam + * @param {ImageSize} size + */ +const deleteSeam = (img, seam, { w }) => { + seam.forEach(({ x: seamX, y: seamY }) => { + for (let x = seamX; x < (w - 1); x += 1) { + const nextPixel = getPixel(img, { x: x + 1, y: seamY }); + setPixel(img, { x, y: seamY }, nextPixel); + } + }); +}; + +/** + * Performs the content-aware image width resizing using the seam carving method. + * @param {ResizeImageWidthArgs} args + * @returns {ResizeImageWidthResult} + */ +const resizeImageWidth = ({ img, toWidth }) => { + /** + * For performance reasons we want to avoid changing the img data array size. + * Instead we'll just keep the record of the resized image width and height separately. + * @type {ImageSize} + */ + const size = { w: img.width, h: img.height }; + + // Calculating the number of pixels to remove. + const pxToRemove = img.width - toWidth; + + let energyMap = null; + let seam = null; + + // Removing the lowest energy seams one by one. + for (let i = 0; i < pxToRemove; i += 1) { + // 1. Calculate the energy map for the current version of the image. + energyMap = calculateEnergyMap(img, size); + + // 2. Find the seam with the lowest energy based on the energy map. + seam = findLowEnergySeam(energyMap, size); + + // 3. Delete the seam with the lowest energy seam from the image. + deleteSeam(img, seam, size); + + // Reduce the image width, and continue iterations. + size.w -= 1; + } + + // Returning the resized image and its final size. + // The img is actually a reference to the ImageData, so technically + // the caller of the function already has this pointer. But let's + // still return it for better code readability. + return { img, size }; +}; + +export default resizeImageWidth; diff --git a/src/algorithms/image-processing/utils/imageData.js b/src/algorithms/image-processing/utils/imageData.js new file mode 100644 index 0000000000..de397b8ead --- /dev/null +++ b/src/algorithms/image-processing/utils/imageData.js @@ -0,0 +1,39 @@ +/** + * @typedef {ArrayLike | Uint8ClampedArray} PixelColor + */ + +/** + * @typedef {Object} PixelCoordinate + * @property {number} x - horizontal coordinate. + * @property {number} y - vertical coordinate. + */ + +/** + * Helper function that returns the color of the pixel. + * @param {ImageData} img + * @param {PixelCoordinate} coordinate + * @returns {PixelColor} + */ +export const getPixel = (img, { x, y }) => { + // The ImageData data array is a flat 1D array. + // Thus we need to convert x and y coordinates to the linear index. + const i = y * img.width + x; + const cellsPerColor = 4; // RGBA + // For better efficiency, instead of creating a new sub-array we return + // a pointer to the part of the ImageData array. + return img.data.subarray(i * cellsPerColor, i * cellsPerColor + cellsPerColor); +}; + +/** + * Helper function that sets the color of the pixel. + * @param {ImageData} img + * @param {PixelCoordinate} coordinate + * @param {PixelColor} color + */ +export const setPixel = (img, { x, y }, color) => { + // The ImageData data array is a flat 1D array. + // Thus we need to convert x and y coordinates to the linear index. + const i = y * img.width + x; + const cellsPerColor = 4; // RGBA + img.data.set(color, i * cellsPerColor); +}; From cfd9a630ff8cacd17880b16b27f32781eaac6bb7 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 21 Apr 2021 07:39:58 +0200 Subject: [PATCH 081/264] Test that two images are identical for the Seam Carving algorithm. (#694) * Test that two images are identical for the Seam Carving algorithm. * Tune the Seam Carving tests. * Tune the Seam Carving tests. * Tune the Seam Carving tests. * Tune the Seam Carving tests. --- .husky/pre-commit | 1 + .../__tests__/resizeImageWidth.test.js | 44 ++++++++++++++++++- 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index bec1c08a1a..a29a4166ea 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,5 +1,6 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" +# @TODO: Implement the pre-commit checks. # npm run lint # npm run test diff --git a/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js b/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js index b6400a3522..9afed97123 100644 --- a/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js +++ b/src/algorithms/image-processing/seam-carving/__tests__/resizeImageWidth.test.js @@ -4,6 +4,40 @@ import resizeImageWidth from '../resizeImageWidth'; const testImageBeforePath = './src/algorithms/image-processing/seam-carving/__tests__/test-image-before.jpg'; const testImageAfterPath = './src/algorithms/image-processing/seam-carving/__tests__/test-image-after.jpg'; +/** + * Compares two images and finds the number of different pixels. + * + * @param {ImageData} imgA - ImageData for the first image. + * @param {ImageData} imgB - ImageData for the second image. + * @param {number} threshold - Color difference threshold [0..255]. Smaller - stricter. + * @returns {number} - Number of different pixels. + */ +function pixelsDiff(imgA, imgB, threshold = 0) { + if (imgA.width !== imgB.width || imgA.height !== imgB.height) { + throw new Error('Images must have the same size'); + } + + let differentPixels = 0; + const numColorParams = 4; // RGBA + + for (let pixelIndex = 0; pixelIndex < imgA.data.length; pixelIndex += numColorParams) { + // Get pixel's color for each image. + const [aR, aG, aB] = imgA.data.subarray(pixelIndex, pixelIndex + numColorParams); + const [bR, bG, bB] = imgB.data.subarray(pixelIndex, pixelIndex + numColorParams); + + // Get average pixel's color for each image (make them greyscale). + const aAvgColor = Math.floor((aR + aG + aB) / 3); + const bAvgColor = Math.floor((bR + bG + bB) / 3); + + // Compare pixel colors. + if (Math.abs(aAvgColor - bAvgColor) > threshold) { + differentPixels += 1; + } + } + + return differentPixels; +} + describe('resizeImageWidth', () => { it('should perform content-aware image width reduction', () => { // @see: https://jestjs.io/docs/asynchronous @@ -21,6 +55,7 @@ describe('resizeImageWidth', () => { const canvasAfter = createCanvas(imgAfter.width, imgAfter.height); const ctxAfter = canvasAfter.getContext('2d'); ctxAfter.drawImage(imgAfter, 0, 0, imgAfter.width, imgAfter.height); + const imgDataAfter = ctxAfter.getImageData(0, 0, imgAfter.width, imgAfter.height); const toWidth = Math.floor(imgBefore.width / 2); @@ -44,8 +79,13 @@ describe('resizeImageWidth', () => { expect(imgDataTest.width).toBe(imgAfter.width); expect(imgDataTest.height).toBe(imgAfter.height); - // @TODO: Check that images are identical. - // expect(canvasTest.toDataURL()).toEqual(canvasAfter.toDataURL()); + const colorThreshold = 50; + const differentPixels = pixelsDiff(imgDataTest, imgDataAfter, colorThreshold); + + // Allow 10% of pixels to be different + const pixelsThreshold = Math.floor((imgAfter.width * imgAfter.height) / 10); + + expect(differentPixels).toBeLessThanOrEqual(pixelsThreshold); }); }); }); From 144b6867761a064bfe766c0c1994ebd1be676e74 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 21 Apr 2021 16:55:26 +0200 Subject: [PATCH 082/264] Testing Husky integration --- .husky/pre-commit | 5 ++--- .npmrc | 1 + package.json | 5 ++++- 3 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 .npmrc diff --git a/.husky/pre-commit b/.husky/pre-commit index a29a4166ea..660b820968 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,6 +1,5 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -# @TODO: Implement the pre-commit checks. -# npm run lint -# npm run test +npm run lint +npm run test diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000000..c0c80ba447 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +engine-strict=false diff --git a/package.json b/package.json index c4ae69b6fd..f77d87ff50 100644 --- a/package.json +++ b/package.json @@ -48,5 +48,8 @@ "husky": "6.0.0", "jest": "26.6.3" }, - "dependencies": {} + "engines": { + "node": ">=12.0.0", + "npm": ">=6.9.0" + } } From f7d07ae66d0fbd2c9b093bb074c8cb02de7be4b8 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 21 Apr 2021 17:09:59 +0200 Subject: [PATCH 083/264] Testing Husky integration --- .husky/pre-commit | 1 + 1 file changed, 1 insertion(+) diff --git a/.husky/pre-commit b/.husky/pre-commit index 660b820968..4c19307277 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,5 +1,6 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" +# Testing Husky. npm run lint npm run test From 4ca41ea83b8fdbfe2eb056c8b89852466a840a29 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 21 Apr 2021 17:12:53 +0200 Subject: [PATCH 084/264] Testing Husky integration --- .husky/pre-commit | 1 - 1 file changed, 1 deletion(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index 4c19307277..660b820968 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,6 +1,5 @@ #!/bin/sh . "$(dirname "$0")/_/husky.sh" -# Testing Husky. npm run lint npm run test From 912941be1d42d19a0a8b5ded73b35deee8e05718 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 21 Apr 2021 17:30:49 +0200 Subject: [PATCH 085/264] Add troubleshooting instructions. --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 71b0798fbe..a9fc7b5ea0 100644 --- a/README.md +++ b/README.md @@ -236,6 +236,7 @@ tree is being used. ## How to use this repository **Install all dependencies** + ``` npm install ``` @@ -249,15 +250,26 @@ npm run lint ``` **Run all tests** + ``` npm test ``` **Run tests by name** + ``` npm test -- 'LinkedList' ``` +**Troubleshooting** + +In case if linting or testing is failing try to delete the `node_modules` folder and re-install npm packages: + +``` +rm -rf ./node_modules +npm i +``` + **Playground** You may play with data-structures and algorithms in `./src/playground/playground.js` file and write From 7ad3fbc0f9eebfc4e86623be94e7c3dfbe9e611d Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 21 Apr 2021 18:09:48 +0200 Subject: [PATCH 086/264] Disabling tests in pre-commit to speed up the commits. --- .husky/pre-commit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.husky/pre-commit b/.husky/pre-commit index 660b820968..598a5dceaa 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,4 +2,4 @@ . "$(dirname "$0")/_/husky.sh" npm run lint -npm run test +# npm run test From d38cecd2e79d64efba1dd0b37cdd9acd60bc42ba Mon Sep 17 00:00:00 2001 From: Coco Guerra Date: Wed, 5 May 2021 22:43:28 -0600 Subject: [PATCH 087/264] Update README.es-ES.md (#704) * Update README.es-ES.md * Update README.es-ES.md --- .../linked-list/README.es-ES.md | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/src/data-structures/linked-list/README.es-ES.md b/src/data-structures/linked-list/README.es-ES.md index 978e234ddf..58eb2b860d 100644 --- a/src/data-structures/linked-list/README.es-ES.md +++ b/src/data-structures/linked-list/README.es-ES.md @@ -7,27 +7,26 @@ _Lee esto en otros idiomas:_ [_Português_](README.pt-BR.md) [_English_](README.md) -En ciencias de la computaciòn una **lista enlazada** es una coleccion linear +En ciencias de la computación una **lista enlazada** es una colección linear de elemntos de datos, en los cuales el orden linear no es dado por -su posciòn fisica en memoria. En cambio, cada -elemento señala al siguiente. Es una estructura de datos +su posción física en memoria. En cambio, cada +elemento señala al siguiente. Es una estructura de datos que consiste en un grupo de nodos los cuales juntos representan -una secuencia. Bajo la forma mas simple, cada nodo es -compuesto de datos y una referencia (en otras palabras, +una secuencia. Bajo la forma más simple, cada nodo es +compuesto de datos y una referencia (en otras palabras, un lazo) al siguiente nodo en la secuencia. Esta estructura -permite la insercion o remocion de elementos -desde cualquier posicion en la secuencia durante la iteracion. -Variantes mas complejas agregan lazos adicionales, permitiendo -una eficiente insercion o remocion desde referencias arbitrarias +permite la inserción o remoción de elementos +desde cualquier posición en la secuencia durante la iteración. +Variantes más complejas agregan lazos adicionales, permitiendo +una eficiente inserción o remoción desde referencias arbitrarias del elemento. Una desventaja de las listas lazadas es que el tiempo de -acceso es linear (y dificil de canalizar) Un acceso -mas rapido, como un acceso aleatorio, no es factible. Los arreglos +acceso es linear (y difícil de canalizar). Un acceso +más rápido, como un acceso aleatorio, no es factible. Los arreglos tienen una mejor locazion comparados con las listas lazadas. - ![Linked List](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg) -## Pseudocodigo para operacones basicas +## Pseudocódigo para operacones básicas ### Insertar @@ -76,7 +75,7 @@ Contains(head, value) return true end Contains ``` - + ### Borrar ```text @@ -146,19 +145,19 @@ ReverseTraversal(head, tail) end ReverseTraversal ``` -## Complexities +## Complejidades -### Time Complexity +### Complejidad del Tiempo -| Access | Search | Insertion | Deletion | -| :-------: | :-------: | :-------: | :-------: | -| O(n) | O(n) | O(1) | O(n) | +| Access | Search | Insertion | Deletion | +| :----: | :----: | :-------: | :------: | +| O(n) | O(n) | O(1) | O(n) | -### Space Complexity +### Complejidad Espacial O(n) -## References +## Referencias - [Wikipedia](https://en.wikipedia.org/wiki/Linked_list) - [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) From 64abcf12f28e02580b28cc8b64bab5ff0ac9c037 Mon Sep 17 00:00:00 2001 From: Deniz Binay <69312106+denizbinay@users.noreply.github.com> Date: Thu, 6 May 2021 06:46:04 +0200 Subject: [PATCH 088/264] add german translation for main readme (#703) --- README.ar-AR.md | 3 +- README.de-DE.md | 333 ++++++++++++++++++++++++++++++++++++++++++++++++ README.es-ES.md | 3 +- README.fr-FR.md | 3 +- README.id-ID.md | 3 +- README.it-IT.md | 3 +- README.ja-JP.md | 3 +- README.ko-KR.md | 3 +- README.md | 3 +- README.pl-PL.md | 3 +- README.pt-BR.md | 3 +- README.ru-RU.md | 3 +- README.tr-TR.md | 3 +- README.uk-UA.md | 3 +- README.zh-CN.md | 3 +- README.zh-TW.md | 3 +- 16 files changed, 363 insertions(+), 15 deletions(-) create mode 100644 README.de-DE.md diff --git a/README.ar-AR.md b/README.ar-AR.md index 378334fab0..797006b6ef 100644 --- a/README.ar-AR.md +++ b/README.ar-AR.md @@ -21,7 +21,8 @@ _اقرأ هذا في لغات أخرى:_ [_Português_](README.pt-BR.md), [_Русский_](README.ru-RU.md), [_Türk_](README.tr-TR.md), -[_Italiana_](README.it-IT.md) +[_Italiana_](README.it-IT.md), +[_Deutsch_](README.de-DE.md) ☝ ملاحضة هذا المشروع مخصص للاستخدام لأغراض التعلم والبحث فقط ، و ** ليست ** معدة للاستخدام في **الإنتاج** diff --git a/README.de-DE.md b/README.de-DE.md new file mode 100644 index 0000000000..3e127c3ea0 --- /dev/null +++ b/README.de-DE.md @@ -0,0 +1,333 @@ +# JavaScript-Algorithmen und Datenstrukturen + +[![CI](https://github.com/trekhleb/javascript-algorithms/workflows/CI/badge.svg)](https://github.com/trekhleb/javascript-algorithms/actions?query=workflow%3ACI+branch%3Amaster) +[![codecov](https://codecov.io/gh/trekhleb/javascript-algorithms/branch/master/graph/badge.svg)](https://codecov.io/gh/trekhleb/javascript-algorithms) + +Dieses Repository enthält JavaScript Beispiele für viele +gängige Algorithmen und Datenstrukturen. + +Jeder Algorithmus und jede Datenstruktur hat eine eigene README +mit zugehörigen Erklärungen und weiterführenden Links (einschließlich zu YouTube-Videos). + +_Lies dies in anderen Sprachen:_ +[_English_](https://github.com/trekhleb/javascript-algorithms/) +[_简体中文_](README.zh-CN.md), +[_繁體中文_](README.zh-TW.md), +[_한국어_](README.ko-KR.md), +[_日本語_](README.ja-JP.md), +[_Polski_](README.pl-PL.md), +[_Français_](README.fr-FR.md), +[_Español_](README.es-ES.md), +[_Português_](README.pt-BR.md), +[_Русский_](README.ru-RU.md), +[_Türk_](README.tr-TR.md), +[_Italiana_](README.it-IT.md), +[_Bahasa Indonesia_](README.id-ID.md), +[_Українська_](README.uk-UA.md), +[_Arabic_](README.ar-AR.md) + +_☝ Beachte, dass dieses Projekt nur für Lern- und Forschungszwecke gedacht ist und **nicht** für den produktiven Einsatz verwendet werden soll_ + +## Datenstrukturen + +Eine Datenstruktur ist eine bestimmte Art und Weise, Daten in einem Computer so zu organisieren und zu speichern, dass sie +effizient erreicht und verändert werden können. Genauer gesagt, ist eine Datenstruktur eine Sammlung von Werten, +den Beziehungen zwischen ihnen und den Funktionen oder Operationen, die auf die Daten angewendet werden können. + +`B` - Anfänger:innen, `A` - Fortgeschrittene + +* `B` [Verkettete Liste (Linked List)](src/data-structures/linked-list) +* `B` [Doppelt verkettete Liste (Doubly Linked List)](src/data-structures/doubly-linked-list) +* `B` [Warteschlange (Queue)](src/data-structures/queue) +* `B` [Stapelspeicher (Stack)](src/data-structures/stack) +* `B` [Hashtabelle (Hash Table)](src/data-structures/hash-table) +* `B` [Heap-Algorithmus (Heap)](src/data-structures/heap) - max und min Heap-Versionen +* `B` [Vorrangwarteschlange (Priority Queue)](src/data-structures/priority-queue) +* `A` [Trie (Trie)](src/data-structures/trie) +* `A` [Baum (Tree)](src/data-structures/tree) + * `A` [Binärer Suchbaum (Binary Search Tree)](src/data-structures/tree/binary-search-tree) + * `A` [AVL-Baum (AVL Tree)](src/data-structures/tree/avl-tree) + * `A` [Rot-Schwarz-Baum (Red-Black Tree)](src/data-structures/tree/red-black-tree) + * `A` [Segment-Baum (Segment Tree)](src/data-structures/tree/segment-tree) - mit Min/Max/Summenbereich-Abfrage Beispiel + * `A` [Fenwick Baum (Fenwick Tree)](src/data-structures/tree/fenwick-tree) (Binär indizierter Baum / Binary Indexed Tree) +* `A` [Graph (Graph)](src/data-structures/graph) (sowohl gerichtet als auch ungerichtet) +* `A` [Union-Find-Struktur (Disjoint Set)](src/data-structures/disjoint-set) +* `A` [Bloomfilter (Bloom Filter)](src/data-structures/bloom-filter) + +## Algorithmen + +Ein Algorithmus ist eine eindeutige Spezifikation, wie eine Klasse von Problemen zu lösen ist. Er besteht +aus einem Satz von Regeln, die eine Abfolge von Operationen genau definieren. + +`B` - Anfänger:innen, `A` - Fortgeschrittene + +### Algorithmen nach Thema + +* **Mathe** + * `B` [Bitmanipulation (Bit Manipulation)](src/algorithms/math/bits) - Bits setzen/lesen/aktualisieren/löschen, Multiplikation/Division durch zwei negieren usw.. + * `B` [Faktoriell (Factorial)](src/algorithms/math/factorial) + * `B` [Fibonacci-Zahl (Fibonacci Number)](src/algorithms/math/fibonacci) - Klassische und geschlossene Version + * `B` [Primfaktoren (Prime Factors)](src/algorithms/math/prime-factors) - Auffinden von Primfaktoren und deren Zählung mit Hilfe des Satz von Hardy-Ramanujan (Hardy-Ramanujan's theorem) + * `B` [Primzahl-Test (Primality Test)](src/algorithms/math/primality-test) (Probedivision / trial division method) + * `B` [Euklidischer Algorithmus (Euclidean Algorithm)](src/algorithms/math/euclidean-algorithm) - Berechnen des größten gemeinsamen Teilers (ggT) + * `B` [Kleinstes gemeinsames Vielfaches (Least Common Multiple)](src/algorithms/math/least-common-multiple) (kgV) + * `B` [Sieb des Eratosthenes (Sieve of Eratosthenes)](src/algorithms/math/sieve-of-eratosthenes) - Finden aller Primzahlen bis zu einer bestimmten Grenze + * `B` [Power of two (Is Power of Two)](src/algorithms/math/is-power-of-two) - Prüft, ob die Zahl eine Zweierpotenz ist (naive und bitweise Algorithmen) + * `B` [Pascalsches Dreieck (Pascal's Triangle)](src/algorithms/math/pascal-triangle) + * `B` [Komplexe Zahlen (Complex Number)](src/algorithms/math/complex-number) - Komplexe Zahlen und Grundoperationen mit ihnen + * `B` [Bogenmaß & Grad (Radian & Degree)](src/algorithms/math/radian) - Umrechnung von Bogenmaß in Grad und zurück + * `B` [Fast Powering Algorithmus (Fast Powering)](src/algorithms/math/fast-powering) + * `B` [Horner-Schema (Horner's method)](src/algorithms/math/horner-method) - Polynomauswertung + * `B` [Matrizen (Matrices)](src/algorithms/math/matrix) - Matrizen und grundlegende Matrixoperationen (Multiplikation, Transposition usw.) + * `B` [Euklidischer Abstand (Euclidean Distance)](src/algorithms/math/euclidean-distance) - Abstand zwischen zwei Punkten/Vektoren/Matrizen + * `A` [Ganzzahlige Partitionierung (Integer Partition)](src/algorithms/math/integer-partition) + * `A` [Quadratwurzel (Square Root)](src/algorithms/math/square-root) - Newtonverfahren (Newton's method) + * `A` [Liu Hui π Algorithmus (Liu Hui π Algorithm)](src/algorithms/math/liu-hui) - Näherungsweise π-Berechnungen auf Basis von N-gons + * `A` [Diskrete Fourier-Transformation (Discrete Fourier Transform)](src/algorithms/math/fourier-transform) - Eine Funktion der Zeit (ein Signal) in die Frequenzen zerlegen, aus denen sie sich zusammensetzt +* **Sets** + * `B` [Kartesisches Produkt (Cartesian Product)](src/algorithms/sets/cartesian-product) - Produkt aus mehreren Mengen + * `B` [Fisher-Yates-Verfahren (Fisher–Yates Shuffle)](src/algorithms/sets/fisher-yates) - Zufällige Permutation einer endlichen Folge + * `A` [Potenzmenge (Power Set)](src/algorithms/sets/power-set) - Alle Teilmengen einer Menge (Bitweise und Rücksetzverfahren Lösungen(backtracking solutions)) + * `A` [Permutation (Permutations)](src/algorithms/sets/permutations) (mit und ohne Wiederholungen) + * `A` [Kombination (Combinations)](src/algorithms/sets/combinations) (mit und ohne Wiederholungen) + * `A` [Problem der längsten gemeinsamen Teilsequenz (Longest Common Subsequence)](src/algorithms/sets/longest-common-subsequence) (LCS) + * `A` [Längste gemeinsame Teilsequenz (Longest Increasing Subsequence)](src/algorithms/sets/longest-increasing-subsequence) + * `A` [Der kürzeste gemeinsame String (Shortest Common Supersequence)](src/algorithms/sets/shortest-common-supersequence) (SCS) + * `A` [Rucksackproblem (Knapsack Problem)](src/algorithms/sets/knapsack-problem) - "0/1" und "Ungebunden" + * `A` [Das Maximum-Subarray Problem (Maximum Subarray)](src/algorithms/sets/maximum-subarray) - "Brute-Force-Methode" und "Dynamische Programmierung" (Kadane' Algorithmus) + * `A` [Kombinationssumme (Combination Sum)](src/algorithms/sets/combination-sum) - Alle Kombinationen finden, die eine bestimmte Summe bilden +* **Zeichenketten (Strings)** + * `B` [Hamming-Abstand (Hamming Distance)](src/algorithms/string/hamming-distance) - Anzahl der Positionen, an denen die Symbole unterschiedlich sind + * `A` [Levenshtein-Distanz (Levenshtein Distance)](src/algorithms/string/levenshtein-distance) - Minimaler Editierabstand zwischen zwei Sequenzen + * `A` [Knuth-Morris-Pratt-Algorithmus (Knuth–Morris–Pratt Algorithm)](src/algorithms/string/knuth-morris-pratt) (KMP Algorithmus) - Teilstringsuche (Mustervergleich / Pattern Matching) + * `A` [Z-Algorithmus (Z Algorithm)](src/algorithms/string/z-algorithm) - Teilstringsuche (Mustervergleich / Pattern Matching) + * `A` [Rabin-Karp-Algorithmus (Rabin Karp Algorithm)](src/algorithms/string/rabin-karp) - Teilstringsuche + * `A` [Längstes häufiges Teilzeichenfolgenproblem (Longest Common Substring)](src/algorithms/string/longest-common-substring) + * `A` [Regulärer Ausdruck (Regular Expression Matching)](src/algorithms/string/regular-expression-matching) +* **Suchen** + * `B` [Lineare Suche (Linear Search)](src/algorithms/search/linear-search) + * `B` [Sprungsuche (Jump Search)](src/algorithms/search/jump-search) (oder Blocksuche) - Suche im sortierten Array + * `B` [Binäre Suche (Binary Search)](src/algorithms/search/binary-search) - Suche in einem sortierten Array + * `B` [Interpolationssuche (Interpolation Search)](src/algorithms/search/interpolation-search) - Suche in gleichmäßig verteilt sortiertem Array +* **Sortieren** + * `B` [Bubblesort (Bubble Sort)](src/algorithms/sorting/bubble-sort) + * `B` [Selectionsort (Selection Sort)](src/algorithms/sorting/selection-sort) + * `B` [Einfügesortierenmethode (Insertion Sort)](src/algorithms/sorting/insertion-sort) + * `B` [Haldensortierung (Heap Sort)](src/algorithms/sorting/heap-sort) + * `B` [Mergesort (Merge Sort)](src/algorithms/sorting/merge-sort) + * `B` [Quicksort (Quicksort)](src/algorithms/sorting/quick-sort) - in-place und non-in-place Implementierungen + * `B` [Shellsort (Shellsort)](src/algorithms/sorting/shell-sort) + * `B` [Countingsort (Counting Sort)](src/algorithms/sorting/counting-sort) + * `B` [Fachverteilen (Radix Sort)](src/algorithms/sorting/radix-sort) +* **Verkettete Liste (Linked List)** + * `B` [Gerade Traversierung (Straight Traversal)](src/algorithms/linked-list/traversal) + * `B` [Umgekehrte Traversierung (Reverse Traversal)](src/algorithms/linked-list/reverse-traversal) +* **Bäume** + * `B` [Tiefensuche (Depth-First Search)](src/algorithms/tree/depth-first-search) (DFS) + * `B` [Breitensuche (Breadth-First Search)](src/algorithms/tree/breadth-first-search) (BFS) +* **Graphen** + * `B` [Tiefensuche (Depth-First Search)](src/algorithms/graph/depth-first-search) (DFS) + * `B` [Breitensuche (Breadth-First Search)](src/algorithms/graph/breadth-first-search) (BFS) + * `B` [Algorithmus von Kruskal (Kruskal’s Algorithm)](src/algorithms/graph/kruskal) - Finden des Spannbaum (Minimum Spanning Tree / MST) für einen gewichteten ungerichteten Graphen + * `A` [Dijkstra-Algorithmus (Dijkstra Algorithm)](src/algorithms/graph/dijkstra) - Finden der kürzesten Wege zu allen Knoten des Graphen von einem einzelnen Knotenpunkt aus + * `A` [Bellman-Ford-Algorithmus (Bellman-Ford Algorithm)](src/algorithms/graph/bellman-ford) - Finden der kürzesten Wege zu allen Knoten des Graphen von einem einzelnen Knotenpunkt aus + * `A` [Algorithmus von Floyd und Warshall (Floyd-Warshall Algorithm)](src/algorithms/graph/floyd-warshall) - Die kürzesten Wege zwischen allen Knotenpaaren finden + * `A` [Zykluserkennung (Detect Cycle)](src/algorithms/graph/detect-cycle) - Sowohl für gerichtete als auch für ungerichtete Graphen (DFS- und Disjoint-Set-basierte Versionen) + * `A` [Algorithmus von Prim (Prim’s Algorithm)](src/algorithms/graph/prim) - Finden des Spannbaums (Minimum Spanning Tree / MST) für einen gewichteten ungerichteten Graphen + * `A` [Topologische Sortierung (Topological Sorting)](src/algorithms/graph/topological-sorting) - DFS-Verfahren + * `A` [Artikulationspunkte (Articulation Points)](src/algorithms/graph/articulation-points) - Algorithmus von Tarjan (Tarjan's algorithm) (DFS basiert) + * `A` [Brücke (Bridges)](src/algorithms/graph/bridges) - DFS-basierter Algorithmus + * `A` [Eulerkreisproblem (Eulerian Path and Eulerian Circuit)](src/algorithms/graph/eulerian-path) - Algorithmus von Fleury (Fleury's algorithm) - Jede Kante genau einmal durchlaufen. + * `A` [Hamiltonkreisproblem (Hamiltonian Cycle)](src/algorithms/graph/hamiltonian-cycle) - Jeden Eckpunkt genau einmal durchlaufen. + * `A` [Starke Zusammenhangskomponente (Strongly Connected Components)](src/algorithms/graph/strongly-connected-components) - Kosarajus Algorithmus + * `A` [Problem des Handlungsreisenden (Travelling Salesman Problem)](src/algorithms/graph/travelling-salesman) - Kürzestmögliche Route, die jede Stadt besucht und zur Ausgangsstadt zurückkehrt +* **Kryptographie** + * `B` [Polynomiale Streuwertfunktion(Polynomial Hash)](src/algorithms/cryptography/polynomial-hash) - Rollierende Streuwert-Funktion basierend auf Polynom + * `B` [Schienenzaun Chiffre (Rail Fence Cipher)](src/algorithms/cryptography/rail-fence-cipher) - Ein Transpositionsalgorithmus zur Verschlüsselung von Nachrichten + * `B` [Caesar-Verschlüsselung (Caesar Cipher)](src/algorithms/cryptography/caesar-cipher) - Einfache Substitutions-Chiffre + * `B` [Hill-Chiffre (Hill Cipher)](src/algorithms/cryptography/hill-cipher) - Substitutionschiffre basierend auf linearer Algebra +* **Maschinelles Lernen** + * `B` [Künstliches Neuron (NanoNeuron)](https://github.com/trekhleb/nano-neuron) - 7 einfache JS-Funktionen, die veranschaulichen, wie Maschinen tatsächlich lernen können (Vorwärts-/Rückwärtspropagation) + * `B` [Nächste-Nachbarn-Klassifikation (k-NN)](src/algorithms/ml/knn) - k-nächste-Nachbarn-Algorithmus + * `B` [k-Means (k-Means)](src/algorithms/ml/k-means) - k-Means-Algorithmus +* **Image Processing** + * `B` [Inhaltsabhängige Bildverzerrung (Seam Carving)](src/algorithms/image-processing/seam-carving) - Algorithmus zur inhaltsabhängigen Bildgrößenänderung +* **Unkategorisiert** + * `B` [Türme von Hanoi (Tower of Hanoi)](src/algorithms/uncategorized/hanoi-tower) + * `B` [Rotationsmatrix (Square Matrix Rotation)](src/algorithms/uncategorized/square-matrix-rotation) - In-Place-Algorithmus + * `B` [Jump Game (Jump Game)](src/algorithms/uncategorized/jump-game) - Backtracking, dynamische Programmierung (Top-down + Bottom-up) und gierige Beispiele + * `B` [Eindeutige Pfade (Unique Paths)](src/algorithms/uncategorized/unique-paths) - Backtracking, dynamische Programmierung und Pascalsches Dreieck basierte Beispiele + * `B` [Regenterrassen (Rain Terraces)](src/algorithms/uncategorized/rain-terraces) - Auffangproblem für Regenwasser (trapping rain water problem) (dynamische Programmierung und Brute-Force-Versionen) + * `B` [Rekursive Treppe (Recursive Staircase)](src/algorithms/uncategorized/recursive-staircase) - Zählen der Anzahl der Wege, die nach oben führen (4 Lösungen) + * `B` [Beste Zeit zum Kaufen/Verkaufen von Aktien (Best Time To Buy Sell Stocks)](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - Beispiele für "Teile und Herrsche" und Beispiele für den One-Pass-Algorithmus + * `A` [Damenproblem (N-Queens Problem)](src/algorithms/uncategorized/n-queens) + * `A` [Springerproblem (Knight's Tour)](src/algorithms/uncategorized/knight-tour) + +### Algorithmen nach Paradigma + +Ein algorithmisches Paradigma ist eine generische Methode oder ein Ansatz, der dem Entwurf einer Klasse von Algorithmen zugrunde liegt. Es ist eine Abstraktion, die höher ist als der Begriff des Algorithmus. Genauso wie ein Algorithmus eine Abstraktion ist, die höher ist als ein Computerprogramm. + +* **Brachiale Gewalt (Brute Force)** - schaut sich alle Möglichkeiten an und wählt die beste Lösung aus + * `B` [Lineare Suche (Linear Search)](src/algorithms/search/linear-search) + * `B` [Regenterrassen (Rain Terraces)](src/algorithms/uncategorized/rain-terraces) - Auffangproblem für Regenwasser (trapping rain water problem) (dynamische Programmierung und Brute-Force-Versionen) + * `B` [Rekursive Treppe (Recursive Staircase)](src/algorithms/uncategorized/recursive-staircase) - Zählen der Anzahl der Wege, die nach oben führen (4 Lösungen) + * `A` [Das Maximum-Subarray Problem (Maximum Subarray)](src/algorithms/sets/maximum-subarray) + * `A` [Problem des Handlungsreisenden (Travelling Salesman Problem)](src/algorithms/graph/travelling-salesman) - Kürzestmögliche Route, die jede Stadt besucht und zur Ausgangsstadt zurückkehrt + * `A` [Diskrete Fourier-Transformation (Discrete Fourier Transform)](src/algorithms/math/fourier-transform) - Eine Funktion der Zeit (ein Signal) in die Frequenzen zerlegen, aus denen sie sich zusammensetzt +* **Gierig (Greedy)** - Wählt die beste Option zum aktuellen Zeitpunkt, ohne Rücksicht auf die Zukunft + * `B` [Jump Game (Jump Game)](src/algorithms/uncategorized/jump-game) + * `A` [Rucksackproblem (Unbound Knapsack Problem)](src/algorithms/sets/knapsack-problem) + * `A` [Dijkstra-Algorithmus (Dijkstra Algorithm)](src/algorithms/graph/dijkstra) - Finden der kürzesten Wege zu allen Knoten des Graphen von einem einzelnen Knotenpunkt aus + * `A` [Algorithmus von Prim (Prim’s Algorithm)](src/algorithms/graph/prim) - Finden des Spannbaums (Minimum Spanning Tree / MST) für einen gewichteten ungerichteten Graphen + * `B` [Algorithmus von Kruskal (Kruskal’s Algorithm)](src/algorithms/graph/kruskal) - Finden des Spannbaum (Minimum Spanning Tree / MST) für einen gewichteten ungerichteten Graphen +* **Teile und herrsche** - Das Problem in kleinere Teile aufteilen und diese Teile dann lösen + * `B` [Binäre Suche (Binary Search)](src/algorithms/search/binary-search) + * `B` [Türme von Hanoi (Tower of Hanoi)](src/algorithms/uncategorized/hanoi-tower) + * `B` [Pascalsches Dreieck (Pascal's Triangle)](src/algorithms/math/pascal-triangle) + * `B` [Euklidischer Algorithmus (Euclidean Algorithm)](src/algorithms/math/euclidean-algorithm) - calculate the Greatest Common Divisor (GCD) + * `B` [Mergesort (Merge Sort)](src/algorithms/sorting/merge-sort) + * `B` [Quicksort (Quicksort)](src/algorithms/sorting/quick-sort) + * `B` [Tiefensuche (Depth-First Search)](src/algorithms/tree/depth-first-search) (DFS) + * `B` [Breitensuche (Breadth-First Search)](src/algorithms/graph/depth-first-search) (DFS) + * `B` [Matrizen (Matrices)](src/algorithms/math/matrix) - Matrizen und grundlegende Matrixoperationen (Multiplikation, Transposition usw.) + * `B` [Jump Game (Jump Game)](src/algorithms/uncategorized/jump-game) + * `B` [Fast Powering Algorithmus (Fast Powering)](src/algorithms/math/fast-powering) + * `B` [Beste Zeit zum Kaufen/Verkaufen von Aktien (Best Time To Buy Sell Stocks)](src/algorithms/uncategorized/best-time-to-buy-sell-stocks) - Beispiele für "Teile und Herrsche" und Beispiele für den One-Pass-Algorithmus + * `A` [Permutation (Permutations)](src/algorithms/sets/permutations) (mit und ohne Wiederholungen) + * `A` [Kombination (Combinations)](src/algorithms/sets/combinations) (mit und ohne Wiederholungen) +* **Dynamische Programmierung** - Eine Lösung aus zuvor gefundenen Teillösungen aufbauen + * `B` [Fibonacci-Zahl (Fibonacci Number)](src/algorithms/math/fibonacci) + * `B` [Jump Game (Jump Game)](src/algorithms/uncategorized/jump-game) + * `B` [Eindeutige Pfade (Unique Paths)](src/algorithms/uncategorized/unique-paths) + * `B` [Regenterrassen (Rain Terraces)](src/algorithms/uncategorized/rain-terraces) - Auffangproblem für Regenwasser (trapping rain water problem) (dynamische Programmierung und Brute-Force-Versionen) + * `B` [Rekursive Treppe (Recursive Staircase)](src/algorithms/uncategorized/recursive-staircase) - Zählen der Anzahl der Wege, die nach oben führen (4 Lösungen) + * `B` [Inhaltsabhängige Bildverzerrung (Seam Carving)](src/algorithms/image-processing/seam-carving) - Algorithmus zur inhaltsabhängigen Bildgrößenänderung + * `A` [Levenshtein-Distanz (Levenshtein Distance)](src/algorithms/string/levenshtein-distance) - Minimaler Editierabstand zwischen zwei Sequenzen + * `A` [Problem der längsten gemeinsamen Teilsequenz (Longest Common Subsequence)](src/algorithms/sets/longest-common-subsequence) (LCS) + * `A` [Längstes häufiges Teilzeichenfolgenproblem (Longest Common Substring)](src/algorithms/string/longest-common-substring) + * `A` [Längste gemeinsame Teilsequenz (Longest Increasing Subsequence)](src/algorithms/sets/longest-increasing-subsequence) + * `A` [Der kürzeste gemeinsame String (Shortest Common Supersequence)](src/algorithms/sets/shortest-common-supersequence) + * `A` [Rucksackproblem (0/1 Knapsack Problem)](src/algorithms/sets/knapsack-problem) + * `A` [Ganzzahlige Partitionierung (Integer Partition)](src/algorithms/math/integer-partition) + * `A` [Das Maximum-Subarray Problem (Maximum Subarray)](src/algorithms/sets/maximum-subarray) + * `A` [Bellman-Ford-Algorithmus (Bellman-Ford Algorithm)](src/algorithms/graph/bellman-ford) - Finden der kürzesten Wege zu allen Knoten des Graphen von einem einzelnen Knotenpunkt aus + * `A` [Algorithmus von Floyd und Warshall (Floyd-Warshall Algorithm)](src/algorithms/graph/floyd-warshall) - Die kürzesten Wege zwischen allen Knotenpaaren finden + * `A` [Regulärer Ausdruck (Regular Expression Matching)](src/algorithms/string/regular-expression-matching) +* **Zurückverfolgung** - Ähnlich wie bei Brute-Force versuchen Sie, alle möglichen Lösungen zu generieren, aber jedes Mal, wenn Sie die nächste Lösung generieren, testen Sie, ob sie alle Bedingungen erfüllt, und fahren erst dann mit der Generierung weiterer Lösungen fort. Andernfalls gehen Sie zurück und nehmen einen anderen Weg, um eine Lösung zu finden. Normalerweise wird das DFS-Traversal des Zustandsraums verwendet. + * `B` [Jump Game (Jump Game)](src/algorithms/uncategorized/jump-game) + * `B` [Eindeutige Pfade (Unique Paths)](src/algorithms/uncategorized/unique-paths) + * `A` [Potenzmenge (Power Set)](src/algorithms/sets/power-set) - Alle Teilmengen einer Menge + * `A` [Hamiltonkreisproblem (Hamiltonian Cycle)](src/algorithms/graph/hamiltonian-cycle) - Jeden Eckpunkt genau einmal durchlaufen. + * `A` [Damenproblem (N-Queens Problem)](src/algorithms/uncategorized/n-queens) + * `A` [Springerproblem (Knight's Tour)](src/algorithms/uncategorized/knight-tour) + * `A` [Kombinationssumme (Combination Sum)](src/algorithms/sets/combination-sum) - Alle Kombinationen finden, die eine bestimmte Summe bilden +* **Verzweigung & Bindung** - Merkt sich die Lösung mit den niedrigsten Kosten, die in jeder Phase der Backtracking-Suche gefunden wurde, und verwendet die Kosten der bisher gefundenen Lösung mit den niedrigsten Kosten als untere Schranke für die Kosten einer Lösung des Problems mit den geringsten Kosten, um Teillösungen zu verwerfen, deren Kosten größer sind als die der bisher gefundenen Lösung mit den niedrigsten Kosten. Normalerweise wird das BFS-Traversal in Kombination mit dem DFS-Traversal des Zustandsraumbaums verwendet. + +## So verwendest du dieses Repository + +**Alle Abhängigkeiten installieren** + +``` +npm install +``` + +**ESLint ausführen** + +You may want to run it to check code quality. + +``` +npm run lint +``` + +**Alle Tests ausführen** + +``` +npm test +``` + +**Tests nach Namen ausführen** + +``` +npm test -- 'LinkedList' +``` + +**Fehlerbehebung** + +Falls das Linting oder Testen fehlschlägt, versuche, den Ordner "node_modules" zu löschen und die npm-Pakete neu zu installieren: + +``` +rm -rf ./node_modules +npm i +``` + +**Spielwiese** + +Du kannst mit Datenstrukturen und Algorithmen in der Datei `./src/playground/playground.js` herumspielen und +dir in dieser Datei Tests schreiben `./src/playground/__test__/playground.test.js`. + +Dann führe einfach folgenden Befehl aus, um zu testen, ob dein Spielwiesencode wie erwartet funktioniert: + +``` +npm test -- 'playground' +``` + +## Nützliche Informationen + +### Referenzen + +[▶ Datenstrukturen und Algorithmen auf YouTube(Englisch)](https://www.youtube.com/playlist?list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) + +### O-Notation (_Big O Notation_) + +Die O-Notation wird verwendet, um Algorithmen danach zu klassifizieren, wie ihre Laufzeit oder ihr Platzbedarf mit zunehmender Eingabegröße wächst. In der folgenden Tabelle finden Sie die häufigsten Wachstumsordnungen von Algorithmen, die in Big-O-Notation angegeben sind. + +![O-Notation Graphen](./assets/big-o-graph.png) + +Quelle: [Big O Cheat Sheet](http://bigocheatsheet.com/). + +Nachfolgend finden Sie eine Liste einiger der am häufigsten verwendeten Big O-Notationen und deren Leistungsvergleiche für unterschiedliche Größen der Eingabedaten. + +| Big O Notation | Berechnungen für 10 Elemente | Berechnungen für 100 Elemente | Berechnungen für 1000 Elemente | +| -------------- | ---------------------------- | ----------------------------- | ------------------------------ | +| **O(1)** | 1 | 1 | 1 | +| **O(log N)** | 3 | 6 | 9 | +| **O(N)** | 10 | 100 | 1000 | +| **O(N log N)** | 30 | 600 | 9000 | +| **O(N^2)** | 100 | 10000 | 1000000 | +| **O(2^N)** | 1024 | 1.26e+29 | 1.07e+301 | +| **O(N!)** | 3628800 | 9.3e+157 | 4.02e+2567 | + +### Komplexität von Datenstrukturoperationen + +| Datenstruktur | Zugriff auf | Suche | Einfügen | Löschung | Kommentare | +| ---------------------- | :---------: | :----: | :------: | :------: | :-------------------------------------------------------------- | +| **Array** | 1 | n | n | n | | +| **Stack** | n | n | 1 | 1 | | +| **Queue** | n | n | 1 | 1 | | +| **Linked List** | n | n | 1 | n | | +| **Hash Table** | - | n | n | n | Im Falle einer perfekten Hash-Funktion wären die Kosten O(1) | +| **Binary Search Tree** | n | n | n | n | Im Falle eines ausgeglichenen Baumes wären die Kosten O(log(n)) | +| **B-Tree** | log(n) | log(n) | log(n) | log(n) | | +| **Red-Black Tree** | log(n) | log(n) | log(n) | log(n) | | +| **AVL Tree** | log(n) | log(n) | log(n) | log(n) | | +| **Bloom Filter** | - | 1 | 1 | - | Falschpostive sind bei der Suche möglichen | + +### Komplexität von Array-Sortieralgorithmen + +| Name | Bester | Durchschnitt | Schlechtester | Speicher | Stabil | Kommentar | +| ------------------ | :-----------: | :---------------------: | :-------------------------: | :------: | :----: | :------------------------------------------------------------------------- | +| **Bubble sort** | n | n2 | n2 | 1 | JA | | +| **Insertion sort** | n | n2 | n2 | 1 | Ja | | +| **Selection sort** | n2 | n2 | n2 | 1 | Nein | | +| **Heap sort** | n log(n) | n log(n) | n log(n) | 1 | Nein | | +| **Merge sort** | n log(n) | n log(n) | n log(n) | n | Ja | | +| **Quick sort** | n log(n) | n log(n) | n2 | log(n) | Nein | Quicksort wird normalerweise in-place mit O(log(n)) Stapelplatz ausgeführt | +| **Shell sort** | n log(n) | abhängig von Spaltfolge | n (log(n))2 | 1 | Nein | | +| **Counting sort** | n + r | n + r | n + r | n + r | Ja | r - größte Zahl im Array | +| **Radix sort** | n \* k | n \* k | n \* k | n + k | Ja | k - Länge des längsten Schlüssels | + +## Projekt-Unterstützer + +> Du kannst dieses Projekt unterstützen über ❤️️ [GitHub](https://github.com/sponsors/trekhleb) or ❤️️ [Patreon](https://www.patreon.com/trekhleb). + +[Leute, die dieses Projekt unterstützen](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0` diff --git a/README.es-ES.md b/README.es-ES.md index fa1fd340c6..f350ee059e 100644 --- a/README.es-ES.md +++ b/README.es-ES.md @@ -23,7 +23,8 @@ _Léelo en otros idiomas:_ [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), [_Українська_](README.uk-UA.md), -[_Arabic_](README.ar-AR.md) +[_Arabic_](README.ar-AR.md), +[_Deutsch_](README.de-DE.md) *☝ Nótese que este proyecto está pensado con fines de aprendizaje e investigación, y **no** para ser usado en producción.* diff --git a/README.fr-FR.md b/README.fr-FR.md index 024a3b1904..4508340aec 100644 --- a/README.fr-FR.md +++ b/README.fr-FR.md @@ -24,7 +24,8 @@ _Lisez ceci dans d'autres langues:_ [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), [_Українська_](README.uk-UA.md), -[_Arabic_](README.ar-AR.md) +[_Arabic_](README.ar-AR.md), +[_Deutsch_](README.de-DE.md) ## Data Structures diff --git a/README.id-ID.md b/README.id-ID.md index 2a258f973c..2f5212ac64 100644 --- a/README.id-ID.md +++ b/README.id-ID.md @@ -21,7 +21,8 @@ _Baca ini dalam bahasa yang lain:_ [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), [_Українська_](README.uk-UA.md), -[_Arabic_](README.ar-AR.md) +[_Arabic_](README.ar-AR.md), +[_Deutsch_](README.de-DE.md) _☝ Perhatikan bahwa proyek ini hanya dimaksudkan untuk tujuan pembelajaran dan riset, dan **tidak** dimaksudkan untuk digunakan sebagai produksi._ diff --git a/README.it-IT.md b/README.it-IT.md index 9d8c664f6a..d74befd683 100644 --- a/README.it-IT.md +++ b/README.it-IT.md @@ -20,7 +20,8 @@ _Leggilo in altre lingue:_ [_Türk_](README.tr-TR.md), [_Bahasa Indonesia_](README.id-ID.md), [_Українська_](README.uk-UA.md), -[_Arabic_](README.ar-AR.md) +[_Arabic_](README.ar-AR.md), +[_Deutsch_](README.de-DE.md) *☝ Si noti che questo progetto è destinato ad essere utilizzato solo per l'apprendimento e la ricerca e non è destinato ad essere utilizzato per il commercio.* diff --git a/README.ja-JP.md b/README.ja-JP.md index af2c887c2c..a1c13211a0 100644 --- a/README.ja-JP.md +++ b/README.ja-JP.md @@ -23,7 +23,8 @@ _Read this in other languages:_ [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), [_Українська_](README.uk-UA.md), -[_Arabic_](README.ar-AR.md) +[_Arabic_](README.ar-AR.md), +[_Deutsch_](README.de-DE.md) ## データ構造 diff --git a/README.ko-KR.md b/README.ko-KR.md index 02f35d0250..e9b77dca27 100644 --- a/README.ko-KR.md +++ b/README.ko-KR.md @@ -22,7 +22,8 @@ _Read this in other languages:_ [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), [_Українська_](README.uk-UA.md), -[_Arabic_](README.ar-AR.md) +[_Arabic_](README.ar-AR.md), +[_Deutsch_](README.de-DE.md) ## 자료 구조 diff --git a/README.md b/README.md index a9fc7b5ea0..d16c264d1e 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,8 @@ _Read this in other languages:_ [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), [_Українська_](README.uk-UA.md), -[_Arabic_](README.ar-AR.md) +[_Arabic_](README.ar-AR.md), +[_Deutsch_](README.de-DE.md) *☝ Note that this project is meant to be used for learning and researching purposes only, and it is **not** meant to be used for production.* diff --git a/README.pl-PL.md b/README.pl-PL.md index 08dc09b6aa..235d0d47d6 100644 --- a/README.pl-PL.md +++ b/README.pl-PL.md @@ -24,7 +24,8 @@ _Read this in other languages:_ [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), [_Українська_](README.uk-UA.md), -[_Arabic_](README.ar-AR.md) +[_Arabic_](README.ar-AR.md), +[_Deutsch_](README.de-DE.md) ## Struktury Danych diff --git a/README.pt-BR.md b/README.pt-BR.md index baffbc3179..c410fda651 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -24,7 +24,8 @@ _Leia isto em outros idiomas:_ [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), [_Українська_](README.uk-UA.md), -[_Arabic_](README.ar-AR.md) +[_Arabic_](README.ar-AR.md), +[_Deutsch_](README.de-DE.md) ## Estrutura de Dados diff --git a/README.ru-RU.md b/README.ru-RU.md index 32f4b2f526..ef9e9444a3 100644 --- a/README.ru-RU.md +++ b/README.ru-RU.md @@ -21,7 +21,8 @@ _Читать на других языках:_ [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), [_Українська_](README.uk-UA.md), -[_Arabic_](README.ar-AR.md) +[_Arabic_](README.ar-AR.md), +[_Deutsch_](README.de-DE.md) *☝ Замечание: этот репозиторий предназначен для учебно-исследовательских целей (**не** для использования в продакшн-системах).* diff --git a/README.tr-TR.md b/README.tr-TR.md index f7ed57fc91..fff640c415 100644 --- a/README.tr-TR.md +++ b/README.tr-TR.md @@ -22,7 +22,8 @@ _Read this in other languages:_ [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), [_Українська_](README.uk-UA.md), -[_Arabic_](README.ar-AR.md) +[_Arabic_](README.ar-AR.md), +[_Deutsch_](README.de-DE.md) *☝ Not, bu proje araştırma ve öğrenme amacı ile yapılmış olup üretim için **yaplılmamıştır**.* diff --git a/README.uk-UA.md b/README.uk-UA.md index 4391ed1992..6fdd7b4c13 100644 --- a/README.uk-UA.md +++ b/README.uk-UA.md @@ -21,7 +21,8 @@ _Вивчення матеріалу на інших мовах:_ [_Türk_](README.tr-TR.md), [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), -[_Arabic_](README.ar-AR.md) +[_Arabic_](README.ar-AR.md), +[_Deutsch_](README.de-DE.md) *☝ Зверніть увагу! Даний проект призначений лише для навчальних та дослідницьких цілей, і він **не** призначений для виробництва (продакшн).* diff --git a/README.zh-CN.md b/README.zh-CN.md index 35a3733fc3..22b50d405c 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -21,7 +21,8 @@ _Read this in other languages:_ [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), [_Українська_](README.uk-UA.md), -[_Arabic_](README.ar-AR.md) +[_Arabic_](README.ar-AR.md), +[_Deutsch_](README.de-DE.md) *注意:这个项目仅用于学习和研究,**不是**用于生产环境。* diff --git a/README.zh-TW.md b/README.zh-TW.md index 4a09b8433e..bf90fbbe62 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -20,7 +20,8 @@ _Read this in other languages:_ [_Italiana_](README.it-IT.md), [_Bahasa Indonesia_](README.id-ID.md), [_Українська_](README.uk-UA.md), -[_Arabic_](README.ar-AR.md) +[_Arabic_](README.ar-AR.md), +[_Deutsch_](README.de-DE.md) ## 資料結構 From 464a84bc7cb8fcc9c78ccb9fab0d77d978e8363c Mon Sep 17 00:00:00 2001 From: justforever Date: Thu, 6 May 2021 12:56:40 +0800 Subject: [PATCH 089/264] Update README.zh-TW.md (#690) --- README.zh-TW.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.zh-TW.md b/README.zh-TW.md index bf90fbbe62..ddf043d7af 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -215,7 +215,7 @@ npm test -- 'playground' | 名稱 | 最佳 | 平均 | 最差 | 記憶體 | 穩定 | | ---------------------- | :-------: | :-------: | :-----------: | :-------: | :-------: | -| **氣派排序** | n | n^2 | n^2 | 1 | Yes | +| **氣泡排序** | n | n^2 | n^2 | 1 | Yes | | **插入排序** | n | n^2 | n^2 | 1 | Yes | | **選擇排序** | n^2 | n^2 | n^2 | 1 | No | | **Heap 排序** | n log(n) | n log(n) | n log(n) | 1 | No | From 5ffab573ca4610c3ea6bd00709883b0a2ec5b898 Mon Sep 17 00:00:00 2001 From: Freivin Campbell Date: Wed, 5 May 2021 23:00:10 -0600 Subject: [PATCH 090/264] Create README.es-ES.md (#680) new translation added --- .../doubly-linked-list/README.es-ES.md | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 src/data-structures/doubly-linked-list/README.es-ES.md diff --git a/src/data-structures/doubly-linked-list/README.es-ES.md b/src/data-structures/doubly-linked-list/README.es-ES.md new file mode 100644 index 0000000000..0736d499ac --- /dev/null +++ b/src/data-structures/doubly-linked-list/README.es-ES.md @@ -0,0 +1,102 @@ +# Lista doblemente enlazada + +_Lea esto en otros idiomas:_ +[_Русский_](README.ru-RU.md), +[_简体中文_](README.zh-CN.md), +[_日本語_](README.ja-JP.md), +[_Português_](README.pt-BR.md) +[_한국어_](README.ko-KR.md) + +En informática, una **lista doblemente enlazada** es una estructura de datos enlazados que consta de un conjunto de registros enlazados secuencialmente llamados nodos. Cada nodo contiene dos campos, llamados enlaces, que son referencias al nodo anterior y al siguiente en la secuencia de nodos. Los enlaces anterior y siguiente de los nodos inicial y final, respectivamente, apuntan a algún tipo de terminador, normalmente un nodo centinela o nulo, para facilitar el recorrido de la lista. Si solo hay un ganglio centinela, la lista se enlaza circularmente a través del ganglio centinela. Puede conceptualizarse como dos listas enlazadas individualmente formadas a partir de los mismos elementos de datos, pero en órdenes secuenciales opuestos. + +![Lista doblemente enlazada](https://upload.wikimedia.org/wikipedia/commons/5/5e/Doubly-linked-list.svg) + +Los dos enlaces de nodo permiten recorrer la lista en cualquier dirección. Si bien agregar o eliminar un nodo en una lista doblemente enlazada requiere cambiar más enlaces que las mismas operaciones en una lista enlazada individualmente, las operaciones son más simples y potencialmente más eficientes (para nodos que no sean los primeros) porque no hay necesidad de realizar un seguimiento de el nodo anterior durante el recorrido o no es necesario recorrer la lista para encontrar el nodo anterior, de modo que se pueda modificar su enlace. + +## Pseudocódigo para operaciones básicas + +### Insertar + +```text +Add(value) + Pre: value is the value to add to the list + Post: value has been placed at the tail of the list + n ← node(value) + if head = ø + head ← n + tail ← n + else + n.previous ← tail + tail.next ← n + tail ← n + end if +end Add +``` + +### Eliminar + +```text +Remove(head, value) + Pre: head is the head node in the list + value is the value to remove from the list + Post: value is removed from the list, true; otherwise false + if head = ø + return false + end if + if value = head.value + if head = tail + head ← ø + tail ← ø + else + head ← head.next + head.previous ← ø + end if + return true + end if + n ← head.next + while n != ø and value !== n.value + n ← n.next + end while + if n = tail + tail ← tail.previous + tail.next ← ø + return true + else if n != ø + n.previous.next ← n.next + n.next.previous ← n.previous + return true + end if + return false +end Remove +``` + +### Recorrido Inverso + +```text +ReverseTraversal(tail) + Pre: tail is the node of the list to traverse + Post: the list has been traversed in reverse order + n ← tail + while n != ø + yield n.value + n ← n.previous + end while +end Reverse Traversal +``` + +## Complejidades + +## Complejidad del Tiempo + +| Acceso | Busqueda | Inserción | Supresión | +| :-------: | :-------: | :-------: | :-------: | +| O(n) | O(n) | O(1) | O(n) | + +### Complejidad del Espacio + +O(n) + +## Referencias + +- [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list) +- [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8) From 22b323e6b112a85210369f48bf9044d9fa9c6371 Mon Sep 17 00:00:00 2001 From: CodingInvoker <71058225+CodingInvoker@users.noreply.github.com> Date: Thu, 6 May 2021 13:02:52 +0800 Subject: [PATCH 091/264] update linkedlist comment (#687) Co-authored-by: Jiachen Zhou Co-authored-by: Oleksii Trekhleb --- src/data-structures/linked-list/LinkedList.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data-structures/linked-list/LinkedList.js b/src/data-structures/linked-list/LinkedList.js index 1fb0b5eaf4..71c2b49755 100644 --- a/src/data-structures/linked-list/LinkedList.js +++ b/src/data-structures/linked-list/LinkedList.js @@ -65,7 +65,7 @@ export default class LinkedList { let deletedNode = null; - // If the head must be deleted then make next node that is differ + // If the head must be deleted then make next node that is different // from the head to be a new head. while (this.head && this.compare.equal(this.head.value, value)) { deletedNode = this.head; From cb50e4e9f394ebaf8172f71bc31dd2f68b1417d4 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Thu, 6 May 2021 07:05:27 +0200 Subject: [PATCH 092/264] Add link to Spanish translation in Doubly-Linked list README. --- .../doubly-linked-list/README.md | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/src/data-structures/doubly-linked-list/README.md b/src/data-structures/doubly-linked-list/README.md index c64b51262d..703520aaf4 100644 --- a/src/data-structures/doubly-linked-list/README.md +++ b/src/data-structures/doubly-linked-list/README.md @@ -4,26 +4,27 @@ _Read this in other languages:_ [_Русский_](README.ru-RU.md), [_简体中文_](README.zh-CN.md), [_日本語_](README.ja-JP.md), -[_Português_](README.pt-BR.md) -[_한국어_](README.ko-KR.md) - -In computer science, a **doubly linked list** is a linked data structure that -consists of a set of sequentially linked records called nodes. Each node contains -two fields, called links, that are references to the previous and to the next -node in the sequence of nodes. The beginning and ending nodes' previous and next -links, respectively, point to some kind of terminator, typically a sentinel -node or null, to facilitate the traversal of the list. If there is only one -sentinel node, then the list is circularly linked via the sentinel node. It can -be conceptualized as two singly linked lists formed from the same data items, +[_Português_](README.pt-BR.md), +[_한국어_](README.ko-KR.md), +[_Español_](README.es-ES.md), + +In computer science, a **doubly linked list** is a linked data structure that +consists of a set of sequentially linked records called nodes. Each node contains +two fields, called links, that are references to the previous and to the next +node in the sequence of nodes. The beginning and ending nodes' previous and next +links, respectively, point to some kind of terminator, typically a sentinel +node or null, to facilitate the traversal of the list. If there is only one +sentinel node, then the list is circularly linked via the sentinel node. It can +be conceptualized as two singly linked lists formed from the same data items, but in opposite sequential orders. ![Doubly Linked List](https://upload.wikimedia.org/wikipedia/commons/5/5e/Doubly-linked-list.svg) -The two node links allow traversal of the list in either direction. While adding -or removing a node in a doubly linked list requires changing more links than the -same operations on a singly linked list, the operations are simpler and -potentially more efficient (for nodes other than first nodes) because there -is no need to keep track of the previous node during traversal or no need +The two node links allow traversal of the list in either direction. While adding +or removing a node in a doubly linked list requires changing more links than the +same operations on a singly linked list, the operations are simpler and +potentially more efficient (for nodes other than first nodes) because there +is no need to keep track of the previous node during traversal or no need to traverse the list to find the previous node, so that its link can be modified. ## Pseudocode for Basic Operations @@ -45,7 +46,7 @@ Add(value) end if end Add ``` - + ### Delete ```text @@ -82,7 +83,7 @@ Remove(head, value) return false end Remove ``` - + ### Reverse Traversal ```text @@ -96,7 +97,7 @@ ReverseTraversal(tail) end while end Reverse Traversal ``` - + ## Complexities ## Time Complexity From 8a24fbfac94dc5d446d51768eaa062637a6c1a16 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Fri, 14 May 2021 09:56:18 +0200 Subject: [PATCH 093/264] Adding more details on how to run the playground code to address the issue #705. --- src/playground/__test__/playground.test.js | 7 +++++-- src/playground/playground.js | 13 ++++++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/playground/__test__/playground.test.js b/src/playground/__test__/playground.test.js index 501a87a728..84a3e8301f 100644 --- a/src/playground/__test__/playground.test.js +++ b/src/playground/__test__/playground.test.js @@ -1,5 +1,8 @@ +import playground from '../playground'; + describe('playground', () => { - it('should perform playground tasks', () => { - // Place your playground tests here. + it('should return correct results', () => { + // Replace the next dummy test with your playground function tests. + expect(playground()).toBe(120); }); }); diff --git a/src/playground/playground.js b/src/playground/playground.js index 7872c9e3b8..b8c5b210bc 100644 --- a/src/playground/playground.js +++ b/src/playground/playground.js @@ -1 +1,12 @@ -// Place your playground code here. +// Import any algorithmic dependencies you need for your playground code here. +import factorial from '../algorithms/math/factorial/factorial'; + +// Write your playground code inside the playground() function. +// Test your code from __tests__/playground.test.js +// Launch playground tests by running: npm test -- 'playground' +function playground() { + // Replace the next line with your playground code. + return factorial(5); +} + +export default playground; From 6d2d8c9379873d0da2b1262a14dd26d0f9779522 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Tue, 18 May 2021 08:44:13 +0200 Subject: [PATCH 094/264] Testing Codecov integration without web-hooks. --- src/utils/comparator/Comparator.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils/comparator/Comparator.js b/src/utils/comparator/Comparator.js index 12957d2d73..f5c41b5c18 100644 --- a/src/utils/comparator/Comparator.js +++ b/src/utils/comparator/Comparator.js @@ -1,5 +1,6 @@ export default class Comparator { /** + * Constructor. * @param {function(a: *, b: *)} [compareFunction] - It may be custom compare function that, let's * say may compare custom objects together. */ From ee35bd6240af55d3353934cb50261c9e256d1326 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 26 May 2021 10:29:05 +0200 Subject: [PATCH 095/264] Testing Codecov integration without web-hooks. --- README.ar-AR.md | 2 ++ README.de-DE.md | 3 +++ README.es-ES.md | 2 ++ README.fr-FR.md | 1 + README.id-ID.md | 2 ++ README.it-IT.md | 2 ++ README.ja-JP.md | 2 ++ README.ko-KR.md | 2 ++ README.md | 2 ++ README.pl-PL.md | 2 ++ README.pt-BR.md | 2 ++ README.ru-RU.md | 2 ++ README.tr-TR.md | 2 ++ README.uk-UA.md | 2 ++ README.zh-CN.md | 2 ++ README.zh-TW.md | 2 ++ 16 files changed, 32 insertions(+) diff --git a/README.ar-AR.md b/README.ar-AR.md index 797006b6ef..3514bce12f 100644 --- a/README.ar-AR.md +++ b/README.ar-AR.md @@ -321,3 +321,5 @@ npm test -- 'playground' > يمكنك دعم هذا المشروع عبر ❤️️ [GitHub](https://github.com/sponsors/trekhleb) أو ❤️️ [Patreon](https://www.patreon.com/trekhleb). [الناس الذين يدعمون هذا المشروع](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0` + +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.de-DE.md b/README.de-DE.md index 3e127c3ea0..bd250ab3b0 100644 --- a/README.de-DE.md +++ b/README.de-DE.md @@ -331,3 +331,6 @@ Nachfolgend finden Sie eine Liste einiger der am häufigsten verwendeten Big O-N > Du kannst dieses Projekt unterstützen über ❤️️ [GitHub](https://github.com/sponsors/trekhleb) or ❤️️ [Patreon](https://www.patreon.com/trekhleb). [Leute, die dieses Projekt unterstützen](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0` + +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) + diff --git a/README.es-ES.md b/README.es-ES.md index f350ee059e..b5246bd61d 100644 --- a/README.es-ES.md +++ b/README.es-ES.md @@ -299,3 +299,5 @@ frente a diferentes tamaños de los datos de entrada. | **Shellsort** | n log(n) | depende de la secuencia de huecos | n (log(n))2 | 1 | No | | | **Ordenamiento por cuentas** | n + r | n + r | n + r | n + r | Si | r - mayor número en el arreglo | | **Ordenamiento Radix** | n \* k | n \* k | n \* k | n + k | Si | k - largo de la llave más larga | + +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.fr-FR.md b/README.fr-FR.md index 4508340aec..aa7a9007a3 100644 --- a/README.fr-FR.md +++ b/README.fr-FR.md @@ -293,3 +293,4 @@ comparaisons de performance suivant différentes tailles pour les données d'ent | **Tri Shell** | n log(n) | dépend du gap séquence | n (log(n))2 | 1 | Non | | | **Tri Comptage** | n + r | n + r | n + r | n + r | Oui | r - le plus grand nombre dans la liste | | **Tri Radix** | n \* k | n \* k | n \* k | n + k | Non | k - longueur du plus long index | +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.id-ID.md b/README.id-ID.md index 2f5212ac64..f1ad648258 100644 --- a/README.id-ID.md +++ b/README.id-ID.md @@ -304,3 +304,5 @@ Di bawah ini adalah daftar dari beberapa notasi _Bog O_ yang sering digunakan da > Anda dapat mendukung proyek ini via ❤️️ [GitHub](https://github.com/sponsors/trekhleb) atau ❤️️ [Patreon](https://www.patreon.com/trekhleb). [Orang-orang yang mendukung proyek ini](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1` + +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.it-IT.md b/README.it-IT.md index d74befd683..5947b92e75 100644 --- a/README.it-IT.md +++ b/README.it-IT.md @@ -297,3 +297,5 @@ Nella tabella qua sotto ci sono riportate la lista delle notazioni Big O più us | **Shell sort** | n log(n) | dipende dagli spazi vuoti nella sequenza | n (log(n))2 | 1 | No | | | **Counting sort** | n + r | n + r | n + r | n + r | Yes | r - numero più grande nell'array | | **Radix sort** | n * k | n * k | n * k | n + k | Yes | k - lunghezza della chiave più grande | + +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.ja-JP.md b/README.ja-JP.md index a1c13211a0..30a9979908 100644 --- a/README.ja-JP.md +++ b/README.ja-JP.md @@ -296,3 +296,5 @@ npm test -- 'playground' | **Shell sort** | n log(n) | depends on gap sequence | n (log(n))2 | 1 | No | | | **Counting sort** | n + r | n + r | n + r | n + r | Yes | r - biggest number in array | | **Radix sort** | n * k | n * k | n * k | n + k | Yes | k - length of longest key | + +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.ko-KR.md b/README.ko-KR.md index e9b77dca27..8bdb98b837 100644 --- a/README.ko-KR.md +++ b/README.ko-KR.md @@ -277,3 +277,5 @@ Source: [Big O Cheat Sheet](http://bigocheatsheet.com/). | **셸 정렬** | n log(n) | 간격 순서에 영향을 받습니다. | n (log(n))2 | 1 | No | | | **계수 정렬** | n + r | n + r | n + r | n + r | Yes | r - 배열내 가장 큰 수 | | **기수 정렬** | n * k | n * k | n * k | n + k | Yes | k - 키값의 최대 길이 | + +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.md b/README.md index d16c264d1e..a589d710e1 100644 --- a/README.md +++ b/README.md @@ -343,3 +343,5 @@ Below is the list of some of the most used Big O notations and their performance > You may support this project via ❤️️ [GitHub](https://github.com/sponsors/trekhleb) or ❤️️ [Patreon](https://www.patreon.com/trekhleb). [Folks who are backing this project](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0` + +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.pl-PL.md b/README.pl-PL.md index 235d0d47d6..cc20e947e7 100644 --- a/README.pl-PL.md +++ b/README.pl-PL.md @@ -289,3 +289,5 @@ Poniżej umieszczamy listę najbardziej używanych Big O notacji i ich porównan | **Sortowanie Shella** | n log(n) | zależy od luki w układzie | n (log(n))2 | 1 | No | | | **Sortowanie przez zliczanie** | n + r | n + r | n + r | n + r | Yes | r - największy numer w tablicy| | **Sortowanie Radix** | n * k | n * k | n * k | n + k | Yes | k -długość najdłuższego klucza | + +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.pt-BR.md b/README.pt-BR.md index c410fda651..cc3b9f2191 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -290,3 +290,5 @@ Abaixo está a lista de algumas das notações Big O mais usadas e suas compara | **Shell sort** | n log(n) | depende da sequência de lacunas | n (log(n))2 | 1 | Não | | | **Counting sort** | n + r | n + r | n + r | n + r | Sim | r - maior número na matriz | | **Radix sort** | n * k | n * k | n * k | n + k | Sim | k - comprimento da chave mais longa | + +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.ru-RU.md b/README.ru-RU.md index ef9e9444a3..d5c2c69c6f 100644 --- a/README.ru-RU.md +++ b/README.ru-RU.md @@ -295,3 +295,5 @@ npm test -- 'playground' | **Сортировка Шелла** | n log(n) | зависит от выбранных шагов | n (log(n))2 | 1 | Нет | | | **Сортировка подсчётом** | n + r | n + r | n + r | n + r | Да | r — наибольшее число в массиве | | **Поразрядная сортировка** | n * k | n * k | n * k | n + k | Да | k — длина самого длинного ключа | + +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.tr-TR.md b/README.tr-TR.md index fff640c415..73f3077e1e 100644 --- a/README.tr-TR.md +++ b/README.tr-TR.md @@ -315,3 +315,5 @@ Altta Big O notations ve farklı input boyutlarına karşın yapılmış perform ## Projeyi Destekleme Bu projeyi buradan destekleyebilirsiniz ❤️️ [GitHub](https://github.com/sponsors/trekhleb) veya ❤️️ [Patreon](https://www.patreon.com/trekhleb). + +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.uk-UA.md b/README.uk-UA.md index 6fdd7b4c13..be4d923b70 100644 --- a/README.uk-UA.md +++ b/README.uk-UA.md @@ -305,3 +305,5 @@ npm test -- 'playground' > Ви можете підтримати цей проект через ❤️️ [GitHub](https://github.com/sponsors/trekhleb) або ❤️️ [Patreon](https://www.patreon.com/trekhleb). [Люди, які підтримують цей проект](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1` + +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.zh-CN.md b/README.zh-CN.md index 22b50d405c..1425f87993 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -292,3 +292,5 @@ npm test -- 'playground' | **希尔排序** | n log(n) | 取决于差距序列 | n (log(n))^2 | 1 | No | | | **计数排序** | n + r | n + r | n + r | n + r | Yes | r - 数组里最大的数 | | **基数排序** | n * k | n * k | n * k | n + k | Yes | k - 最长 key 的升序 | + +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.zh-TW.md b/README.zh-TW.md index ddf043d7af..10b6e84f08 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -222,3 +222,5 @@ npm test -- 'playground' | **合併排序** | n log(n) | n log(n) | n log(n) | n | Yes | | **快速排序** | n log(n) | n log(n) | n^2 | log(n) | No | | **希爾排序** | n log(n) | 由gap sequence決定 | n (log(n))^2 | 1 | No | + +> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) From 433515f1b22a1a53443429b20f09f821a3325895 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Wed, 26 May 2021 10:55:57 +0200 Subject: [PATCH 096/264] Fix typo in READMEs. --- README.ar-AR.md | 2 +- README.de-DE.md | 2 +- README.es-ES.md | 2 +- README.fr-FR.md | 3 ++- README.id-ID.md | 2 +- README.it-IT.md | 2 +- README.ja-JP.md | 2 +- README.ko-KR.md | 2 +- README.md | 2 +- README.pl-PL.md | 2 +- README.pt-BR.md | 2 +- README.ru-RU.md | 2 +- README.tr-TR.md | 2 +- README.uk-UA.md | 2 +- README.zh-CN.md | 2 +- README.zh-TW.md | 2 +- 16 files changed, 17 insertions(+), 16 deletions(-) diff --git a/README.ar-AR.md b/README.ar-AR.md index 3514bce12f..07522e78a6 100644 --- a/README.ar-AR.md +++ b/README.ar-AR.md @@ -322,4 +322,4 @@ npm test -- 'playground' [الناس الذين يدعمون هذا المشروع](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0` -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.de-DE.md b/README.de-DE.md index bd250ab3b0..b34ad3563f 100644 --- a/README.de-DE.md +++ b/README.de-DE.md @@ -332,5 +332,5 @@ Nachfolgend finden Sie eine Liste einiger der am häufigsten verwendeten Big O-N [Leute, die dieses Projekt unterstützen](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0` -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.es-ES.md b/README.es-ES.md index b5246bd61d..6f5db59bb8 100644 --- a/README.es-ES.md +++ b/README.es-ES.md @@ -300,4 +300,4 @@ frente a diferentes tamaños de los datos de entrada. | **Ordenamiento por cuentas** | n + r | n + r | n + r | n + r | Si | r - mayor número en el arreglo | | **Ordenamiento Radix** | n \* k | n \* k | n \* k | n + k | Si | k - largo de la llave más larga | -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.fr-FR.md b/README.fr-FR.md index aa7a9007a3..59087825ff 100644 --- a/README.fr-FR.md +++ b/README.fr-FR.md @@ -293,4 +293,5 @@ comparaisons de performance suivant différentes tailles pour les données d'ent | **Tri Shell** | n log(n) | dépend du gap séquence | n (log(n))2 | 1 | Non | | | **Tri Comptage** | n + r | n + r | n + r | n + r | Oui | r - le plus grand nombre dans la liste | | **Tri Radix** | n \* k | n \* k | n \* k | n + k | Non | k - longueur du plus long index | -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) + +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.id-ID.md b/README.id-ID.md index f1ad648258..01d539c5ef 100644 --- a/README.id-ID.md +++ b/README.id-ID.md @@ -305,4 +305,4 @@ Di bawah ini adalah daftar dari beberapa notasi _Bog O_ yang sering digunakan da [Orang-orang yang mendukung proyek ini](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1` -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.it-IT.md b/README.it-IT.md index 5947b92e75..b459ac87d1 100644 --- a/README.it-IT.md +++ b/README.it-IT.md @@ -298,4 +298,4 @@ Nella tabella qua sotto ci sono riportate la lista delle notazioni Big O più us | **Counting sort** | n + r | n + r | n + r | n + r | Yes | r - numero più grande nell'array | | **Radix sort** | n * k | n * k | n * k | n + k | Yes | k - lunghezza della chiave più grande | -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.ja-JP.md b/README.ja-JP.md index 30a9979908..44b6b6c13e 100644 --- a/README.ja-JP.md +++ b/README.ja-JP.md @@ -297,4 +297,4 @@ npm test -- 'playground' | **Counting sort** | n + r | n + r | n + r | n + r | Yes | r - biggest number in array | | **Radix sort** | n * k | n * k | n * k | n + k | Yes | k - length of longest key | -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.ko-KR.md b/README.ko-KR.md index 8bdb98b837..040ac8a57d 100644 --- a/README.ko-KR.md +++ b/README.ko-KR.md @@ -278,4 +278,4 @@ Source: [Big O Cheat Sheet](http://bigocheatsheet.com/). | **계수 정렬** | n + r | n + r | n + r | n + r | Yes | r - 배열내 가장 큰 수 | | **기수 정렬** | n * k | n * k | n * k | n + k | Yes | k - 키값의 최대 길이 | -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.md b/README.md index a589d710e1..b8e2be362a 100644 --- a/README.md +++ b/README.md @@ -344,4 +344,4 @@ Below is the list of some of the most used Big O notations and their performance [Folks who are backing this project](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 0` -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.pl-PL.md b/README.pl-PL.md index cc20e947e7..51777b0da2 100644 --- a/README.pl-PL.md +++ b/README.pl-PL.md @@ -290,4 +290,4 @@ Poniżej umieszczamy listę najbardziej używanych Big O notacji i ich porównan | **Sortowanie przez zliczanie** | n + r | n + r | n + r | n + r | Yes | r - największy numer w tablicy| | **Sortowanie Radix** | n * k | n * k | n * k | n + k | Yes | k -długość najdłuższego klucza | -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.pt-BR.md b/README.pt-BR.md index cc3b9f2191..68b7e1721f 100644 --- a/README.pt-BR.md +++ b/README.pt-BR.md @@ -291,4 +291,4 @@ Abaixo está a lista de algumas das notações Big O mais usadas e suas compara | **Counting sort** | n + r | n + r | n + r | n + r | Sim | r - maior número na matriz | | **Radix sort** | n * k | n * k | n * k | n + k | Sim | k - comprimento da chave mais longa | -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.ru-RU.md b/README.ru-RU.md index d5c2c69c6f..6200aedd53 100644 --- a/README.ru-RU.md +++ b/README.ru-RU.md @@ -296,4 +296,4 @@ npm test -- 'playground' | **Сортировка подсчётом** | n + r | n + r | n + r | n + r | Да | r — наибольшее число в массиве | | **Поразрядная сортировка** | n * k | n * k | n * k | n + k | Да | k — длина самого длинного ключа | -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.tr-TR.md b/README.tr-TR.md index 73f3077e1e..0dd0ee3bf2 100644 --- a/README.tr-TR.md +++ b/README.tr-TR.md @@ -316,4 +316,4 @@ Altta Big O notations ve farklı input boyutlarına karşın yapılmış perform Bu projeyi buradan destekleyebilirsiniz ❤️️ [GitHub](https://github.com/sponsors/trekhleb) veya ❤️️ [Patreon](https://www.patreon.com/trekhleb). -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.uk-UA.md b/README.uk-UA.md index be4d923b70..b43da83ca6 100644 --- a/README.uk-UA.md +++ b/README.uk-UA.md @@ -306,4 +306,4 @@ npm test -- 'playground' [Люди, які підтримують цей проект](https://github.com/trekhleb/javascript-algorithms/blob/master/BACKERS.md) `∑ = 1` -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.zh-CN.md b/README.zh-CN.md index 1425f87993..8bf216d6bd 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -293,4 +293,4 @@ npm test -- 'playground' | **计数排序** | n + r | n + r | n + r | n + r | Yes | r - 数组里最大的数 | | **基数排序** | n * k | n * k | n * k | n + k | Yes | k - 最长 key 的升序 | -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) diff --git a/README.zh-TW.md b/README.zh-TW.md index 10b6e84f08..e42aba445d 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md @@ -223,4 +223,4 @@ npm test -- 'playground' | **快速排序** | n log(n) | n log(n) | n^2 | log(n) | No | | **希爾排序** | n log(n) | 由gap sequence決定 | n (log(n))^2 | 1 | No | -> ℹ️ Some more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) +> ℹ️ A few more [projects](https://trekhleb.dev/projects/) and [articles](https://trekhleb.dev/blog/) about JavaScript and algorithms on [trekhleb.dev](https://trekhleb.dev) From b2d1ec83f04a66d9d2d3f09150bcaf0cacb0f7ba Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Fri, 16 Jul 2021 11:51:53 +0200 Subject: [PATCH 097/264] Binary representation of floating-point numbers (#737) * Add "Binary representation of floating point numbers" section. * Adding a half-precision explanatory picture. * Binary representation of the floating-point numbers. --- README.md | 1 + .../math/binary-floating-point/README.md | 93 ++++++++++++++ .../__tests__/bitsToFloat.test.js | 32 +++++ .../__tests__/floatAsBinaryString.test.js | 20 +++ .../math/binary-floating-point/bitsToFloat.js | 119 ++++++++++++++++++ .../floatAsBinaryString.js | 61 +++++++++ ...cision-floating-point-number-explained.png | Bin 0 -> 352613 bytes .../images/03-scientific-notation.png | Bin 0 -> 76251 bytes .../math/binary-floating-point/testCases.js | 71 +++++++++++ 9 files changed, 397 insertions(+) create mode 100644 src/algorithms/math/binary-floating-point/README.md create mode 100644 src/algorithms/math/binary-floating-point/__tests__/bitsToFloat.test.js create mode 100644 src/algorithms/math/binary-floating-point/__tests__/floatAsBinaryString.test.js create mode 100644 src/algorithms/math/binary-floating-point/bitsToFloat.js create mode 100644 src/algorithms/math/binary-floating-point/floatAsBinaryString.js create mode 100644 src/algorithms/math/binary-floating-point/images/02-half-precision-floating-point-number-explained.png create mode 100644 src/algorithms/math/binary-floating-point/images/03-scientific-notation.png create mode 100644 src/algorithms/math/binary-floating-point/testCases.js diff --git a/README.md b/README.md index b8e2be362a..d00945e5a5 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ a set of rules that precisely define a sequence of operations. * **Math** * `B` [Bit Manipulation](src/algorithms/math/bits) - set/get/update/clear bits, multiplication/division by two, make negative etc. + * `B` [Binary Floating Point](src/algorithms/math/binary-floating-point) - binary representation of the floating-point numbers. * `B` [Factorial](src/algorithms/math/factorial) * `B` [Fibonacci Number](src/algorithms/math/fibonacci) - classic and closed-form versions * `B` [Prime Factors](src/algorithms/math/prime-factors) - finding prime factors and counting them using Hardy-Ramanujan's theorem diff --git a/src/algorithms/math/binary-floating-point/README.md b/src/algorithms/math/binary-floating-point/README.md new file mode 100644 index 0000000000..2851902845 --- /dev/null +++ b/src/algorithms/math/binary-floating-point/README.md @@ -0,0 +1,93 @@ +# Binary representation of floating-point numbers + +Have you ever wondered how computers store the floating-point numbers like `3.1415` (𝝿) or `9.109 × 10⁻³¹` (the mass of the electron in kg) in the memory which is limited by a finite number of ones and zeroes (aka bits)? + +It seems pretty straightforward for integers (i.e. `17`). Let's say we have 16 bits (2 bytes) to store the number. In 16 bits we may store the integers in a range of `[0, 65535]`: + +```text +(0000000000000000)₂ = (0)₁₀ + +(0000000000010001)₂ = + (1 × 2⁴) + + (0 × 2³) + + (0 × 2²) + + (0 × 2¹) + + (1 × 2⁰) = (17)₁₀ + +(1111111111111111)₂ = + (1 × 2¹⁵) + + (1 × 2¹⁴) + + (1 × 2¹³) + + (1 × 2¹²) + + (1 × 2¹¹) + + (1 × 2¹⁰) + + (1 × 2⁹) + + (1 × 2⁸) + + (1 × 2⁷) + + (1 × 2⁶) + + (1 × 2⁵) + + (1 × 2⁴) + + (1 × 2³) + + (1 × 2²) + + (1 × 2¹) + + (1 × 2⁰) = (65535)₁₀ +``` + +If we need a signed integer we may use [two's complement](https://en.wikipedia.org/wiki/Two%27s_complement) and shift the range of `[0, 65535]` towards the negative numbers. In this case, our 16 bits would represent the numbers in a range of `[-32768, +32767]`. + +As you might have noticed, this approach won't allow you to represent the numbers like `-27.15625` (numbers after the decimal point are just being ignored). + +We're not the first ones who have noticed this issue though. Around ≈36 years ago some smart folks overcame this limitation by introducing the [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) standard for floating-point arithmetic. + +The IEEE 754 standard describes the way (the framework) of using those 16 bits (or 32, or 64 bits) to store the numbers of wider range, including the small floating numbers (smaller than 1 and closer to 0). + +To get the idea behind the standard we might recall the [scientific notation](https://en.wikipedia.org/wiki/Scientific_notation) - a way of expressing numbers that are too large or too small (usually would result in a long string of digits) to be conveniently written in decimal form. + +![Scientific number notation](images/03-scientific-notation.png) + +As you may see from the image, the number representation might be split into three parts: + +- **sign** +- **fraction (aka significand)** - the valuable digits (the meaning, the payload) of the number +- **exponent** - controls how far and in which direction to move the decimal point in the fraction + +The **base** part we may omit by just agreeing on what it will be equal to. In our case, we'll be using `2` as a base. + +Instead of using all 16 bits (or 32 bits, or 64 bits) to store the fraction of the number, we may share the bits and store a sign, exponent, and fraction at the same time. Depending on the number of bits that we're going to use to store the number we end up with the following splits: + +| Floating-point format | Total bits | Sign bits | Exponent bits | Fraction bits | Base | +| :-------------------- | :--------: | :-------: | :-----------: | :--------------: | :--: | +| [Half-precision](https://en.wikipedia.org/wiki/Half-precision_floating-point_format) | 16 | 1 | 5 | 10 | 2 | +| [Single-precision](https://en.wikipedia.org/wiki/Single-precision_floating-point_format) | 32 | 1 | 8 | 23 | 2 | +| [Double-precision](https://en.wikipedia.org/wiki/Double-precision_floating-point_format) | 64 | 1 | 11 | 52 | 2 | + +With this approach, the number of bits for the fraction has been reduced (i.e. for the 16-bits number it was reduced from 16 bits to 10 bits). It means that the fraction might take a narrower range of values now (losing some precision). However, since we also have an exponent part, it will actually increase the ultimate number range and also allow us to describe the numbers between 0 and 1 (if the exponent is negative). + +> For example, a signed 32-bit integer variable has a maximum value of 2³¹ − 1 = 2,147,483,647, whereas an IEEE 754 32-bit base-2 floating-point variable has a maximum value of ≈ 3.4028235 × 10³⁸. + +To make it possible to have a negative exponent, the IEEE 754 standard uses the [biased exponent](https://en.wikipedia.org/wiki/Exponent_bias). The idea is simple - subtract the bias from the exponent value to make it negative. For example, if the exponent has 5 bits, it might take the values from the range of `[0, 31]` (all values are positive here). But if we subtract the value of `15` from it, the range will be `[-15, 16]`. The number `15` is called bias, and it is being calculated by the following formula: + +``` +exponent_bias = 2 ^ (k−1) − 1 + +k - number of exponent bits +``` + +I've tried to describe the logic behind the converting of floating-point numbers from a binary format back to the decimal format on the image below. Hopefully, it will give you a better understanding of how the IEEE 754 standard works. The 16-bits number is being used here for simplicity, but the same approach works for 32-bits and 64-bits numbers as well. + +![Half-precision floating point number format explained in one picture](images/02-half-precision-floating-point-number-explained.png) + +> Checkout the [interactive version of this diagram](https://trekhleb.dev/blog/2021/binary-floating-point/) to play around with setting bits on and off, and seeing how it would influence the final result + +## Code examples + +- See the [bitsToFloat.js](bitsToFloat.js) for the example of how to convert array of bits to the floating point number (the example is a bit artificial but still it gives the overview of how the conversion is going on) +- See the [floatAsBinaryString.js](floatAsBinaryString.js) for the example of how to see the actual binary representation of the floating-point number in JavaScript + +## References + +You might also want to check out the following resources to get a deeper understanding of the binary representation of floating-point numbers: + +- [Here is what you need to know about JavaScript’s Number type](https://indepth.dev/posts/1139/here-is-what-you-need-to-know-about-javascripts-number-type) +- [Float Exposed](https://float.exposed/) +- [IEEE754 Visualization](https://bartaz.github.io/ieee754-visualization/) diff --git a/src/algorithms/math/binary-floating-point/__tests__/bitsToFloat.test.js b/src/algorithms/math/binary-floating-point/__tests__/bitsToFloat.test.js new file mode 100644 index 0000000000..53afe691a2 --- /dev/null +++ b/src/algorithms/math/binary-floating-point/__tests__/bitsToFloat.test.js @@ -0,0 +1,32 @@ +import { testCases16Bits, testCases32Bits, testCases64Bits } from '../testCases'; +import { bitsToFloat16, bitsToFloat32, bitsToFloat64 } from '../bitsToFloat'; + +describe('bitsToFloat16', () => { + it('should convert floating point binary bits to floating point decimal number', () => { + for (let testCaseIndex = 0; testCaseIndex < testCases16Bits.length; testCaseIndex += 1) { + const [decimal, binary] = testCases16Bits[testCaseIndex]; + const bits = binary.split('').map((bitString) => parseInt(bitString, 10)); + expect(bitsToFloat16(bits)).toBeCloseTo(decimal, 4); + } + }); +}); + +describe('bitsToFloat32', () => { + it('should convert floating point binary bits to floating point decimal number', () => { + for (let testCaseIndex = 0; testCaseIndex < testCases32Bits.length; testCaseIndex += 1) { + const [decimal, binary] = testCases32Bits[testCaseIndex]; + const bits = binary.split('').map((bitString) => parseInt(bitString, 10)); + expect(bitsToFloat32(bits)).toBeCloseTo(decimal, 7); + } + }); +}); + +describe('bitsToFloat64', () => { + it('should convert floating point binary bits to floating point decimal number', () => { + for (let testCaseIndex = 0; testCaseIndex < testCases64Bits.length; testCaseIndex += 1) { + const [decimal, binary] = testCases64Bits[testCaseIndex]; + const bits = binary.split('').map((bitString) => parseInt(bitString, 10)); + expect(bitsToFloat64(bits)).toBeCloseTo(decimal, 14); + } + }); +}); diff --git a/src/algorithms/math/binary-floating-point/__tests__/floatAsBinaryString.test.js b/src/algorithms/math/binary-floating-point/__tests__/floatAsBinaryString.test.js new file mode 100644 index 0000000000..efb8a2ba5e --- /dev/null +++ b/src/algorithms/math/binary-floating-point/__tests__/floatAsBinaryString.test.js @@ -0,0 +1,20 @@ +import { floatAs32BinaryString, floatAs64BinaryString } from '../floatAsBinaryString'; +import { testCases32Bits, testCases64Bits } from '../testCases'; + +describe('floatAs32Binary', () => { + it('should create a binary representation of the floating numbers', () => { + for (let testCaseIndex = 0; testCaseIndex < testCases32Bits.length; testCaseIndex += 1) { + const [decimal, binary] = testCases32Bits[testCaseIndex]; + expect(floatAs32BinaryString(decimal)).toBe(binary); + } + }); +}); + +describe('floatAs64Binary', () => { + it('should create a binary representation of the floating numbers', () => { + for (let testCaseIndex = 0; testCaseIndex < testCases64Bits.length; testCaseIndex += 1) { + const [decimal, binary] = testCases64Bits[testCaseIndex]; + expect(floatAs64BinaryString(decimal)).toBe(binary); + } + }); +}); diff --git a/src/algorithms/math/binary-floating-point/bitsToFloat.js b/src/algorithms/math/binary-floating-point/bitsToFloat.js new file mode 100644 index 0000000000..6d1ef0d851 --- /dev/null +++ b/src/algorithms/math/binary-floating-point/bitsToFloat.js @@ -0,0 +1,119 @@ +/** + * Sequence of 0s and 1s. + * @typedef {number[]} Bits + */ + +/** + * @typedef {{ + * signBitsCount: number, + * exponentBitsCount: number, + * fractionBitsCount: number, + * }} PrecisionConfig + */ + +/** + * @typedef {{ + * half: PrecisionConfig, + * single: PrecisionConfig, + * double: PrecisionConfig + * }} PrecisionConfigs + */ + +/** + * ┌───────────────── sign bit + * │ ┌───────────── exponent bits + * │ │ ┌───── fraction bits + * │ │ │ + * X XXXXX XXXXXXXXXX + * + * @type {PrecisionConfigs} + */ +const precisionConfigs = { + // @see: https://en.wikipedia.org/wiki/Half-precision_floating-point_format + half: { + signBitsCount: 1, + exponentBitsCount: 5, + fractionBitsCount: 10, + }, + // @see: https://en.wikipedia.org/wiki/Single-precision_floating-point_format + single: { + signBitsCount: 1, + exponentBitsCount: 8, + fractionBitsCount: 23, + }, + // @see: https://en.wikipedia.org/wiki/Double-precision_floating-point_format + double: { + signBitsCount: 1, + exponentBitsCount: 11, + fractionBitsCount: 52, + }, +}; + +/** + * Converts the binary representation of the floating point number to decimal float number. + * + * @param {Bits} bits - sequence of bits that represents the floating point number. + * @param {PrecisionConfig} precisionConfig - half/single/double precision config. + * @return {number} - floating point number decoded from its binary representation. + */ +function bitsToFloat(bits, precisionConfig) { + const { signBitsCount, exponentBitsCount } = precisionConfig; + + // Figuring out the sign. + const sign = (-1) ** bits[0]; // -1^1 = -1, -1^0 = 1 + + // Calculating the exponent value. + const exponentBias = 2 ** (exponentBitsCount - 1) - 1; + const exponentBits = bits.slice(signBitsCount, signBitsCount + exponentBitsCount); + const exponentUnbiased = exponentBits.reduce( + (exponentSoFar, currentBit, bitIndex) => { + const bitPowerOfTwo = 2 ** (exponentBitsCount - bitIndex - 1); + return exponentSoFar + currentBit * bitPowerOfTwo; + }, + 0, + ); + const exponent = exponentUnbiased - exponentBias; + + // Calculating the fraction value. + const fractionBits = bits.slice(signBitsCount + exponentBitsCount); + const fraction = fractionBits.reduce( + (fractionSoFar, currentBit, bitIndex) => { + const bitPowerOfTwo = 2 ** -(bitIndex + 1); + return fractionSoFar + currentBit * bitPowerOfTwo; + }, + 0, + ); + + // Putting all parts together to calculate the final number. + return sign * (2 ** exponent) * (1 + fraction); +} + +/** + * Converts the 16-bit binary representation of the floating point number to decimal float number. + * + * @param {Bits} bits - sequence of bits that represents the floating point number. + * @return {number} - floating point number decoded from its binary representation. + */ +export function bitsToFloat16(bits) { + return bitsToFloat(bits, precisionConfigs.half); +} + +/** + * Converts the 32-bit binary representation of the floating point number to decimal float number. + * + * @param {Bits} bits - sequence of bits that represents the floating point number. + * @return {number} - floating point number decoded from its binary representation. + */ +export function bitsToFloat32(bits) { + return bitsToFloat(bits, precisionConfigs.single); +} + +/** + * Converts the 64-bit binary representation of the floating point number to decimal float number. + * + * @param {Bits} bits - sequence of bits that represents the floating point number. + * @return {number} - floating point number decoded from its binary representation. + */ +export function bitsToFloat64(bits) { + return bitsToFloat(bits, precisionConfigs.double); +} diff --git a/src/algorithms/math/binary-floating-point/floatAsBinaryString.js b/src/algorithms/math/binary-floating-point/floatAsBinaryString.js new file mode 100644 index 0000000000..aa907ac049 --- /dev/null +++ b/src/algorithms/math/binary-floating-point/floatAsBinaryString.js @@ -0,0 +1,61 @@ +// @see: https://en.wikipedia.org/wiki/Single-precision_floating-point_format +const singlePrecisionBytesLength = 4; // 32 bits + +// @see: https://en.wikipedia.org/wiki/Double-precision_floating-point_format +const doublePrecisionBytesLength = 8; // 64 bits + +const bitsInByte = 8; + +/** + * Converts the float number into its IEEE 754 binary representation. + * @see: https://en.wikipedia.org/wiki/IEEE_754 + * + * @param {number} floatNumber - float number in decimal format. + * @param {number} byteLength - number of bytes to use to store the float number. + * @return {string} - binary string representation of the float number. + */ +function floatAsBinaryString(floatNumber, byteLength) { + let numberAsBinaryString = ''; + + const arrayBuffer = new ArrayBuffer(byteLength); + const dataView = new DataView(arrayBuffer); + + const byteOffset = 0; + const littleEndian = false; + + if (byteLength === singlePrecisionBytesLength) { + dataView.setFloat32(byteOffset, floatNumber, littleEndian); + } else { + dataView.setFloat64(byteOffset, floatNumber, littleEndian); + } + + for (let byteIndex = 0; byteIndex < byteLength; byteIndex += 1) { + let bits = dataView.getUint8(byteIndex).toString(2); + if (bits.length < bitsInByte) { + bits = new Array(bitsInByte - bits.length).fill('0').join('') + bits; + } + numberAsBinaryString += bits; + } + + return numberAsBinaryString; +} + +/** + * Converts the float number into its IEEE 754 64-bits binary representation. + * + * @param {number} floatNumber - float number in decimal format. + * @return {string} - 64 bits binary string representation of the float number. + */ +export function floatAs64BinaryString(floatNumber) { + return floatAsBinaryString(floatNumber, doublePrecisionBytesLength); +} + +/** + * Converts the float number into its IEEE 754 32-bits binary representation. + * + * @param {number} floatNumber - float number in decimal format. + * @return {string} - 32 bits binary string representation of the float number. + */ +export function floatAs32BinaryString(floatNumber) { + return floatAsBinaryString(floatNumber, singlePrecisionBytesLength); +} diff --git a/src/algorithms/math/binary-floating-point/images/02-half-precision-floating-point-number-explained.png b/src/algorithms/math/binary-floating-point/images/02-half-precision-floating-point-number-explained.png new file mode 100644 index 0000000000000000000000000000000000000000..1bc0a5b83596b9479525362d67af1dfb5168ef70 GIT binary patch literal 352613 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

&eX$vFDz3>({GKR?|8jeJ~nrYRr-g^<+j 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
!<{-7gQua#Wkb~y_nd!3&8PO!6gT$2r&M7; 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�umf(!rc@!gG^JXQ}6#U{oInvxH6DG=^nUX15 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�>M9;HiE~$9Er~yGc(j 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%0DMYGVLC&V9`*0XxFZrQ0C{rr63J7yZyC>bupF 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 c&DU>o^DHIT Date: Fri, 16 Jul 2021 14:39:35 +0200 Subject: [PATCH 098/264] Binary representation of the floating-point numbers. --- src/algorithms/math/binary-floating-point/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/algorithms/math/binary-floating-point/README.md b/src/algorithms/math/binary-floating-point/README.md index 2851902845..32b41f642a 100644 --- a/src/algorithms/math/binary-floating-point/README.md +++ b/src/algorithms/math/binary-floating-point/README.md @@ -1,6 +1,6 @@ # Binary representation of floating-point numbers -Have you ever wondered how computers store the floating-point numbers like `3.1415` (𝝿) or `9.109 × 10⁻³¹` (the mass of the electron in kg) in the memory which is limited by a finite number of ones and zeroes (aka bits)? +Have you ever wondered how computers store the floating-point numbers like `3.1416` (𝝿) or `9.109 × 10⁻³¹` (the mass of the electron in kg) in the memory which is limited by a finite number of ones and zeroes (aka bits)? It seems pretty straightforward for integers (i.e. `17`). Let's say we have 16 bits (2 bytes) to store the number. In 16 bits we may store the integers in a range of `[0, 65535]`: From 71da6df63312096964eaaf8f538c174d1c39014b Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Mon, 26 Jul 2021 07:43:07 +0200 Subject: [PATCH 099/264] Binary representation of the floating-point numbers. --- src/algorithms/math/binary-floating-point/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/algorithms/math/binary-floating-point/README.md b/src/algorithms/math/binary-floating-point/README.md index 32b41f642a..c0c6fce046 100644 --- a/src/algorithms/math/binary-floating-point/README.md +++ b/src/algorithms/math/binary-floating-point/README.md @@ -79,6 +79,8 @@ I've tried to describe the logic behind the converting of floating-point numbers > Checkout the [interactive version of this diagram](https://trekhleb.dev/blog/2021/binary-floating-point/) to play around with setting bits on and off, and seeing how it would influence the final result +Be aware that this is by no means a complete and sufficient overview of the IEEE 754 standard. It is rather a simplified and basic overview. Several corner cases were omitted in the examples above for simplicity of presentation (i.e. `-0`, `-∞`, `+∞` and `NaN` (not a number) values) + ## Code examples - See the [bitsToFloat.js](bitsToFloat.js) for the example of how to convert array of bits to the floating point number (the example is a bit artificial but still it gives the overview of how the conversion is going on) From 2ad5617a4bcf05a59c650d91ab950fd054d0f69a Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Mon, 26 Jul 2021 07:44:21 +0200 Subject: [PATCH 100/264] Binary representation of the floating-point numbers. --- src/algorithms/math/binary-floating-point/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/algorithms/math/binary-floating-point/README.md b/src/algorithms/math/binary-floating-point/README.md index c0c6fce046..0952d99f5b 100644 --- a/src/algorithms/math/binary-floating-point/README.md +++ b/src/algorithms/math/binary-floating-point/README.md @@ -79,6 +79,13 @@ I've tried to describe the logic behind the converting of floating-point numbers > Checkout the [interactive version of this diagram](https://trekhleb.dev/blog/2021/binary-floating-point/) to play around with setting bits on and off, and seeing how it would influence the final result +Here is the number ranges that different floating-point formats support: + +| Floating-point format | Exp min | Exp max | Range | Min positive | +| :-------------------- | :------ | :------ | :--------------- | :----------- | +| Half-precision | −14 | +15 | ±65,504 | 6.10 × 10⁻⁵ | +| Single-precision | −126 | +127 | ±3.4028235 × 10³⁸| 1.18 × 10⁻³⁸ | + Be aware that this is by no means a complete and sufficient overview of the IEEE 754 standard. It is rather a simplified and basic overview. Several corner cases were omitted in the examples above for simplicity of presentation (i.e. `-0`, `-∞`, `+∞` and `NaN` (not a number) values) ## Code examples From 4548296affb227c29ead868309e48667f8280c55 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Mon, 26 Jul 2021 11:55:40 +0200 Subject: [PATCH 101/264] Binary representation of the floating-point numbers. --- src/algorithms/math/binary-floating-point/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/algorithms/math/binary-floating-point/README.md b/src/algorithms/math/binary-floating-point/README.md index 0952d99f5b..d1ae72731e 100644 --- a/src/algorithms/math/binary-floating-point/README.md +++ b/src/algorithms/math/binary-floating-point/README.md @@ -97,6 +97,7 @@ Be aware that this is by no means a complete and sufficient overview of the IEEE You might also want to check out the following resources to get a deeper understanding of the binary representation of floating-point numbers: +- [Interactive version of this article](https://trekhleb.dev/blog/2021/binary-floating-point/) (allows setting the bits manually and seeing the resulting floating number) - [Here is what you need to know about JavaScript’s Number type](https://indepth.dev/posts/1139/here-is-what-you-need-to-know-about-javascripts-number-type) - [Float Exposed](https://float.exposed/) - [IEEE754 Visualization](https://bartaz.github.io/ieee754-visualization/) From d0576a2594f843cae01abfdb9a2aa08663bdee54 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Mon, 18 Oct 2021 18:02:40 +0200 Subject: [PATCH 102/264] Upgrade dependencies. (#790) --- package-lock.json | 6881 +++++++++++++++++---------------------------- package.json | 20 +- 2 files changed, 2597 insertions(+), 4304 deletions(-) diff --git a/package-lock.json b/package-lock.json index 93de7f66c9..ea195beb9b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,53 +5,52 @@ "requires": true, "dependencies": { "@babel/cli": { - "version": "7.12.10", - "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.12.10.tgz", - "integrity": "sha512-+y4ZnePpvWs1fc/LhZRTHkTesbXkyBYuOB+5CyodZqrEuETXi3zOVfpAQIdgC3lXbHLTDG9dQosxR9BhvLKDLQ==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.15.7.tgz", + "integrity": "sha512-YW5wOprO2LzMjoWZ5ZG6jfbY9JnkDxuHDwvnrThnuYtByorova/I0HNXJedrUfwuXFQfYOjcqDA4PU3qlZGZjg==", "dev": true, "requires": { - "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents", + "@nicolo-ribaudo/chokidar-2": "2.1.8-no-fsevents.3", "chokidar": "^3.4.0", "commander": "^4.0.1", "convert-source-map": "^1.1.0", "fs-readdir-recursive": "^1.1.0", "glob": "^7.0.0", - "lodash": "^4.17.19", "make-dir": "^2.1.0", "slash": "^2.0.0", "source-map": "^0.5.0" } }, "@babel/code-frame": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.13.tgz", - "integrity": "sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz", + "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==", "dev": true, "requires": { - "@babel/highlight": "^7.12.13" + "@babel/highlight": "^7.14.5" } }, "@babel/compat-data": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.13.15.tgz", - "integrity": "sha512-ltnibHKR1VnrU4ymHyQ/CXtNXI6yZC0oJThyW78Hft8XndANwi+9H+UIklBDraIjFEJzw8wmcM427oDd9KS5wA==", + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", + "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", "dev": true }, "@babel/core": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.13.15.tgz", - "integrity": "sha512-6GXmNYeNjS2Uz+uls5jalOemgIhnTMeaXo+yBUA72kC2uX/8VW6XyhVIo2L8/q0goKQA3EVKx0KOQpVKSeWadQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.9", - "@babel/helper-compilation-targets": "^7.13.13", - "@babel/helper-module-transforms": "^7.13.14", - "@babel/helpers": "^7.13.10", - "@babel/parser": "^7.13.15", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.15", - "@babel/types": "^7.13.14", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.15.8.tgz", + "integrity": "sha512-3UG9dsxvYBMYwRv+gS41WKHno4K60/9GPy1CJaH6xy3Elq8CTtvtjT5R5jmNhXfCYLX2mTw+7/aq5ak/gOE0og==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.15.8", + "@babel/generator": "^7.15.8", + "@babel/helper-compilation-targets": "^7.15.4", + "@babel/helper-module-transforms": "^7.15.8", + "@babel/helpers": "^7.15.4", + "@babel/parser": "^7.15.8", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -60,15 +59,6 @@ "source-map": "^0.5.0" }, "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, "json5": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", @@ -78,12 +68,6 @@ "minimist": "^1.2.5" } }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -93,44 +77,44 @@ } }, "@babel/generator": { - "version": "7.13.9", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.13.9.tgz", - "integrity": "sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.8.tgz", + "integrity": "sha512-ECmAKstXbp1cvpTTZciZCgfOt6iN64lR0d+euv3UZisU5awfRawOvg07Utn/qBGuH4bRIEZKrA/4LzZyXhZr8g==", "dev": true, "requires": { - "@babel/types": "^7.13.0", + "@babel/types": "^7.15.6", "jsesc": "^2.5.1", "source-map": "^0.5.0" } }, "@babel/helper-annotate-as-pure": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.12.13.tgz", - "integrity": "sha512-7YXfX5wQ5aYM/BOlbSccHDbuXXFPxeoUmfWtz8le2yTkTZc+BxsiEnENFoi2SlmA8ewDkG2LgIMIVzzn2h8kfw==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.15.4.tgz", + "integrity": "sha512-QwrtdNvUNsPCj2lfNQacsGSQvGX8ee1ttrBrcozUP2Sv/jylewBP/8QFe6ZkBsC8T/GYWonNAWJV4aRR9AL2DA==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.15.4" } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.12.13.tgz", - "integrity": "sha512-CZOv9tGphhDRlVjVkAgm8Nhklm9RzSmWpX2my+t7Ua/KT616pEzXsQCjinzvkRvHWJ9itO4f296efroX23XCMA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.15.4.tgz", + "integrity": "sha512-P8o7JP2Mzi0SdC6eWr1zF+AEYvrsZa7GSY1lTayjF5XJhVH0kjLYUZPvTMflP7tBgZoe9gIhTa60QwFpqh/E0Q==", "dev": true, "requires": { - "@babel/helper-explode-assignable-expression": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/helper-explode-assignable-expression": "^7.15.4", + "@babel/types": "^7.15.4" } }, "@babel/helper-compilation-targets": { - "version": "7.13.13", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.13.tgz", - "integrity": "sha512-q1kcdHNZehBwD9jYPh3WyXcsFERi39X4I59I3NadciWtNDyZ6x+GboOxncFK0kXlKIv6BJm5acncehXWUjWQMQ==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.4.tgz", + "integrity": "sha512-rMWPCirulnPSe4d+gwdWXLfAXTTBj8M3guAf5xFQJ0nvFY7tfNAFnWdqaHegHlgDZOCT4qvhF3BYlSJag8yhqQ==", "dev": true, "requires": { - "@babel/compat-data": "^7.13.12", - "@babel/helper-validator-option": "^7.12.17", - "browserslist": "^4.14.5", + "@babel/compat-data": "^7.15.0", + "@babel/helper-validator-option": "^7.14.5", + "browserslist": "^4.16.6", "semver": "^6.3.0" }, "dependencies": { @@ -143,351 +127,409 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.13.11", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.13.11.tgz", - "integrity": "sha512-ays0I7XYq9xbjCSvT+EvysLgfc3tOkwCULHjrnscGT3A9qD4sk3wXnJ3of0MAWsWGjdinFvajHU2smYuqXKMrw==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.15.4.tgz", + "integrity": "sha512-7ZmzFi+DwJx6A7mHRwbuucEYpyBwmh2Ca0RvI6z2+WLZYCqV0JOaLb+u0zbtmDicebgKBZgqbYfLaKNqSgv5Pw==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-member-expression-to-functions": "^7.13.0", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/helper-replace-supers": "^7.13.0", - "@babel/helper-split-export-declaration": "^7.12.13" + "@babel/helper-annotate-as-pure": "^7.15.4", + "@babel/helper-function-name": "^7.15.4", + "@babel/helper-member-expression-to-functions": "^7.15.4", + "@babel/helper-optimise-call-expression": "^7.15.4", + "@babel/helper-replace-supers": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4" } }, "@babel/helper-create-regexp-features-plugin": { - "version": "7.12.17", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.17.tgz", - "integrity": "sha512-p2VGmBu9oefLZ2nQpgnEnG0ZlRPvL8gAGvPUMQwUdaE8k49rOMuZpOwdQoy5qJf6K8jL3bcAMhVUlHAjIgJHUg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.14.5.tgz", + "integrity": "sha512-TLawwqpOErY2HhWbGJ2nZT5wSkR192QpN+nBg1THfBfftrlvOh+WbhrxXCH4q4xJ9Gl16BGPR/48JA+Ryiho/A==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.12.13", + "@babel/helper-annotate-as-pure": "^7.14.5", "regexpu-core": "^4.7.1" } }, + "@babel/helper-define-polyfill-provider": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.2.3.tgz", + "integrity": "sha512-RH3QDAfRMzj7+0Nqu5oqgO5q9mFtQEVvCRsi8qCEfzLR9p2BHfn5FzhSB2oj1fF7I2+DcTORkYaQ6aTR9Cofew==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.13.0", + "@babel/helper-module-imports": "^7.12.13", + "@babel/helper-plugin-utils": "^7.13.0", + "@babel/traverse": "^7.13.0", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "@babel/helper-explode-assignable-expression": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.13.0.tgz", - "integrity": "sha512-qS0peLTDP8kOisG1blKbaoBg/o9OSa1qoumMjTK5pM+KDTtpxpsiubnCGP34vK8BXGcb2M9eigwgvoJryrzwWA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.15.4.tgz", + "integrity": "sha512-J14f/vq8+hdC2KoWLIQSsGrC9EFBKE4NFts8pfMpymfApds+fPqR30AOUWc4tyr56h9l/GA1Sxv2q3dLZWbQ/g==", "dev": true, "requires": { - "@babel/types": "^7.13.0" + "@babel/types": "^7.15.4" } }, "@babel/helper-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz", - "integrity": "sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.15.4.tgz", + "integrity": "sha512-Z91cOMM4DseLIGOnog+Z8OI6YseR9bua+HpvLAQ2XayUGU+neTtX+97caALaLdyu53I/fjhbeCnWnRH1O3jFOw==", "dev": true, "requires": { - "@babel/helper-get-function-arity": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/helper-get-function-arity": "^7.15.4", + "@babel/template": "^7.15.4", + "@babel/types": "^7.15.4" } }, "@babel/helper-get-function-arity": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz", - "integrity": "sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.15.4.tgz", + "integrity": "sha512-1/AlxSF92CmGZzHnC515hm4SirTxtpDnLEJ0UyEMgTMZN+6bxXKg04dKhiRx5Enel+SUA1G1t5Ed/yQia0efrA==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.15.4" } }, "@babel/helper-hoist-variables": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.13.0.tgz", - "integrity": "sha512-0kBzvXiIKfsCA0y6cFEIJf4OdzfpRuNk4+YTeHZpGGc666SATFKTz6sRncwFnQk7/ugJ4dSrCj6iJuvW4Qwr2g==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.15.4.tgz", + "integrity": "sha512-VTy085egb3jUGVK9ycIxQiPbquesq0HUQ+tPO0uv5mPEBZipk+5FkRKiWq5apuyTE9FUrjENB0rCf8y+n+UuhA==", "dev": true, "requires": { - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" + "@babel/types": "^7.15.4" } }, "@babel/helper-member-expression-to-functions": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.12.tgz", - "integrity": "sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.4.tgz", + "integrity": "sha512-cokOMkxC/BTyNP1AlY25HuBWM32iCEsLPI4BHDpJCHHm1FU2E7dKWWIXJgQgSFiu4lp8q3bL1BIKwqkSUviqtA==", "dev": true, "requires": { - "@babel/types": "^7.13.12" + "@babel/types": "^7.15.4" } }, "@babel/helper-module-imports": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz", - "integrity": "sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.15.4.tgz", + "integrity": "sha512-jeAHZbzUwdW/xHgHQ3QmWR4Jg6j15q4w/gCfwZvtqOxoo5DKtLHk8Bsf4c5RZRC7NmLEs+ohkdq8jFefuvIxAA==", "dev": true, "requires": { - "@babel/types": "^7.13.12" + "@babel/types": "^7.15.4" } }, "@babel/helper-module-transforms": { - "version": "7.13.14", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.13.14.tgz", - "integrity": "sha512-QuU/OJ0iAOSIatyVZmfqB0lbkVP0kDRiKj34xy+QNsnVZi/PA6BoSoreeqnxxa9EHFAIL0R9XOaAR/G9WlIy5g==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.8.tgz", + "integrity": "sha512-DfAfA6PfpG8t4S6npwzLvTUpp0sS7JrcuaMiy1Y5645laRJIp/LiLGIBbQKaXSInK8tiGNI7FL7L8UvB8gdUZg==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.13.12", - "@babel/helper-replace-supers": "^7.13.12", - "@babel/helper-simple-access": "^7.13.12", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/helper-validator-identifier": "^7.12.11", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.13", - "@babel/types": "^7.13.14" + "@babel/helper-module-imports": "^7.15.4", + "@babel/helper-replace-supers": "^7.15.4", + "@babel/helper-simple-access": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/helper-validator-identifier": "^7.15.7", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.6" } }, "@babel/helper-optimise-call-expression": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz", - "integrity": "sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.15.4.tgz", + "integrity": "sha512-E/z9rfbAOt1vDW1DR7k4SzhzotVV5+qMciWV6LaG1g4jeFrkDlJedjtV4h0i4Q/ITnUu+Pk08M7fczsB9GXBDw==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.15.4" } }, "@babel/helper-plugin-utils": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz", - "integrity": "sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", "dev": true }, "@babel/helper-remap-async-to-generator": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.13.0.tgz", - "integrity": "sha512-pUQpFBE9JvC9lrQbpX0TmeNIy5s7GnZjna2lhhcHC7DzgBs6fWn722Y5cfwgrtrqc7NAJwMvOa0mKhq6XaE4jg==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.15.4.tgz", + "integrity": "sha512-v53MxgvMK/HCwckJ1bZrq6dNKlmwlyRNYM6ypaRTdXWGOE2c1/SCa6dL/HimhPulGhZKw9W0QhREM583F/t0vQ==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "@babel/helper-wrap-function": "^7.13.0", - "@babel/types": "^7.13.0" + "@babel/helper-annotate-as-pure": "^7.15.4", + "@babel/helper-wrap-function": "^7.15.4", + "@babel/types": "^7.15.4" } }, "@babel/helper-replace-supers": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz", - "integrity": "sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.4.tgz", + "integrity": "sha512-/ztT6khaXF37MS47fufrKvIsiQkx1LBRvSJNzRqmbyeZnTwU9qBxXYLaaT/6KaxfKhjs2Wy8kG8ZdsFUuWBjzw==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.13.12", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.12" + "@babel/helper-member-expression-to-functions": "^7.15.4", + "@babel/helper-optimise-call-expression": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" } }, "@babel/helper-simple-access": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.13.12.tgz", - "integrity": "sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.15.4.tgz", + "integrity": "sha512-UzazrDoIVOZZcTeHHEPYrr1MvTR/K+wgLg6MY6e1CJyaRhbibftF6fR2KU2sFRtI/nERUZR9fBd6aKgBlIBaPg==", "dev": true, "requires": { - "@babel/types": "^7.13.12" + "@babel/types": "^7.15.4" } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.12.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", - "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.15.4.tgz", + "integrity": "sha512-BMRLsdh+D1/aap19TycS4eD1qELGrCBJwzaY9IE8LrpJtJb+H7rQkPIdsfgnMtLBA6DJls7X9z93Z4U8h7xw0A==", "dev": true, "requires": { - "@babel/types": "^7.12.1" + "@babel/types": "^7.15.4" } }, "@babel/helper-split-export-declaration": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz", - "integrity": "sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.15.4.tgz", + "integrity": "sha512-HsFqhLDZ08DxCpBdEVtKmywj6PQbwnF6HHybur0MAnkAKnlS6uHkwnmRIkElB2Owpfb4xL4NwDmDLFubueDXsw==", "dev": true, "requires": { - "@babel/types": "^7.12.13" + "@babel/types": "^7.15.4" } }, "@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.12.17", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz", - "integrity": "sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", + "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", "dev": true }, "@babel/helper-wrap-function": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.13.0.tgz", - "integrity": "sha512-1UX9F7K3BS42fI6qd2A4BjKzgGjToscyZTdp1DjknHLCIvpgne6918io+aL5LXFcER/8QWiwpoY902pVEqgTXA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.15.4.tgz", + "integrity": "sha512-Y2o+H/hRV5W8QhIfTpRIBwl57y8PrZt6JM3V8FOo5qarjshHItyH5lXlpMfBfmBefOqSCpKZs/6Dxqp0E/U+uw==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.12.13", - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" + "@babel/helper-function-name": "^7.15.4", + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" } }, "@babel/helpers": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.13.10.tgz", - "integrity": "sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.4.tgz", + "integrity": "sha512-V45u6dqEJ3w2rlryYYXf6i9rQ5YMNu4FLS6ngs8ikblhu2VdR1AqAd6aJjBzmf2Qzh6KOLqKHxEN9+TFbAkAVQ==", "dev": true, "requires": { - "@babel/template": "^7.12.13", - "@babel/traverse": "^7.13.0", - "@babel/types": "^7.13.0" + "@babel/template": "^7.15.4", + "@babel/traverse": "^7.15.4", + "@babel/types": "^7.15.4" } }, "@babel/highlight": { - "version": "7.13.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.13.10.tgz", - "integrity": "sha512-5aPpe5XQPzflQrFwL1/QoeHkP2MsA4JCntcXHRhEsdsfPVkvPi2w7Qix4iV7t5S/oC9OodGrggd8aco1g3SZFg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.12.11", + "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", "js-tokens": "^4.0.0" } }, "@babel/parser": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.13.15.tgz", - "integrity": "sha512-b9COtcAlVEQljy/9fbcMHpG+UIW9ReF+gpaxDHTlZd0c6/UU9ng8zdySAW9sRTzpvcdCHn6bUcbuYUgGzLAWVQ==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.8.tgz", + "integrity": "sha512-BRYa3wcQnjS/nqI8Ac94pYYpJfojHVvVXJ97+IDCImX4Jc8W8Xv1+47enbruk+q1etOpsQNwnfFcNGw+gtPGxA==", "dev": true }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.15.4.tgz", + "integrity": "sha512-eBnpsl9tlhPhpI10kU06JHnrYXwg3+V6CaP2idsCXNef0aeslpqyITXQ74Vfk5uHgY7IG7XP0yIH8b42KSzHog==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.15.4", + "@babel/plugin-proposal-optional-chaining": "^7.14.5" + } + }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.13.15.tgz", - "integrity": "sha512-VapibkWzFeoa6ubXy/NgV5U2U4MVnUlvnx6wo1XhlsaTrLYWE0UFpDQsVrmn22q5CzeloqJ8gEMHSKxuee6ZdA==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.15.8.tgz", + "integrity": "sha512-2Z5F2R2ibINTc63mY7FLqGfEbmofrHU9FitJW1Q7aPaKFhiPvSq6QEt/BoWN5oME3GVyjcRuNNSRbb9LC0CSWA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-remap-async-to-generator": "^7.13.0", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-remap-async-to-generator": "^7.15.4", "@babel/plugin-syntax-async-generators": "^7.8.4" } }, "@babel/plugin-proposal-class-properties": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.13.0.tgz", - "integrity": "sha512-KnTDjFNC1g+45ka0myZNvSBFLhNCLN+GeGYLDEA8Oq7MZ6yMgfLoIRh86GRT0FjtJhZw8JyUskP9uvj5pHM9Zg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.14.5.tgz", + "integrity": "sha512-q/PLpv5Ko4dVc1LYMpCY7RVAAO4uk55qPwrIuJ5QJ8c6cVuAmhu7I/49JOppXL6gXf7ZHzpRVEUZdYoPLM04Gg==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.15.4.tgz", + "integrity": "sha512-M682XWrrLNk3chXCjoPUQWOyYsB93B9z3mRyjtqqYJWDf2mfCdIYgDrA11cgNVhAQieaq6F2fn2f3wI0U4aTjA==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0" + "@babel/helper-create-class-features-plugin": "^7.15.4", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" } }, "@babel/plugin-proposal-dynamic-import": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.13.8.tgz", - "integrity": "sha512-ONWKj0H6+wIRCkZi9zSbZtE/r73uOhMVHh256ys0UzfM7I3d4n+spZNWjOnJv2gzopumP2Wxi186vI8N0Y2JyQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.14.5.tgz", + "integrity": "sha512-ExjiNYc3HDN5PXJx+bwC50GIx/KKanX2HiggnIUAYedbARdImiCU4RhhHfdf0Kd7JNXGpsBBBCOm+bBVy3Gb0g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-plugin-utils": "^7.14.5", "@babel/plugin-syntax-dynamic-import": "^7.8.3" } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.13.tgz", - "integrity": "sha512-INAgtFo4OnLN3Y/j0VwAgw3HDXcDtX+C/erMvWzuV9v71r7urb6iyMXu7eM9IgLr1ElLlOkaHjJ0SbCmdOQ3Iw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.14.5.tgz", + "integrity": "sha512-g5POA32bXPMmSBu5Dx/iZGLGnKmKPc5AiY7qfZgurzrCYgIztDlHFbznSNCoQuv57YQLnQfaDi7dxCtLDIdXdA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13", + "@babel/helper-plugin-utils": "^7.14.5", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, "@babel/plugin-proposal-json-strings": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.13.8.tgz", - "integrity": "sha512-w4zOPKUFPX1mgvTmL/fcEqy34hrQ1CRcGxdphBc6snDnnqJ47EZDIyop6IwXzAC8G916hsIuXB2ZMBCExC5k7Q==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.14.5.tgz", + "integrity": "sha512-NSq2fczJYKVRIsUJyNxrVUMhB27zb7N7pOFGQOhBKJrChbGcgEAqyZrmZswkPk18VMurEeJAaICbfm57vUeTbQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-plugin-utils": "^7.14.5", "@babel/plugin-syntax-json-strings": "^7.8.3" } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.13.8.tgz", - "integrity": "sha512-aul6znYB4N4HGweImqKn59Su9RS8lbUIqxtXTOcAGtNIDczoEFv+l1EhmX8rUBp3G1jMjKJm8m0jXVp63ZpS4A==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.14.5.tgz", + "integrity": "sha512-YGn2AvZAo9TwyhlLvCCWxD90Xq8xJ4aSgaX3G5D/8DW94L8aaT+dS5cSP+Z06+rCJERGSr9GxMBZ601xoc2taw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-plugin-utils": "^7.14.5", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.13.8.tgz", - "integrity": "sha512-iePlDPBn//UhxExyS9KyeYU7RM9WScAG+D3Hhno0PLJebAEpDZMocbDe64eqynhNAnwz/vZoL/q/QB2T1OH39A==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.14.5.tgz", + "integrity": "sha512-gun/SOnMqjSb98Nkaq2rTKMwervfdAoz6NphdY0vTfuzMfryj+tDGb2n6UkDKwez+Y8PZDhE3D143v6Gepp4Hg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-plugin-utils": "^7.14.5", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" } }, "@babel/plugin-proposal-numeric-separator": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.13.tgz", - "integrity": "sha512-O1jFia9R8BUCl3ZGB7eitaAPu62TXJRHn7rh+ojNERCFyqRwJMTmhz+tJ+k0CwI6CLjX/ee4qW74FSqlq9I35w==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.14.5.tgz", + "integrity": "sha512-yiclALKe0vyZRZE0pS6RXgjUOt87GWv6FYa5zqj15PvhOGFO69R5DusPlgK/1K5dVnCtegTiWu9UaBSrLLJJBg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13", + "@babel/helper-plugin-utils": "^7.14.5", "@babel/plugin-syntax-numeric-separator": "^7.10.4" } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.13.8.tgz", - "integrity": "sha512-DhB2EuB1Ih7S3/IRX5AFVgZ16k3EzfRbq97CxAVI1KSYcW+lexV8VZb7G7L8zuPVSdQMRn0kiBpf/Yzu9ZKH0g==", + "version": "7.15.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.15.6.tgz", + "integrity": "sha512-qtOHo7A1Vt+O23qEAX+GdBpqaIuD3i9VRrWgCJeq7WO6H2d14EK3q11urj5Te2MAeK97nMiIdRpwd/ST4JFbNg==", "dev": true, "requires": { - "@babel/compat-data": "^7.13.8", - "@babel/helper-compilation-targets": "^7.13.8", - "@babel/helper-plugin-utils": "^7.13.0", + "@babel/compat-data": "^7.15.0", + "@babel/helper-compilation-targets": "^7.15.4", + "@babel/helper-plugin-utils": "^7.14.5", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.13.0" + "@babel/plugin-transform-parameters": "^7.15.4" } }, "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.13.8.tgz", - "integrity": "sha512-0wS/4DUF1CuTmGo+NiaHfHcVSeSLj5S3e6RivPTg/2k3wOv3jO35tZ6/ZWsQhQMvdgI7CwphjQa/ccarLymHVA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.14.5.tgz", + "integrity": "sha512-3Oyiixm0ur7bzO5ybNcZFlmVsygSIQgdOa7cTfOYCMY+wEPAYhZAJxi3mixKFCTCKUhQXuCTtQ1MzrpL3WT8ZQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-plugin-utils": "^7.14.5", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.13.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.13.12.tgz", - "integrity": "sha512-fcEdKOkIB7Tf4IxrgEVeFC4zeJSTr78no9wTdBuZZbqF64kzllU0ybo2zrzm7gUQfxGhBgq4E39oRs8Zx/RMYQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.14.5.tgz", + "integrity": "sha512-ycz+VOzo2UbWNI1rQXxIuMOzrDdHGrI23fRiz/Si2R4kv2XZQ1BK8ccdHwehMKBlcH/joGW/tzrUmo67gbJHlQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.14.5", "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, "@babel/plugin-proposal-private-methods": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.13.0.tgz", - "integrity": "sha512-MXyyKQd9inhx1kDYPkFRVOBXQ20ES8Pto3T7UZ92xj2mY0EVD8oAVzeyYuVfy/mxAdTSIayOvg+aVzcHV2bn6Q==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.14.5.tgz", + "integrity": "sha512-838DkdUA1u+QTCplatfq4B7+1lnDa/+QMI89x5WZHBcnNv+47N8QEj2k9I2MUU9xIv8XJ4XvPCviM/Dj7Uwt9g==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.15.4.tgz", + "integrity": "sha512-X0UTixkLf0PCCffxgu5/1RQyGGbgZuKoI+vXP4iSbJSYwPb7hu06omsFGBvQ9lJEvwgrxHdS8B5nbfcd8GyUNA==", "dev": true, "requires": { - "@babel/helper-create-class-features-plugin": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0" + "@babel/helper-annotate-as-pure": "^7.15.4", + "@babel/helper-create-class-features-plugin": "^7.15.4", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" } }, "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.13.tgz", - "integrity": "sha512-XyJmZidNfofEkqFV5VC/bLabGmO5QzenPO/YOfGuEbgU+2sSwMmio3YLb4WtBgcmmdwZHyVyv8on77IUjQ5Gvg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.14.5.tgz", + "integrity": "sha512-6axIeOU5LnY471KenAB9vI8I5j7NQ2d652hIYwVyRfgaZT5UpiqFKCuVXCDMSrU+3VFafnu2c5m3lrWIlr6A5Q==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-syntax-async-generators": { @@ -517,6 +559,15 @@ "@babel/helper-plugin-utils": "^7.12.13" } }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, "@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", @@ -607,399 +658,432 @@ "@babel/helper-plugin-utils": "^7.8.0" } }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, "@babel/plugin-syntax-top-level-await": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz", - "integrity": "sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.14.5.tgz", + "integrity": "sha512-u6OXzDaIXjEstBRRoBCQ/uKQKlbuaeE5in0RvWdA4pN6AhqxTIwUsnHPU1CFZA/amYObMsuWhYfRl3Ch90HD0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-arrow-functions": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz", - "integrity": "sha512-96lgJagobeVmazXFaDrbmCLQxBysKu7U6Do3mLsx27gf5Dk85ezysrs2BZUpXD703U/Su1xTBDxxar2oa4jAGg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.14.5.tgz", + "integrity": "sha512-KOnO0l4+tD5IfOdi4x8C1XmEIRWUjNRV8wc6K2vz/3e8yAOoZZvsRXRRIF/yo/MAOFb4QjtAw9xSxMXbSMRy8A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-async-to-generator": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.13.0.tgz", - "integrity": "sha512-3j6E004Dx0K3eGmhxVJxwwI89CTJrce7lg3UrtFuDAVQ/2+SJ/h/aSFOeE6/n0WB1GsOffsJp6MnPQNQ8nmwhg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.14.5.tgz", + "integrity": "sha512-szkbzQ0mNk0rpu76fzDdqSyPu0MuvpXgC+6rz5rpMb5OIRxdmHfQxrktL8CYolL2d8luMCZTR0DpIMIdL27IjA==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-remap-async-to-generator": "^7.13.0" + "@babel/helper-module-imports": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-remap-async-to-generator": "^7.14.5" } }, "@babel/plugin-transform-block-scoped-functions": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.13.tgz", - "integrity": "sha512-zNyFqbc3kI/fVpqwfqkg6RvBgFpC4J18aKKMmv7KdQ/1GgREapSJAykLMVNwfRGO3BtHj3YQZl8kxCXPcVMVeg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.14.5.tgz", + "integrity": "sha512-dtqWqdWZ5NqBX3KzsVCWfQI3A53Ft5pWFCT2eCVUftWZgjc5DpDponbIF1+c+7cSGk2wN0YK7HGL/ezfRbpKBQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-block-scoping": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.13.tgz", - "integrity": "sha512-Pxwe0iqWJX4fOOM2kEZeUuAxHMWb9nK+9oh5d11bsLoB0xMg+mkDpt0eYuDZB7ETrY9bbcVlKUGTOGWy7BHsMQ==", + "version": "7.15.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.15.3.tgz", + "integrity": "sha512-nBAzfZwZb4DkaGtOes1Up1nOAp9TDRRFw4XBzBBSG9QK7KVFmYzgj9o9sbPv7TX5ofL4Auq4wZnxCoPnI/lz2Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-classes": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.13.0.tgz", - "integrity": "sha512-9BtHCPUARyVH1oXGcSJD3YpsqRLROJx5ZNP6tN5vnk17N0SVf9WCtf8Nuh1CFmgByKKAIMstitKduoCmsaDK5g==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.15.4.tgz", + "integrity": "sha512-Yjvhex8GzBmmPQUvpXRPWQ9WnxXgAFuZSrqOK/eJlOGIXwvv8H3UEdUigl1gb/bnjTrln+e8bkZUYCBt/xYlBg==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.12.13", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-optimise-call-expression": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-replace-supers": "^7.13.0", - "@babel/helper-split-export-declaration": "^7.12.13", + "@babel/helper-annotate-as-pure": "^7.15.4", + "@babel/helper-function-name": "^7.15.4", + "@babel/helper-optimise-call-expression": "^7.15.4", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-replace-supers": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.13.0.tgz", - "integrity": "sha512-RRqTYTeZkZAz8WbieLTvKUEUxZlUTdmL5KGMyZj7FnMfLNKV4+r5549aORG/mgojRmFlQMJDUupwAMiF2Q7OUg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.14.5.tgz", + "integrity": "sha512-pWM+E4283UxaVzLb8UBXv4EIxMovU4zxT1OPnpHJcmnvyY9QbPPTKZfEj31EUvG3/EQRbYAGaYEUZ4yWOBC2xg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-destructuring": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.13.0.tgz", - "integrity": "sha512-zym5em7tePoNT9s964c0/KU3JPPnuq7VhIxPRefJ4/s82cD+q1mgKfuGRDMCPL0HTyKz4dISuQlCusfgCJ86HA==", + "version": "7.14.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.14.7.tgz", + "integrity": "sha512-0mDE99nK+kVh3xlc5vKwB6wnP9ecuSj+zQCa/n0voENtP/zymdT4HH6QEb65wjjcbqr1Jb/7z9Qp7TF5FtwYGw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-dotall-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.13.tgz", - "integrity": "sha512-foDrozE65ZFdUC2OfgeOCrEPTxdB3yjqxpXh8CH+ipd9CHd4s/iq81kcUpyH8ACGNEPdFqbtzfgzbT/ZGlbDeQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.14.5.tgz", + "integrity": "sha512-loGlnBdj02MDsFaHhAIJzh7euK89lBrGIdM9EAtHFo6xKygCUGuuWe07o1oZVk287amtW1n0808sQM99aZt3gw==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.13.tgz", - "integrity": "sha512-NfADJiiHdhLBW3pulJlJI2NB0t4cci4WTZ8FtdIuNc2+8pslXdPtRRAEWqUY+m9kNOk2eRYbTAOipAxlrOcwwQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.14.5.tgz", + "integrity": "sha512-iJjbI53huKbPDAsJ8EmVmvCKeeq21bAze4fu9GBQtSLqfvzj2oRuHVx4ZkDwEhg1htQ+5OBZh/Ab0XDf5iBZ7A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-exponentiation-operator": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.13.tgz", - "integrity": "sha512-fbUelkM1apvqez/yYx1/oICVnGo2KM5s63mhGylrmXUxK/IAXSIf87QIxVfZldWf4QsOafY6vV3bX8aMHSvNrA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.14.5.tgz", + "integrity": "sha512-jFazJhMBc9D27o9jDnIE5ZErI0R0m7PbKXVq77FFvqFbzvTMuv8jaAwLZ5PviOLSFttqKIW0/wxNSDbjLk0tYA==", "dev": true, "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-for-of": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.13.0.tgz", - "integrity": "sha512-IHKT00mwUVYE0zzbkDgNRP6SRzvfGCYsOxIRz8KsiaaHCcT9BWIkO+H9QRJseHBLOGBZkHUdHiqj6r0POsdytg==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.15.4.tgz", + "integrity": "sha512-DRTY9fA751AFBDh2oxydvVm4SYevs5ILTWLs6xKXps4Re/KG5nfUkr+TdHCrRWB8C69TlzVgA9b3RmGWmgN9LA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-function-name": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.13.tgz", - "integrity": "sha512-6K7gZycG0cmIwwF7uMK/ZqeCikCGVBdyP2J5SKNCXO5EOHcqi+z7Jwf8AmyDNcBgxET8DrEtCt/mPKPyAzXyqQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.14.5.tgz", + "integrity": "sha512-vbO6kv0fIzZ1GpmGQuvbwwm+O4Cbm2NrPzwlup9+/3fdkuzo1YqOZcXw26+YUJB84Ja7j9yURWposEHLYwxUfQ==", "dev": true, "requires": { - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-literals": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.13.tgz", - "integrity": "sha512-FW+WPjSR7hiUxMcKqyNjP05tQ2kmBCdpEpZHY1ARm96tGQCCBvXKnpjILtDplUnJ/eHZ0lALLM+d2lMFSpYJrQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.14.5.tgz", + "integrity": "sha512-ql33+epql2F49bi8aHXxvLURHkxJbSmMKl9J5yHqg4PLtdE6Uc48CH1GS6TQvZ86eoB/ApZXwm7jlA+B3kra7A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-member-expression-literals": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.13.tgz", - "integrity": "sha512-kxLkOsg8yir4YeEPHLuO2tXP9R/gTjpuTOjshqSpELUN3ZAg2jfDnKUvzzJxObun38sw3wm4Uu69sX/zA7iRvg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.14.5.tgz", + "integrity": "sha512-WkNXxH1VXVTKarWFqmso83xl+2V3Eo28YY5utIkbsmXoItO8Q3aZxN4BTS2k0hz9dGUloHK26mJMyQEYfkn/+Q==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-modules-amd": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.13.0.tgz", - "integrity": "sha512-EKy/E2NHhY/6Vw5d1k3rgoobftcNUmp9fGjb9XZwQLtTctsRBOTRO7RHHxfIky1ogMN5BxN7p9uMA3SzPfotMQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.14.5.tgz", + "integrity": "sha512-3lpOU8Vxmp3roC4vzFpSdEpGUWSMsHFreTWOMMLzel2gNGfHE5UWIh/LN6ghHs2xurUp4jRFYMUIZhuFbody1g==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0", + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.13.8.tgz", - "integrity": "sha512-9QiOx4MEGglfYZ4XOnU79OHr6vIWUakIj9b4mioN8eQIoEh+pf5p/zEB36JpDFWA12nNMiRf7bfoRvl9Rn79Bw==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.15.4.tgz", + "integrity": "sha512-qg4DPhwG8hKp4BbVDvX1s8cohM8a6Bvptu4l6Iingq5rW+yRUAhe/YRup/YcW2zCOlrysEWVhftIcKzrEZv3sA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-simple-access": "^7.12.13", + "@babel/helper-module-transforms": "^7.15.4", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-simple-access": "^7.15.4", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.13.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.13.8.tgz", - "integrity": "sha512-hwqctPYjhM6cWvVIlOIe27jCIBgHCsdH2xCJVAYQm7V5yTMoilbVMi9f6wKg0rpQAOn6ZG4AOyvCqFF/hUh6+A==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.15.4.tgz", + "integrity": "sha512-fJUnlQrl/mezMneR72CKCgtOoahqGJNVKpompKwzv3BrEXdlPspTcyxrZ1XmDTIr9PpULrgEQo3qNKp6dW7ssw==", "dev": true, "requires": { - "@babel/helper-hoist-variables": "^7.13.0", - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-validator-identifier": "^7.12.11", + "@babel/helper-hoist-variables": "^7.15.4", + "@babel/helper-module-transforms": "^7.15.4", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-validator-identifier": "^7.14.9", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-umd": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.13.0.tgz", - "integrity": "sha512-D/ILzAh6uyvkWjKKyFE/W0FzWwasv6vPTSqPcjxFqn6QpX3u8DjRVliq4F2BamO2Wee/om06Vyy+vPkNrd4wxw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.14.5.tgz", + "integrity": "sha512-RfPGoagSngC06LsGUYyM9QWSXZ8MysEjDJTAea1lqRjNECE3y0qIJF/qbvJxc4oA4s99HumIMdXOrd+TdKaAAA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.13.0", - "@babel/helper-plugin-utils": "^7.13.0" + "@babel/helper-module-transforms": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.13.tgz", - "integrity": "sha512-Xsm8P2hr5hAxyYblrfACXpQKdQbx4m2df9/ZZSQ8MAhsadw06+jW7s9zsSw6he+mJZXRlVMyEnVktJo4zjk1WA==", + "version": "7.14.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.14.9.tgz", + "integrity": "sha512-l666wCVYO75mlAtGFfyFwnWmIXQm3kSH0C3IRnJqWcZbWkoihyAdDhFm2ZWaxWTqvBvhVFfJjMRQ0ez4oN1yYA==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13" + "@babel/helper-create-regexp-features-plugin": "^7.14.5" } }, "@babel/plugin-transform-new-target": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.13.tgz", - "integrity": "sha512-/KY2hbLxrG5GTQ9zzZSc3xWiOy379pIETEhbtzwZcw9rvuaVV4Fqy7BYGYOWZnaoXIQYbbJ0ziXLa/sKcGCYEQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.14.5.tgz", + "integrity": "sha512-Nx054zovz6IIRWEB49RDRuXGI4Gy0GMgqG0cII9L3MxqgXz/+rgII+RU58qpo4g7tNEx1jG7rRVH4ihZoP4esQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-object-super": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.13.tgz", - "integrity": "sha512-JzYIcj3XtYspZDV8j9ulnoMPZZnF/Cj0LUxPOjR89BdBVx+zYJI9MdMIlUZjbXDX+6YVeS6I3e8op+qQ3BYBoQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.14.5.tgz", + "integrity": "sha512-MKfOBWzK0pZIrav9z/hkRqIk/2bTv9qvxHzPQc12RcVkMOzpIKnFCNYJip00ssKWYkd8Sf5g0Wr7pqJ+cmtuFg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13", - "@babel/helper-replace-supers": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-replace-supers": "^7.14.5" } }, "@babel/plugin-transform-parameters": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.13.0.tgz", - "integrity": "sha512-Jt8k/h/mIwE2JFEOb3lURoY5C85ETcYPnbuAJ96zRBzh1XHtQZfs62ChZ6EP22QlC8c7Xqr9q+e1SU5qttwwjw==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.15.4.tgz", + "integrity": "sha512-9WB/GUTO6lvJU3XQsSr6J/WKvBC2hcs4Pew8YxZagi6GkTdniyqp8On5kqdK8MN0LMeu0mGbhPN+O049NV/9FQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-property-literals": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.13.tgz", - "integrity": "sha512-nqVigwVan+lR+g8Fj8Exl0UQX2kymtjcWfMOYM1vTYEKujeyv2SkMgazf2qNcK7l4SDiKyTA/nHCPqL4e2zo1A==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.14.5.tgz", + "integrity": "sha512-r1uilDthkgXW8Z1vJz2dKYLV1tuw2xsbrp3MrZmD99Wh9vsfKoob+JTgri5VUb/JqyKRXotlOtwgu4stIYCmnw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-regenerator": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.13.15.tgz", - "integrity": "sha512-Bk9cOLSz8DiurcMETZ8E2YtIVJbFCPGW28DJWUakmyVWtQSm6Wsf0p4B4BfEr/eL2Nkhe/CICiUiMOCi1TPhuQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.14.5.tgz", + "integrity": "sha512-NVIY1W3ITDP5xQl50NgTKlZ0GrotKtLna08/uGY6ErQt6VEQZXla86x/CTddm5gZdcr+5GSsvMeTmWA5Ii6pkg==", "dev": true, "requires": { "regenerator-transform": "^0.14.2" } }, "@babel/plugin-transform-reserved-words": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.13.tgz", - "integrity": "sha512-xhUPzDXxZN1QfiOy/I5tyye+TRz6lA7z6xaT4CLOjPRMVg1ldRf0LHw0TDBpYL4vG78556WuHdyO9oi5UmzZBg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.14.5.tgz", + "integrity": "sha512-cv4F2rv1nD4qdexOGsRQXJrOcyb5CrgjUH9PKrrtyhSDBNWGxd0UIitjyJiWagS+EbUGjG++22mGH1Pub8D6Vg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-shorthand-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.13.tgz", - "integrity": "sha512-xpL49pqPnLtf0tVluuqvzWIgLEhuPpZzvs2yabUHSKRNlN7ScYU7aMlmavOeyXJZKgZKQRBlh8rHbKiJDraTSw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.14.5.tgz", + "integrity": "sha512-xLucks6T1VmGsTB+GWK5Pl9Jl5+nRXD1uoFdA5TSO6xtiNjtXTjKkmPdFXVLGlK5A2/or/wQMKfmQ2Y0XJfn5g==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-spread": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.13.0.tgz", - "integrity": "sha512-V6vkiXijjzYeFmQTr3dBxPtZYLPcUfY34DebOU27jIl2M/Y8Egm52Hw82CSjjPqd54GTlJs5x+CR7HeNr24ckg==", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.15.8.tgz", + "integrity": "sha512-/daZ8s2tNaRekl9YJa9X4bzjpeRZLt122cpgFnQPLGUe61PH8zMEBmYqKkW5xF5JUEh5buEGXJoQpqBmIbpmEQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.15.4" } }, "@babel/plugin-transform-sticky-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.13.tgz", - "integrity": "sha512-Jc3JSaaWT8+fr7GRvQP02fKDsYk4K/lYwWq38r/UGfaxo89ajud321NH28KRQ7xy1Ybc0VUE5Pz8psjNNDUglg==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.14.5.tgz", + "integrity": "sha512-Z7F7GyvEMzIIbwnziAZmnSNpdijdr4dWt+FJNBnBLz5mwDFkqIXU9wmBcWWad3QeJF5hMTkRe4dAq2sUZiG+8A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-template-literals": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.13.0.tgz", - "integrity": "sha512-d67umW6nlfmr1iehCcBv69eSUSySk1EsIS8aTDX4Xo9qajAh6mYtcl4kJrBkGXuxZPEgVr7RVfAvNW6YQkd4Mw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.14.5.tgz", + "integrity": "sha512-22btZeURqiepOfuy/VkFr+zStqlujWaarpMErvay7goJS6BWwdd6BY9zQyDLDa4x2S3VugxFb162IZ4m/S/+Gg==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.13.0" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.13.tgz", - "integrity": "sha512-eKv/LmUJpMnu4npgfvs3LiHhJua5fo/CysENxa45YCQXZwKnGCQKAg87bvoqSW1fFT+HA32l03Qxsm8ouTY3ZQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.14.5.tgz", + "integrity": "sha512-lXzLD30ffCWseTbMQzrvDWqljvZlHkXU+CnseMhkMNqU1sASnCsz3tSzAaH3vCUXb9PHeUb90ZT1BdFTm1xxJw==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.13.tgz", - "integrity": "sha512-0bHEkdwJ/sN/ikBHfSmOXPypN/beiGqjo+o4/5K+vxEFNPRPdImhviPakMKG4x96l85emoa0Z6cDflsdBusZbw==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.14.5.tgz", + "integrity": "sha512-crTo4jATEOjxj7bt9lbYXcBAM3LZaUrbP2uUdxb6WIorLmjNKSpHfIybgY4B8SRpbf8tEVIWH3Vtm7ayCrKocA==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/plugin-transform-unicode-regex": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.13.tgz", - "integrity": "sha512-mDRzSNY7/zopwisPZ5kM9XKCfhchqIYwAKRERtEnhYscZB79VRekuRSoYbN0+KVe3y8+q1h6A4svXtP7N+UoCA==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.14.5.tgz", + "integrity": "sha512-UygduJpC5kHeCiRw/xDVzC+wj8VaYSoKl5JNVmbP7MadpNinAm3SvZCxZ42H37KZBKztz46YC73i9yV34d0Tzw==", "dev": true, "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.12.13", - "@babel/helper-plugin-utils": "^7.12.13" + "@babel/helper-create-regexp-features-plugin": "^7.14.5", + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/preset-env": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.11.tgz", - "integrity": "sha512-j8Tb+KKIXKYlDBQyIOy4BLxzv1NUOwlHfZ74rvW+Z0Gp4/cI2IMDPBWAgWceGcE7aep9oL/0K9mlzlMGxA8yNw==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.12.7", - "@babel/helper-compilation-targets": "^7.12.5", - "@babel/helper-module-imports": "^7.12.5", - "@babel/helper-plugin-utils": "^7.10.4", - "@babel/helper-validator-option": "^7.12.11", - "@babel/plugin-proposal-async-generator-functions": "^7.12.1", - "@babel/plugin-proposal-class-properties": "^7.12.1", - "@babel/plugin-proposal-dynamic-import": "^7.12.1", - "@babel/plugin-proposal-export-namespace-from": "^7.12.1", - "@babel/plugin-proposal-json-strings": "^7.12.1", - "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", - "@babel/plugin-proposal-numeric-separator": "^7.12.7", - "@babel/plugin-proposal-object-rest-spread": "^7.12.1", - "@babel/plugin-proposal-optional-catch-binding": "^7.12.1", - "@babel/plugin-proposal-optional-chaining": "^7.12.7", - "@babel/plugin-proposal-private-methods": "^7.12.1", - "@babel/plugin-proposal-unicode-property-regex": "^7.12.1", - "@babel/plugin-syntax-async-generators": "^7.8.0", - "@babel/plugin-syntax-class-properties": "^7.12.1", - "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "version": "7.15.8", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.15.8.tgz", + "integrity": "sha512-rCC0wH8husJgY4FPbHsiYyiLxSY8oMDJH7Rl6RQMknbN9oDDHhM9RDFvnGM2MgkbUJzSQB4gtuwygY5mCqGSsA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.15.0", + "@babel/helper-compilation-targets": "^7.15.4", + "@babel/helper-plugin-utils": "^7.14.5", + "@babel/helper-validator-option": "^7.14.5", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.15.4", + "@babel/plugin-proposal-async-generator-functions": "^7.15.8", + "@babel/plugin-proposal-class-properties": "^7.14.5", + "@babel/plugin-proposal-class-static-block": "^7.15.4", + "@babel/plugin-proposal-dynamic-import": "^7.14.5", + "@babel/plugin-proposal-export-namespace-from": "^7.14.5", + "@babel/plugin-proposal-json-strings": "^7.14.5", + "@babel/plugin-proposal-logical-assignment-operators": "^7.14.5", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.14.5", + "@babel/plugin-proposal-numeric-separator": "^7.14.5", + "@babel/plugin-proposal-object-rest-spread": "^7.15.6", + "@babel/plugin-proposal-optional-catch-binding": "^7.14.5", + "@babel/plugin-proposal-optional-chaining": "^7.14.5", + "@babel/plugin-proposal-private-methods": "^7.14.5", + "@babel/plugin-proposal-private-property-in-object": "^7.15.4", + "@babel/plugin-proposal-unicode-property-regex": "^7.14.5", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-json-strings": "^7.8.3", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.0", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.0", - "@babel/plugin-syntax-top-level-await": "^7.12.1", - "@babel/plugin-transform-arrow-functions": "^7.12.1", - "@babel/plugin-transform-async-to-generator": "^7.12.1", - "@babel/plugin-transform-block-scoped-functions": "^7.12.1", - "@babel/plugin-transform-block-scoping": "^7.12.11", - "@babel/plugin-transform-classes": "^7.12.1", - "@babel/plugin-transform-computed-properties": "^7.12.1", - "@babel/plugin-transform-destructuring": "^7.12.1", - "@babel/plugin-transform-dotall-regex": "^7.12.1", - "@babel/plugin-transform-duplicate-keys": "^7.12.1", - "@babel/plugin-transform-exponentiation-operator": "^7.12.1", - "@babel/plugin-transform-for-of": "^7.12.1", - "@babel/plugin-transform-function-name": "^7.12.1", - "@babel/plugin-transform-literals": "^7.12.1", - "@babel/plugin-transform-member-expression-literals": "^7.12.1", - "@babel/plugin-transform-modules-amd": "^7.12.1", - "@babel/plugin-transform-modules-commonjs": "^7.12.1", - "@babel/plugin-transform-modules-systemjs": "^7.12.1", - "@babel/plugin-transform-modules-umd": "^7.12.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.1", - "@babel/plugin-transform-new-target": "^7.12.1", - "@babel/plugin-transform-object-super": "^7.12.1", - "@babel/plugin-transform-parameters": "^7.12.1", - "@babel/plugin-transform-property-literals": "^7.12.1", - "@babel/plugin-transform-regenerator": "^7.12.1", - "@babel/plugin-transform-reserved-words": "^7.12.1", - "@babel/plugin-transform-shorthand-properties": "^7.12.1", - "@babel/plugin-transform-spread": "^7.12.1", - "@babel/plugin-transform-sticky-regex": "^7.12.7", - "@babel/plugin-transform-template-literals": "^7.12.1", - "@babel/plugin-transform-typeof-symbol": "^7.12.10", - "@babel/plugin-transform-unicode-escapes": "^7.12.1", - "@babel/plugin-transform-unicode-regex": "^7.12.1", - "@babel/preset-modules": "^0.1.3", - "@babel/types": "^7.12.11", - "core-js-compat": "^3.8.0", - "semver": "^5.5.0" + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-transform-arrow-functions": "^7.14.5", + "@babel/plugin-transform-async-to-generator": "^7.14.5", + "@babel/plugin-transform-block-scoped-functions": "^7.14.5", + "@babel/plugin-transform-block-scoping": "^7.15.3", + "@babel/plugin-transform-classes": "^7.15.4", + "@babel/plugin-transform-computed-properties": "^7.14.5", + "@babel/plugin-transform-destructuring": "^7.14.7", + "@babel/plugin-transform-dotall-regex": "^7.14.5", + "@babel/plugin-transform-duplicate-keys": "^7.14.5", + "@babel/plugin-transform-exponentiation-operator": "^7.14.5", + "@babel/plugin-transform-for-of": "^7.15.4", + "@babel/plugin-transform-function-name": "^7.14.5", + "@babel/plugin-transform-literals": "^7.14.5", + "@babel/plugin-transform-member-expression-literals": "^7.14.5", + "@babel/plugin-transform-modules-amd": "^7.14.5", + "@babel/plugin-transform-modules-commonjs": "^7.15.4", + "@babel/plugin-transform-modules-systemjs": "^7.15.4", + "@babel/plugin-transform-modules-umd": "^7.14.5", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.14.9", + "@babel/plugin-transform-new-target": "^7.14.5", + "@babel/plugin-transform-object-super": "^7.14.5", + "@babel/plugin-transform-parameters": "^7.15.4", + "@babel/plugin-transform-property-literals": "^7.14.5", + "@babel/plugin-transform-regenerator": "^7.14.5", + "@babel/plugin-transform-reserved-words": "^7.14.5", + "@babel/plugin-transform-shorthand-properties": "^7.14.5", + "@babel/plugin-transform-spread": "^7.15.8", + "@babel/plugin-transform-sticky-regex": "^7.14.5", + "@babel/plugin-transform-template-literals": "^7.14.5", + "@babel/plugin-transform-typeof-symbol": "^7.14.5", + "@babel/plugin-transform-unicode-escapes": "^7.14.5", + "@babel/plugin-transform-unicode-regex": "^7.14.5", + "@babel/preset-modules": "^0.1.4", + "@babel/types": "^7.15.6", + "babel-plugin-polyfill-corejs2": "^0.2.2", + "babel-plugin-polyfill-corejs3": "^0.2.5", + "babel-plugin-polyfill-regenerator": "^0.2.2", + "core-js-compat": "^3.16.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "@babel/preset-modules": { @@ -1035,57 +1119,40 @@ } }, "@babel/template": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.13.tgz", - "integrity": "sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.15.4.tgz", + "integrity": "sha512-UgBAfEa1oGuYgDIPM2G+aHa4Nlo9Lh6mGD2bDBGMTbYnc38vulXPuC1MGjYILIEmlwl6Rd+BPR9ee3gm20CBtg==", "dev": true, "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/parser": "^7.12.13", - "@babel/types": "^7.12.13" + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4" } }, "@babel/traverse": { - "version": "7.13.15", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.13.15.tgz", - "integrity": "sha512-/mpZMNvj6bce59Qzl09fHEs8Bt8NnpEDQYleHUPZQ3wXUMvXi+HJPLars68oAbmp839fGoOkv2pSL2z9ajCIaQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.12.13", - "@babel/generator": "^7.13.9", - "@babel/helper-function-name": "^7.12.13", - "@babel/helper-split-export-declaration": "^7.12.13", - "@babel/parser": "^7.13.15", - "@babel/types": "^7.13.14", + "version": "7.15.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.4.tgz", + "integrity": "sha512-W6lQD8l4rUbQR/vYgSuCAE75ADyyQvOpFVsvPPdkhf6lATXAsQIG9YdtOcu8BB1dZ0LKu+Zo3c1wEcbKeuhdlA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.4", + "@babel/helper-function-name": "^7.15.4", + "@babel/helper-hoist-variables": "^7.15.4", + "@babel/helper-split-export-declaration": "^7.15.4", + "@babel/parser": "^7.15.4", + "@babel/types": "^7.15.4", "debug": "^4.1.0", "globals": "^11.1.0" - }, - "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } } }, "@babel/types": { - "version": "7.13.14", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.13.14.tgz", - "integrity": "sha512-A2aa3QTkWoyqsZZFl56MLUsfmh7O0gN41IPvXAE/++8ojpbz12SszD7JEGYVdn4f9Kt4amIei07swF1h4AqmmQ==", + "version": "7.15.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.6.tgz", + "integrity": "sha512-BPU+7QhqNjmWyDO0/vitH/CuhpV8ZmK1wpKva8nuyNF5MJfuRNWMc+hc14+u9xT93kvykMdncrJT19h74uB1Ig==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.12.11", - "lodash": "^4.17.19", + "@babel/helper-validator-identifier": "^7.14.9", "to-fast-properties": "^2.0.0" } }, @@ -1095,66 +1162,61 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, - "@cnakazawa/watch": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz", - "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", - "dev": true, - "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - } - }, "@eslint/eslintrc": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.2.2.tgz", - "integrity": "sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.3.tgz", + "integrity": "sha512-DHI1wDPoKCBPoLZA3qDR91+3te/wDSc1YhKg3jR8NxKKRJq2hwHwcWv31cSwSYvIBrmbENoYMWcenW8uproQqg==", "dev": true, "requires": { "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^12.1.0", + "debug": "^4.3.2", + "espree": "^9.0.0", + "globals": "^13.9.0", "ignore": "^4.0.6", "import-fresh": "^3.2.1", "js-yaml": "^3.13.1", - "lodash": "^4.17.19", "minimatch": "^3.0.4", "strip-json-comments": "^3.1.1" }, "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "globals": { + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", "dev": true, "requires": { - "ms": "2.1.2" + "type-fest": "^0.20.2" } }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "requires": { - "type-fest": "^0.8.1" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true } } }, + "@humanwhocodes/config-array": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.6.0.tgz", + "integrity": "sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -1178,6 +1240,16 @@ "path-exists": "^4.0.0" } }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -1232,16 +1304,16 @@ "dev": true }, "@jest/console": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-26.6.2.tgz", - "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.3.0.tgz", + "integrity": "sha512-+Tr/xoNiosjckq96xIGpDaGsybeIm45VWXpSvDR8T9deXmWjYKX85prhz8yFPhLG4UVOeMo/B6RI/+flw3sO8A==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^26.6.2", - "jest-util": "^26.6.2", + "jest-message-util": "^27.3.0", + "jest-util": "^27.3.0", "slash": "^3.0.0" }, "dependencies": { @@ -1255,9 +1327,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -1303,36 +1375,36 @@ } }, "@jest/core": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-26.6.3.tgz", - "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.3.0.tgz", + "integrity": "sha512-0B3PWQouwS651m8AbQDse08dfRlzLHqSmywRPGYn2ZzU6RT4aP2Xwz8mEWfSPXXZmtwAtNgUXy0Cbt6QsBqKvw==", "dev": true, "requires": { - "@jest/console": "^26.6.2", - "@jest/reporters": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/console": "^27.3.0", + "@jest/reporters": "^27.3.0", + "@jest/test-result": "^27.3.0", + "@jest/transform": "^27.3.0", + "@jest/types": "^27.2.5", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", + "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", - "jest-changed-files": "^26.6.2", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-resolve-dependencies": "^26.6.3", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "jest-watcher": "^26.6.2", - "micromatch": "^4.0.2", - "p-each-series": "^2.1.0", + "jest-changed-files": "^27.3.0", + "jest-config": "^27.3.0", + "jest-haste-map": "^27.3.0", + "jest-message-util": "^27.3.0", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.0", + "jest-resolve-dependencies": "^27.3.0", + "jest-runner": "^27.3.0", + "jest-runtime": "^27.3.0", + "jest-snapshot": "^27.3.0", + "jest-util": "^27.3.0", + "jest-validate": "^27.3.0", + "jest-watcher": "^27.3.0", + "micromatch": "^4.0.4", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" @@ -1347,19 +1419,10 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -1381,46 +1444,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -1428,12 +1457,12 @@ "dev": true }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } }, "supports-color": { @@ -1444,66 +1473,58 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, "@jest/environment": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-26.6.2.tgz", - "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.3.0.tgz", + "integrity": "sha512-OWx5RBd8QaPLlw7fL6l2IVyhYDpamaW3dDXlBnXb4IPGCIwoXAHZkmHV+VPIzb6xAkcPyXOmVm/rSaEneTqweg==", "dev": true, "requires": { - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/fake-timers": "^27.3.0", + "@jest/types": "^27.2.5", "@types/node": "*", - "jest-mock": "^26.6.2" + "jest-mock": "^27.3.0" } }, "@jest/fake-timers": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.6.2.tgz", - "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.3.0.tgz", + "integrity": "sha512-GCWgnItK6metb75QKflFxcVRlraVGomZonBQ+9B5UPc6wxBB3xzS7dATDWe/73R5P6BfnzCEaiizna771M5r9w==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "@sinonjs/fake-timers": "^6.0.1", + "@jest/types": "^27.2.5", + "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" + "jest-message-util": "^27.3.0", + "jest-mock": "^27.3.0", + "jest-util": "^27.3.0" } }, "@jest/globals": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-26.6.2.tgz", - "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.3.0.tgz", + "integrity": "sha512-EEqmQHMLXgEZfchMVAavUfJuZmORRrP+zhomfREqVE85d1nccd7nw8uN4FQDJ53m5Glm1XtVCyOIJ9kQLrqjeA==", "dev": true, "requires": { - "@jest/environment": "^26.6.2", - "@jest/types": "^26.6.2", - "expect": "^26.6.2" + "@jest/environment": "^27.3.0", + "@jest/types": "^27.2.5", + "expect": "^27.3.0" } }, "@jest/reporters": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-26.6.2.tgz", - "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.3.0.tgz", + "integrity": "sha512-D9QLaLgbH+nIjDbKIvoX7yiRX6aXHO56/GzOxKNzKuvJVYhrzeQHcCMttXpp5SB08TdxVvFOPKZfFvkIcVgfBA==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/console": "^27.3.0", + "@jest/test-result": "^27.3.0", + "@jest/transform": "^27.3.0", + "@jest/types": "^27.2.5", + "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", @@ -1514,16 +1535,15 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.0.2", - "jest-haste-map": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "node-notifier": "^8.0.0", + "jest-haste-map": "^27.3.0", + "jest-resolve": "^27.3.0", + "jest-util": "^27.3.0", + "jest-worker": "^27.3.0", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", "terminal-link": "^2.0.0", - "v8-to-istanbul": "^7.0.0" + "v8-to-istanbul": "^8.1.0" }, "dependencies": { "ansi-styles": { @@ -1536,9 +1556,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -1590,9 +1610,9 @@ } }, "@jest/source-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-26.6.2.tgz", - "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz", + "integrity": "sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g==", "dev": true, "requires": { "callsites": "^3.0.0", @@ -1609,47 +1629,46 @@ } }, "@jest/test-result": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-26.6.2.tgz", - "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.3.0.tgz", + "integrity": "sha512-5+rYZgj562oPKjExQngfboobeIF2FSrgAvoxlkrogEMIbgT7FY+VAMIkp03klVfJtqo3XKzVWkTfsDSmZFI29w==", "dev": true, "requires": { - "@jest/console": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/console": "^27.3.0", + "@jest/types": "^27.2.5", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz", - "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.3.0.tgz", + "integrity": "sha512-6eQHyBUCtK06sPfsufzEVijZtAtT7yGR1qaAZBlcz6P+FGJ569VW2O5o7mZc+L++uZc7BH4X2Ks7SMIgy1npJw==", "dev": true, "requires": { - "@jest/test-result": "^26.6.2", + "@jest/test-result": "^27.3.0", "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-runner": "^26.6.3", - "jest-runtime": "^26.6.3" + "jest-haste-map": "^27.3.0", + "jest-runtime": "^27.3.0" } }, "@jest/transform": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-26.6.2.tgz", - "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.3.0.tgz", + "integrity": "sha512-IKrFhIT/+WIfeNjIRKTwQN7HYCdjKF/mmBqoD660gyGWVw1MzCO9pQuEJK9GXEnFWIuOcMHlm8XfUaDohP/zxA==", "dev": true, "requires": { "@babel/core": "^7.1.0", - "@jest/types": "^26.6.2", + "@jest/types": "^27.2.5", "babel-plugin-istanbul": "^6.0.0", "chalk": "^4.0.0", "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", "graceful-fs": "^4.2.4", - "jest-haste-map": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-util": "^26.6.2", - "micromatch": "^4.0.2", + "jest-haste-map": "^27.3.0", + "jest-regex-util": "^27.0.6", + "jest-util": "^27.3.0", + "micromatch": "^4.0.4", "pirates": "^4.0.1", "slash": "^3.0.0", "source-map": "^0.6.1", @@ -1665,19 +1684,10 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -1699,37 +1709,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -1750,28 +1735,19 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.2.5.tgz", + "integrity": "sha512-nmuM4VuDtCZcY+eTpw+0nvstwReMsjPoj7ZR80/BbixulhLaiX+fbv8oeLW8WZlJMcsGQsTmMKT/iTZu1Uy/lQ==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^15.0.0", + "@types/yargs": "^16.0.0", "chalk": "^4.0.0" }, "dependencies": { @@ -1785,9 +1761,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -1826,49 +1802,81 @@ } } }, + "@mapbox/node-pre-gyp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz", + "integrity": "sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA==", + "dev": true, + "requires": { + "detect-libc": "^1.0.3", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.1", + "nopt": "^5.0.0", + "npmlog": "^4.1.2", + "rimraf": "^3.0.2", + "semver": "^7.3.4", + "tar": "^6.1.0" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, "@nicolo-ribaudo/chokidar-2": { - "version": "2.1.8-no-fsevents", - "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.tgz", - "integrity": "sha512-+nb9vWloHNNMFHjGofEam3wopE3m1yuambrrd/fnPc+lFOMB9ROTqQlche9ByFWNkdNqfSgR/kkQtQ8DzEWt2w==", + "version": "2.1.8-no-fsevents.3", + "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.3.tgz", + "integrity": "sha512-s88O1aVtXftvp5bCPB7WnmXc5IwOZZ7YPuwNPt+GtOOXpPvad1LfbmjYv+qII7zP6RU2QGnqve27dnLycEnyEQ==", "dev": true, - "optional": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } + "optional": true }, "@nodelib/fs.scandir": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz", - "integrity": "sha512-33g3pMJk3bg5nXbL/+CY6I2eJDzZAni49PfJnL5fghPTggPvBd/pFNSgJsdAgWptuFu7qq/ERvOYFlhvsLTCKA==", + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, "requires": { - "@nodelib/fs.stat": "2.0.4", + "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "@nodelib/fs.stat": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.4.tgz", - "integrity": "sha512-IYlHJA0clt2+Vg7bccq+TzRdJvv19c2INqBSsoOLp1je7xjtr7J26+WXR72MCdvU9q1qTzIWDfhMf+DRvQJK4Q==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true }, "@nodelib/fs.walk": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.6.tgz", - "integrity": "sha512-8Broas6vTtW4GIXTAHDoE32hnN2M5ykgCpWGbuXHQ15vEMqr23pB76e/GZcYsZCHALv50ktd24qhEyKr6wBtow==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "requires": { - "@nodelib/fs.scandir": "2.1.4", + "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, @@ -1882,18 +1890,24 @@ } }, "@sinonjs/fake-timers": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz", - "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.0.1.tgz", + "integrity": "sha512-AU7kwFxreVd6OAXcAFlKSmZquiRUU0FvYm44k1Y1QbK7Co4m0aqfGMhjykIeQp/H6rcl+nFmj0zfdUcGVs9Dew==", "dev": true, "requires": { "@sinonjs/commons": "^1.7.0" } }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, "@types/babel__core": { - "version": "7.1.14", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.14.tgz", - "integrity": "sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g==", + "version": "7.1.16", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", + "integrity": "sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -1904,18 +1918,18 @@ } }, "@types/babel__generator": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", - "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.3.tgz", + "integrity": "sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA==", "dev": true, "requires": { "@babel/types": "^7.0.0" } }, "@types/babel__template": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", - "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -1923,9 +1937,9 @@ } }, "@types/babel__traverse": { - "version": "7.11.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.1.tgz", - "integrity": "sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw==", + "version": "7.14.2", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", + "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", "dev": true, "requires": { "@babel/types": "^7.3.0" @@ -1956,28 +1970,28 @@ } }, "@types/istanbul-reports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", - "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", "dev": true, "requires": { "@types/istanbul-lib-report": "*" } }, "@types/jest": { - "version": "26.0.19", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.19.tgz", - "integrity": "sha512-jqHoirTG61fee6v6rwbnEuKhpSKih0tuhqeFbCmMmErhtu3BYlOZaXWjffgOstMM4S/3iQD31lI5bGLTrs97yQ==", + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.2.tgz", + "integrity": "sha512-4dRxkS/AFX0c5XW6IPMNOydLn2tEhNhJV7DnYK+0bjoJZ+QTmfucBlihX7aoEsh/ocYtkLC73UbnBXBXIxsULA==", "dev": true, "requires": { - "jest-diff": "^26.0.0", - "pretty-format": "^26.0.0" + "jest-diff": "^27.0.0", + "pretty-format": "^27.0.0" } }, "@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "version": "7.0.9", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", + "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", "dev": true }, "@types/json5": { @@ -1987,104 +2001,101 @@ "dev": true }, "@types/node": { - "version": "14.14.41", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.41.tgz", - "integrity": "sha512-dueRKfaJL4RTtSa7bWeTK1M+VH+Gns73oCgzvYfHZywRCoPSd8EkXBL0mZ9unPTveBn+D9phZBaxuzpwjWkW0g==", - "dev": true - }, - "@types/normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "version": "16.11.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.1.tgz", + "integrity": "sha512-PYGcJHL9mwl1Ek3PLiYgyEKtwTMmkMw4vbiyz/ps3pfdRYLVv+SN7qHVAImrjdAXxgluDEw6Ph4lyv+m9UpRmA==", "dev": true }, "@types/prettier": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.2.3.tgz", - "integrity": "sha512-PijRCG/K3s3w1We6ynUKdxEc5AcuuH3NBmMDP8uvKVp6X43UY7NQlTzczakXP3DJR0F4dfNQIGjU2cUeRYs2AA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz", + "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", "dev": true }, "@types/stack-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.0.tgz", - "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, "@types/yargs": { - "version": "15.0.13", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", - "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "version": "16.0.4", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz", + "integrity": "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw==", "dev": true, "requires": { "@types/yargs-parser": "*" } }, "@types/yargs-parser": { - "version": "20.2.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", - "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", + "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", "dev": true }, "@typescript-eslint/experimental-utils": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.0.tgz", - "integrity": "sha512-xJXHHl6TuAxB5AWiVrGhvbGL8/hbiCQ8FiWwObO3r0fnvBdrbWEDy1hlvGQOAWc6qsCWuWMKdVWlLAEMpxnddg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.0.0.tgz", + "integrity": "sha512-Dnp4dFIsZcPawD6CT1p5NibNUQyGSEz80sULJZkyhyna8AEqArmfwMwJPbmKzWVo4PabqNVzHYlzmcdLQWk+pg==", "dev": true, "requires": { - "@types/json-schema": "^7.0.3", - "@typescript-eslint/scope-manager": "4.22.0", - "@typescript-eslint/types": "4.22.0", - "@typescript-eslint/typescript-estree": "4.22.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^2.0.0" + "@types/json-schema": "^7.0.7", + "@typescript-eslint/scope-manager": "5.0.0", + "@typescript-eslint/types": "5.0.0", + "@typescript-eslint/typescript-estree": "5.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "dependencies": { + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } } }, "@typescript-eslint/scope-manager": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.22.0.tgz", - "integrity": "sha512-OcCO7LTdk6ukawUM40wo61WdeoA7NM/zaoq1/2cs13M7GyiF+T4rxuA4xM+6LeHWjWbss7hkGXjFDRcKD4O04Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.0.0.tgz", + "integrity": "sha512-5RFjdA/ain/MDUHYXdF173btOKncIrLuBmA9s6FJhzDrRAyVSA+70BHg0/MW6TE+UiKVyRtX91XpVS0gVNwVDQ==", "dev": true, "requires": { - "@typescript-eslint/types": "4.22.0", - "@typescript-eslint/visitor-keys": "4.22.0" + "@typescript-eslint/types": "5.0.0", + "@typescript-eslint/visitor-keys": "5.0.0" } }, "@typescript-eslint/types": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.22.0.tgz", - "integrity": "sha512-sW/BiXmmyMqDPO2kpOhSy2Py5w6KvRRsKZnV0c4+0nr4GIcedJwXAq+RHNK4lLVEZAJYFltnnk1tJSlbeS9lYA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.0.0.tgz", + "integrity": "sha512-dU/pKBUpehdEqYuvkojmlv0FtHuZnLXFBn16zsDmlFF3LXkOpkAQ2vrKc3BidIIve9EMH2zfTlxqw9XM0fFN5w==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.0.tgz", - "integrity": "sha512-TkIFeu5JEeSs5ze/4NID+PIcVjgoU3cUQUIZnH3Sb1cEn1lBo7StSV5bwPuJQuoxKXlzAObjYTilOEKRuhR5yg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.0.0.tgz", + "integrity": "sha512-V/6w+PPQMhinWKSn+fCiX5jwvd1vRBm7AX7SJQXEGQtwtBvjMPjaU3YTQ1ik2UF1u96X7tsB96HMnulG3eLi9Q==", "dev": true, "requires": { - "@typescript-eslint/types": "4.22.0", - "@typescript-eslint/visitor-keys": "4.22.0", - "debug": "^4.1.1", - "globby": "^11.0.1", + "@typescript-eslint/types": "5.0.0", + "@typescript-eslint/visitor-keys": "5.0.0", + "debug": "^4.3.1", + "globby": "^11.0.3", "is-glob": "^4.0.1", - "semver": "^7.3.2", - "tsutils": "^3.17.1" + "semver": "^7.3.5", + "tsutils": "^3.21.0" }, "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -2097,13 +2108,13 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "4.22.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.0.tgz", - "integrity": "sha512-nnMu4F+s4o0sll6cBSsTeVsT4cwxB7zECK3dFxzEjPBii9xLpq4yqqsy/FU5zMfan6G60DKZSCXAa3sHJZrcYw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.0.0.tgz", + "integrity": "sha512-yRyd2++o/IrJdyHuYMxyFyBhU762MRHQ/bAGQeTnN3pGikfh+nEmM61XTqaDH1XDp53afZ+waXrk0ZvenoZ6xw==", "dev": true, "requires": { - "@typescript-eslint/types": "4.22.0", - "eslint-visitor-keys": "^2.0.0" + "@typescript-eslint/types": "5.0.0", + "eslint-visitor-keys": "^3.0.0" } }, "abab": { @@ -2119,9 +2130,9 @@ "dev": true }, "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", "dev": true }, "acorn-globals": { @@ -2132,12 +2143,20 @@ "requires": { "acorn": "^7.1.1", "acorn-walk": "^7.1.1" + }, + "dependencies": { + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true + } } }, "acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true }, "acorn-walk": { @@ -2146,6 +2165,15 @@ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "dev": true }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2182,9 +2210,9 @@ } }, "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { @@ -2197,24 +2225,13 @@ } }, "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", "dev": true, "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, "aproba": { @@ -2224,9 +2241,9 @@ "dev": true }, "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", "dev": true, "requires": { "delegates": "^1.0.0", @@ -2252,24 +2269,6 @@ "@babel/runtime-corejs3": "^7.10.2" } }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, "array-includes": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", @@ -2289,99 +2288,162 @@ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, "array.prototype.flat": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", - "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", + "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", "dev": true, "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1" + "es-abstract": "^1.19.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "dev": true + } } }, "array.prototype.flatmap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.4.tgz", - "integrity": "sha512-r9Z0zYoxqHz60vvQbWEdXIEtCwHF0yxaWfno9qzXeNHvfyl3BZqygmGzb84dsubyaXLH4husF+NFgMSdpZhk2Q==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", + "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", "dev": true, "requires": { "call-bind": "^1.0.0", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.1", - "function-bind": "^1.1.1" - } - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" + "es-abstract": "^1.19.0" + }, + "dependencies": { + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "dev": true + } } }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, "ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=", "dev": true }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true, - "optional": true - }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", "dev": true }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, "axe-core": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.1.4.tgz", @@ -2395,16 +2457,16 @@ "dev": true }, "babel-jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-26.6.3.tgz", - "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.3.0.tgz", + "integrity": "sha512-+Utvd2yZkT7tkgbBqVcH3uRpgRSTKRi0uBtVkjmuw2jFxp45rQ9fROSqqeHKzHYRelgdVOtQ3M745Wnyme/xOg==", "dev": true, "requires": { - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/babel__core": "^7.1.7", + "@jest/transform": "^27.3.0", + "@jest/types": "^27.2.5", + "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^26.6.2", + "babel-preset-jest": "^27.2.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", "slash": "^3.0.0" @@ -2420,9 +2482,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -2477,22 +2539,43 @@ } }, "babel-plugin-istanbul": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", - "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-instrument": "^5.0.4", "test-exclude": "^6.0.0" + }, + "dependencies": { + "istanbul-lib-instrument": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.0.4.tgz", + "integrity": "sha512-W6jJF9rLGEISGoCyXRqa/JCGQGmmxPO10TMu7izaUTynxvBvTjqzAIIGCK9USBmIbQAaSWD6XJPrM9Pv5INknw==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } } }, "babel-plugin-jest-hoist": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", - "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz", + "integrity": "sha512-TOux9khNKdi64mW+0OIhcmbAn75tTlzKhxmiNXevQaPbrBYK7YKjP1jl6NHTJ6XR5UgUrJbCnWlKVnJn29dfjw==", "dev": true, "requires": { "@babel/template": "^7.3.3", @@ -2501,6 +2584,44 @@ "@types/babel__traverse": "^7.0.6" } }, + "babel-plugin-polyfill-corejs2": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz", + "integrity": "sha512-kISrENsJ0z5dNPq5eRvcctITNHYXWOA4DUZRFYCz3jYCcvTb/A546LIddmoGNMVYg2U38OyFeNosQwI9ENTqIQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.13.11", + "@babel/helper-define-polyfill-provider": "^0.2.2", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.2.5.tgz", + "integrity": "sha512-ninF5MQNwAX9Z7c9ED+H2pGt1mXdP4TqzlHKyPIYmJIYz0N+++uwdM7RnJukklhzJ54Q84vA4ZJkgs7lu5vqcw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.2.2", + "core-js-compat": "^3.16.2" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.2.2.tgz", + "integrity": "sha512-Goy5ghsc21HgPDFtzRkSirpZVW35meGoTmTOb2bxqdl60ghub4xOidgNTHaZfQ2FaxQsKmwvXtOAkcIS4SMBWg==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.2.2" + } + }, "babel-preset-current-node-syntax": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", @@ -2522,12 +2643,12 @@ } }, "babel-preset-jest": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", - "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.2.0.tgz", + "integrity": "sha512-z7MgQ3peBwN5L5aCqBKnF6iqdlvZvFUQynEhu0J+X9nHLU72jO3iY331lcYrg+AssJ8q7xsv5/3AICzVmJ/wvg==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^26.6.2", + "babel-plugin-jest-hoist": "^27.2.0", "babel-preset-current-node-syntax": "^1.0.0" } }, @@ -2537,74 +2658,10 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true, "optional": true }, @@ -2619,32 +2676,12 @@ } }, "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" } }, "browser-process-hrtime": { @@ -2654,16 +2691,16 @@ "dev": true }, "browserslist": { - "version": "4.16.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.4.tgz", - "integrity": "sha512-d7rCxYV8I9kj41RH8UKYnvDYCRENUlHRgyXy/Rhr/1BaeLGfiCptEdFE8MIrvGfWbBFNjVYx76SQWvNX1j+/cQ==", + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.4.tgz", + "integrity": "sha512-Zg7RpbZpIJRW3am9Lyckue7PLytvVxxhJj1CaJVlCWENsGEAOlnlt8X0ZxGRPp7Bt9o8tIRM5SEXy4BCPMJjLQ==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001208", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.712", + "caniuse-lite": "^1.0.30001265", + "electron-to-chromium": "^1.3.867", "escalade": "^3.1.1", - "node-releases": "^1.1.71" + "node-releases": "^2.0.0", + "picocolors": "^1.0.0" } }, "bser": { @@ -2676,28 +2713,11 @@ } }, "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -2721,37 +2741,22 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001214", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001214.tgz", - "integrity": "sha512-O2/SCpuaU3eASWVaesQirZv1MSjUNOvmugaD8zNSJqw6Vv5SGwoOpA9LJs3pNPfM745nxqPvfZY3MQKY4AKHYg==", + "version": "1.0.30001269", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001269.tgz", + "integrity": "sha512-UOy8okEVs48MyHYgV+RdW1Oiudl1H6KolybD6ZquD0VcrPSgj25omXO1S7rDydjpqaISCwA8Pyx+jUQKZwWO5w==", "dev": true }, "canvas": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.7.0.tgz", - "integrity": "sha512-pzCxtkHb+5su5MQjTtepMDlIOtaXo277x0C0u3nMOxtkhTyQ+h2yNKhlROAaDllWgRyePAUitC08sXw26Eb6aw==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.8.0.tgz", + "integrity": "sha512-gLTi17X8WY9Cf5GZ2Yns8T5lfBOcGgFehDFb+JQwDqdOoBOcECS9ZWMEAqMSVcMYwXD659J8NyzjRY/2aE+C2Q==", "dev": true, "requires": { + "@mapbox/node-pre-gyp": "^1.0.0", "nan": "^2.14.0", - "node-pre-gyp": "^0.15.0", "simple-get": "^3.0.3" } }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, - "requires": { - "rsvp": "^4.8.4" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -2770,185 +2775,75 @@ "dev": true }, "chokidar": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.1.tgz", - "integrity": "sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", "dev": true, "optional": true, "requires": { - "anymatch": "~3.1.1", + "anymatch": "~3.1.2", "braces": "~3.0.2", - "fsevents": "~2.3.1", - "glob-parent": "~5.1.0", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", - "readdirp": "~3.5.0" + "readdirp": "~3.6.0" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true + }, + "ci-info": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" }, "dependencies": { - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "optional": true, "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "dev": true, - "optional": true - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "optional": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "optional": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "optional": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "optional": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "optional": true - }, - "readdirp": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz", - "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==", - "dev": true, - "optional": true, - "requires": { - "picomatch": "^2.2.1" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "optional": true, - "requires": { - "is-number": "^7.0.0" - } - } - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "cjs-module-lexer": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", - "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", - "dev": true - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } } } @@ -2971,16 +2866,6 @@ "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", "dev": true }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, "color-convert": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", @@ -2996,12 +2881,6 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, - "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", - "dev": true - }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -3017,12 +2896,6 @@ "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", "dev": true }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -3041,34 +2914,22 @@ "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", "dev": true }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, "convert-source-map": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", - "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", "dev": true, "requires": { "safe-buffer": "~5.1.1" } }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, "core-js-compat": { - "version": "3.10.2", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.10.2.tgz", - "integrity": "sha512-IGHnpuaM1N++gLSPI1F1wu3WXICPxSyj/Q++clcwsIOnUVp5uKUIPl/+6h0TQ112KU3fMiSxqJuM+OrCyKj5+A==", + "version": "3.18.3", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.18.3.tgz", + "integrity": "sha512-4zP6/y0a2RTHN5bRGT7PTq9lVt3WzvffTNjqnTKsXhkAYNDTkdCLOIfAdOLcQ/7TDdyRj3c+NeHe1NmF1eDScw==", "dev": true, "requires": { - "browserslist": "^4.16.4", + "browserslist": "^4.17.3", "semver": "7.0.0" }, "dependencies": { @@ -3087,9 +2948,9 @@ "dev": true }, "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, "cross-spawn": { @@ -3132,15 +2993,6 @@ "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==", "dev": true }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, "data-urls": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", @@ -3150,33 +3002,49 @@ "abab": "^2.0.3", "whatwg-mimetype": "^2.3.0", "whatwg-url": "^8.0.0" + }, + "dependencies": { + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } + } } }, "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "2.1.2" } }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, "decimal.js": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.1.tgz", - "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz", + "integrity": "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==", "dev": true }, "decompress-response": { @@ -3188,16 +3056,16 @@ "mimic-response": "^2.0.0" } }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", "dev": true }, "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, "deepmerge": { @@ -3215,47 +3083,6 @@ "object-keys": "^1.0.12" } }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -3281,9 +3108,9 @@ "dev": true }, "diff-sequences": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", + "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", "dev": true }, "dir-glob": { @@ -3293,14 +3120,6 @@ "dev": true, "requires": { "path-type": "^4.0.0" - }, - "dependencies": { - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - } } }, "doctrine": { @@ -3329,26 +3148,16 @@ } } }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "electron-to-chromium": { - "version": "1.3.717", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.717.tgz", - "integrity": "sha512-OfzVPIqD1MkJ7fX+yTl2nKyOE4FReeVfMCzzxQS+Kp43hZYwHwThlGP+EGIZRXJsxCM7dqo8Y65NOX/HP12iXQ==", + "version": "1.3.871", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.871.tgz", + "integrity": "sha512-qcLvDUPf8DSIMWarHT2ptgcqrYg62n3vPA7vhrOF24d8UNzbUBaHu2CySiENR3nEDzYgaN60071t0F6KLYMQ7Q==", "dev": true }, "emittery": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.7.2.tgz", - "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", + "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", "dev": true }, "emoji-regex": { @@ -3357,15 +3166,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, "enquirer": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", @@ -3375,15 +3175,6 @@ "ansi-colors": "^4.1.1" } }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, "es-abstract": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", @@ -3444,12 +3235,6 @@ "source-map": "~0.6.1" }, "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -3499,46 +3284,47 @@ } }, "eslint": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.16.0.tgz", - "integrity": "sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.0.1.tgz", + "integrity": "sha512-LsgcwZgQ72vZ+SMp4K6pAnk2yFDWL7Ti4pJaRvsZ0Hsw2h8ZjUIW38a9AFn2cZXdBMlScMFYYgsSp4ttFI/0bA==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@eslint/eslintrc": "^0.2.2", + "@eslint/eslintrc": "^1.0.3", + "@humanwhocodes/config-array": "^0.6.0", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", - "debug": "^4.0.1", + "debug": "^4.3.2", "doctrine": "^3.0.0", "enquirer": "^2.3.5", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.2.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^6.0.0", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", + "esquery": "^1.4.0", "esutils": "^2.0.2", - "file-entry-cache": "^6.0.0", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", "ignore": "^4.0.6", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", + "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", - "lodash": "^4.17.19", + "lodash.merge": "^4.6.2", "minimatch": "^3.0.4", "natural-compare": "^1.4.0", "optionator": "^0.9.1", "progress": "^2.0.0", - "regexpp": "^3.1.0", + "regexpp": "^3.2.0", "semver": "^7.2.1", "strip-ansi": "^6.0.0", "strip-json-comments": "^3.1.0", - "table": "^6.0.4", "text-table": "^0.2.0", "v8-compile-cache": "^2.0.3" }, @@ -3553,9 +3339,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -3577,31 +3363,28 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true }, "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "requires": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" } }, "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "version": "13.11.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz", + "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==", "dev": true, "requires": { - "type-fest": "^0.8.1" + "type-fest": "^0.20.2" } }, "has-flag": { @@ -3610,12 +3393,6 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "semver": { "version": "7.3.5", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", @@ -3626,20 +3403,14 @@ } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -3674,65 +3445,174 @@ } }, "eslint-import-resolver-node": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", - "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", "dev": true, "requires": { - "debug": "^2.6.9", - "resolve": "^1.13.1" + "debug": "^3.2.7", + "resolve": "^1.20.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } } }, "eslint-module-utils": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.0.tgz", - "integrity": "sha512-6j9xxegbqe8/kZY8cYpcp0xhbK0EgJlg3g9mib3/miLaExuuwc3n5UEfSnU6hWMbT0FAYVvDbL9RrRgpUeQIvA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz", + "integrity": "sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ==", "dev": true, "requires": { - "debug": "^2.6.9", + "debug": "^3.2.7", + "find-up": "^2.1.0", "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } } }, "eslint-plugin-import": { - "version": "2.22.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", - "integrity": "sha512-8K7JjINHOpH64ozkAhpT3sd+FswIZTfMZTjdx052pnWrgRCVfp8op9tbjpAk3DdUeI/Ba4C8OjdC0r90erHEOw==", + "version": "2.25.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.2.tgz", + "integrity": "sha512-qCwQr9TYfoBHOFcVGKY9C9unq05uOxxdklmBXLVvcwo68y5Hta6/GzCZEMx2zQiu0woKNEER0LE7ZgaOfBU14g==", "dev": true, "requires": { - "array-includes": "^3.1.1", - "array.prototype.flat": "^1.2.3", - "contains-path": "^0.1.0", + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", "debug": "^2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "^0.3.4", - "eslint-module-utils": "^2.6.0", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.0", "has": "^1.0.3", + "is-core-module": "^2.7.0", + "is-glob": "^4.0.3", "minimatch": "^3.0.4", - "object.values": "^1.1.1", - "read-pkg-up": "^2.0.0", - "resolve": "^1.17.0", - "tsconfig-paths": "^3.9.0" + "object.values": "^1.1.5", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.11.0" }, "dependencies": { + "array-includes": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", "dev": true, "requires": { - "esutils": "^2.0.2", - "isarray": "^1.0.0" + "has-tostringtag": "^1.0.0" } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "dev": true } } }, "eslint-plugin-jest": { - "version": "24.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-24.1.3.tgz", - "integrity": "sha512-dNGGjzuEzCE3d5EPZQ/QGtmlMotqnYWD/QpCZ1UuZlrMAdhG5rldh0N0haCvhGnUkSeuORS5VNROwF9Hrgn3Lg==", + "version": "25.2.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-25.2.2.tgz", + "integrity": "sha512-frn5yhOF60U4kcqozO3zKTNZQUk+mfx037XOy2iiYL8FhorEkuCuL3/flzKcY1ECDP2WYT9ydmvlO3fRW9o4mg==", "dev": true, "requires": { - "@typescript-eslint/experimental-utils": "^4.0.1" + "@typescript-eslint/experimental-utils": "^5.0.0" } }, "eslint-plugin-jsx-a11y": { @@ -3763,22 +3643,25 @@ } }, "eslint-plugin-react": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz", - "integrity": "sha512-8MaEggC2et0wSF6bUeywF7qQ46ER81irOdWS4QWxnnlAEsnzeBevk1sWh7fhpCghPpXb+8Ks7hvaft6L/xsR6g==", + "version": "7.26.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.26.1.tgz", + "integrity": "sha512-Lug0+NOFXeOE+ORZ5pbsh6mSKjBKXDXItUD2sQoT+5Yl0eoT82DqnXeTMfUare4QVCn9QwXbfzO/dBLjLXwVjQ==", "dev": true, "requires": { - "array-includes": "^3.1.1", - "array.prototype.flatmap": "^1.2.3", + "array-includes": "^3.1.3", + "array.prototype.flatmap": "^1.2.4", "doctrine": "^2.1.0", - "has": "^1.0.3", + "estraverse": "^5.2.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "object.entries": "^1.1.2", - "object.fromentries": "^2.0.2", - "object.values": "^1.1.1", + "minimatch": "^3.0.4", + "object.entries": "^1.1.4", + "object.fromentries": "^2.0.4", + "object.hasown": "^1.0.0", + "object.values": "^1.1.4", "prop-types": "^15.7.2", - "resolve": "^1.18.1", - "string.prototype.matchall": "^4.0.2" + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.5" }, "dependencies": { "doctrine": { @@ -3789,59 +3672,137 @@ "requires": { "esutils": "^2.0.2" } - } - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + }, + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "dev": true + }, + "object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "resolve": { + "version": "2.0.0-next.3", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", + "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz", + "integrity": "sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" } }, "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "eslint-visitor-keys": "^1.1.0" + "eslint-visitor-keys": "^2.0.0" }, "dependencies": { "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true } } }, "eslint-visitor-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz", - "integrity": "sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.0.0.tgz", + "integrity": "sha512-mJOZa35trBTb3IyRmo8xmKBZlxf+N7OnUl4+ZhJHs/r+0770Wh/LEACE2pqMGMe27G/4y8P2bYGk4J70IC5k1Q==", "dev": true }, "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.0.0.tgz", + "integrity": "sha512-r5EQJcYZ2oaGbeR0jR0fFVijGOcwai07/690YRXLINuhmVeRY4UKSAsQPe/0BNuDgwP7Ophoc1PRsr2E3tkbdQ==", "dev": true, "requires": { - "acorn": "^7.4.0", + "acorn": "^8.5.0", "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } + "eslint-visitor-keys": "^3.0.0" } }, "esprima": { @@ -3857,14 +3818,6 @@ "dev": true, "requires": { "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } } }, "esrecurse": { @@ -3874,20 +3827,12 @@ "dev": true, "requires": { "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } } }, "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", "dev": true }, "esutils": { @@ -3896,70 +3841,21 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, - "exec-sh": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.6.tgz", - "integrity": "sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==", - "dev": true - }, "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" } }, "exit": { @@ -3968,179 +3864,28 @@ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "dev": true }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, "expect": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-26.6.2.tgz", - "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.3.0.tgz", + "integrity": "sha512-JBRU82EBkZUBqLBAoF3ovzNGEBm14QQnePK4PmZdm6de6q/UzPnmIuWP3dRCw/FE8wRQhf/1eKzy1p1q8d6EvQ==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "ansi-styles": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-regex-util": "^26.0.0" + "@jest/types": "^27.2.5", + "ansi-styles": "^5.0.0", + "jest-get-type": "^27.0.6", + "jest-matcher-utils": "^27.3.0", + "jest-message-util": "^27.3.0", + "jest-regex-util": "^27.0.6" }, "dependencies": { "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true } } }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -4148,71 +3893,16 @@ "dev": true }, "fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", + "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", + "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" - }, - "dependencies": { - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - } + "micromatch": "^4.0.4" } }, "fast-json-stable-stringify": { @@ -4228,9 +3918,9 @@ "dev": true }, "fastq": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", - "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "requires": { "reusify": "^1.0.4" @@ -4255,26 +3945,12 @@ } }, "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "to-regex-range": "^5.0.1" } }, "find-up": { @@ -4294,64 +3970,32 @@ "requires": { "flatted": "^3.1.0", "rimraf": "^3.0.2" - }, - "dependencies": { - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } } }, "flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", - "dev": true - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz", + "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==", "dev": true }, "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", + "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", "dev": true, "requires": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", + "combined-stream": "^1.0.8", "mime-types": "^2.1.12" } }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, "fs-minipass": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz", - "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", "dev": true, "requires": { - "minipass": "^2.6.0" + "minipass": "^3.0.0" } }, "fs-readdir-recursive": { @@ -4431,33 +4075,25 @@ "dev": true }, "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", "dev": true, "requires": { - "assert-plus": "^1.0.0" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" } }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -4469,26 +4105,12 @@ } }, "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "optional": true, "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "optional": true, - "requires": { - "is-extglob": "^2.1.0" - } - } + "is-glob": "^4.0.1" } }, "globals": { @@ -4498,9 +4120,9 @@ "dev": true }, "globby": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", - "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz", + "integrity": "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg==", "dev": true, "requires": { "array-union": "^2.1.0", @@ -4526,34 +4148,11 @@ } }, "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", + "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==", "dev": true }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true, - "optional": true - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "dev": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -4581,48 +4180,19 @@ "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true - }, - "has-value": { + "has-tostringtag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", "dev": true, "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "has-symbols": "^1.0.2" } }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", "dev": true }, "html-encoding-sniffer": { @@ -4640,27 +4210,37 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", "dev": true, "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "agent-base": "6", + "debug": "4" } }, "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, "husky": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/husky/-/husky-6.0.0.tgz", - "integrity": "sha512-SQS2gDTB7tBN486QSoKPKQItZw97BMOd+Kdb6ghfpBc0yXyzrddI0oDV5MkDAbuB4X2mO3/nj60TRMcYxwzZeQ==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/husky/-/husky-7.0.2.tgz", + "integrity": "sha512-8yKEWNX4z2YsofXAMT7KvA1g8p+GxtB1ffV8XtpAEGuXNAbCV5wdNKH+qTpw8SM9fh4aMPDR+yQuKfgnreyZlg==", "dev": true }, "iconv-lite": { @@ -4678,15 +4258,6 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, - "ignore-walk": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz", - "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==", - "dev": true, - "requires": { - "minimatch": "^3.0.4" - } - }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", @@ -4698,9 +4269,9 @@ } }, "import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", + "integrity": "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA==", "dev": true, "requires": { "pkg-dir": "^4.2.0", @@ -4789,12 +4360,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, "internal-slot": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", @@ -4806,32 +4371,6 @@ "side-channel": "^1.0.4" } }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, "is-bigint": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", @@ -4839,13 +4378,13 @@ "dev": true }, "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "optional": true, "requires": { - "binary-extensions": "^1.0.0" + "binary-extensions": "^2.0.0" } }, "is-boolean-object": { @@ -4857,12 +4396,6 @@ "call-bind": "^1.0.0" } }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, "is-callable": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", @@ -4870,79 +4403,27 @@ "dev": true }, "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.0.tgz", + "integrity": "sha512-kDXyttuLeslKAHYL/K28F2YkM3x5jvFPEw3yXbRptXydjD9rpLEz+C5K5iutY9ZiUu6AP41JdvRQwF4Iqs4ZCQ==", "dev": true, "requires": { - "ci-info": "^2.0.0" + "ci-info": "^3.1.1" } }, "is-core-module": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", - "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", "dev": true, "requires": { "has": "^1.0.3" } }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "is-date-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "optional": true - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", "dev": true }, "is-extglob": { @@ -4967,9 +4448,9 @@ "dev": true }, "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" @@ -4982,24 +4463,10 @@ "dev": true }, "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true }, "is-number-object": { "version": "1.0.4", @@ -5007,15 +4474,6 @@ "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", "dev": true }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, "is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", @@ -5032,10 +4490,16 @@ "has-symbols": "^1.0.1" } }, + "is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "dev": true + }, "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true }, "is-string": { @@ -5059,20 +4523,13 @@ "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", "dev": true }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "is-weakref": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.1.tgz", + "integrity": "sha512-b2jKc2pQZjaeFYWEf7ScFj+Be1I+PXmlu572Q8coTXZ+LD/QQZ7ShPMst8h16riVgyXTQwUsFEl74mDvc/3MHQ==", "dev": true, - "optional": true, "requires": { - "is-docker": "^2.0.0" + "call-bind": "^1.0.0" } }, "isarray": { @@ -5087,22 +4544,10 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, "istanbul-lib-coverage": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", - "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", "dev": true }, "istanbul-lib-instrument": { @@ -5169,9 +4614,9 @@ } }, "istanbul-lib-source-maps": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", - "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, "requires": { "debug": "^4.1.1", @@ -5179,21 +4624,6 @@ "source-map": "^0.6.1" }, "dependencies": { - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5203,9 +4633,9 @@ } }, "istanbul-reports": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", - "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.5.tgz", + "integrity": "sha512-5+19PlhnGabNWB7kOFnuxT8H3T/iIyQzIbQMxXsURmmvKg86P2sbkrGOT77VnHw0Qr0gc2XzRaRfMZYYbSQCJQ==", "dev": true, "requires": { "html-escaper": "^2.0.0", @@ -5213,14 +4643,14 @@ } }, "jest": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest/-/jest-26.6.3.tgz", - "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.3.0.tgz", + "integrity": "sha512-ZSwT6ROUbUs3bXirxzxBvohE/1y7t+IHIu3fL8WgIeJppE2XsFoa2dB03CI9kXA81znW0Kt0t2R+QVOWeY8cYw==", "dev": true, "requires": { - "@jest/core": "^26.6.3", + "@jest/core": "^27.3.0", "import-local": "^3.0.2", - "jest-cli": "^26.6.3" + "jest-cli": "^27.3.0" }, "dependencies": { "ansi-styles": { @@ -5233,9 +4663,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5264,24 +4694,23 @@ "dev": true }, "jest-cli": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-26.6.3.tgz", - "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.3.0.tgz", + "integrity": "sha512-PUM2RHhqgGRuGc+7QTuyfqPPWGDTCQNMKhtlVBTBYOvhP+7g8a1a7OztM/wfpsKHfqQLHFIe1Mms6jVSXSi4Vg==", "dev": true, "requires": { - "@jest/core": "^26.6.3", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/core": "^27.3.0", + "@jest/test-result": "^27.3.0", + "@jest/types": "^27.2.5", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.4", "import-local": "^3.0.2", - "is-ci": "^2.0.0", - "jest-config": "^26.6.3", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", + "jest-config": "^27.3.0", + "jest-util": "^27.3.0", + "jest-validate": "^27.3.0", "prompts": "^2.0.1", - "yargs": "^15.4.1" + "yargs": "^16.2.0" } }, "supports-color": { @@ -5296,83 +4725,127 @@ } }, "jest-changed-files": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.6.2.tgz", - "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.3.0.tgz", + "integrity": "sha512-9DJs9garMHv4RhylUMZgbdCJ3+jHSkpL9aaVKp13xtXAD80qLTLrqcDZL1PHA9dYA0bCI86Nv2BhkLpLhrBcPg==", + "dev": true, + "requires": { + "@jest/types": "^27.2.5", + "execa": "^5.0.0", + "throat": "^6.0.1" + } + }, + "jest-circus": { + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.3.0.tgz", + "integrity": "sha512-i2P6t92Z6qujHD7C0nVYWm9YofUBMbOOTE9q9vEGi9qFotKUZv1H8M0H3NPTOWButgFuSXZfcwGBXGDAt7b9NA==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "execa": "^4.0.0", - "throat": "^5.0.0" + "@jest/environment": "^27.3.0", + "@jest/test-result": "^27.3.0", + "@jest/types": "^27.2.5", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "expect": "^27.3.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^27.3.0", + "jest-matcher-utils": "^27.3.0", + "jest-message-util": "^27.3.0", + "jest-runtime": "^27.3.0", + "jest-snapshot": "^27.3.0", + "jest-util": "^27.3.0", + "pretty-format": "^27.3.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3", + "throat": "^6.0.1" }, "dependencies": { - "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" + "color-convert": "^2.0.1" } }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "pump": "^3.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "path-key": "^3.0.0" + "has-flag": "^4.0.0" } } } }, "jest-config": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-26.6.3.tgz", - "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.3.0.tgz", + "integrity": "sha512-hGknSnu6qJmwENNSUNY4qQjE9PENIYp4P8yHLVzo7qoQN4wuYHZuZEwAKaoQ66iHeSXmcZkCqFvAUa5WFdB0sg==", "dev": true, "requires": { "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^26.6.3", - "@jest/types": "^26.6.2", - "babel-jest": "^26.6.3", + "@jest/test-sequencer": "^27.3.0", + "@jest/types": "^27.2.5", + "babel-jest": "^27.3.0", "chalk": "^4.0.0", "deepmerge": "^4.2.2", "glob": "^7.1.1", "graceful-fs": "^4.2.4", - "jest-environment-jsdom": "^26.6.2", - "jest-environment-node": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-jasmine2": "^26.6.3", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2" + "is-ci": "^3.0.0", + "jest-circus": "^27.3.0", + "jest-environment-jsdom": "^27.3.0", + "jest-environment-node": "^27.3.0", + "jest-get-type": "^27.0.6", + "jest-jasmine2": "^27.3.0", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.0", + "jest-runner": "^27.3.0", + "jest-util": "^27.3.0", + "jest-validate": "^27.3.0", + "micromatch": "^4.0.4", + "pretty-format": "^27.3.0" }, "dependencies": { "ansi-styles": { @@ -5384,19 +4857,10 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5418,37 +4882,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5457,28 +4896,19 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, "jest-diff": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", - "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.3.0.tgz", + "integrity": "sha512-Nl2rE58B2ye+RvPcU4hN+6wBCHxX7aWz6RMTMFxe9jAg8ZueMj5QQ+T/nmHRutbBc5BEjrbbEWOrRzp9rUEsYA==", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "diff-sequences": "^27.0.6", + "jest-get-type": "^27.0.6", + "pretty-format": "^27.3.0" }, "dependencies": { "ansi-styles": { @@ -5491,9 +4921,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5533,25 +4963,25 @@ } }, "jest-docblock": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz", - "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz", + "integrity": "sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-26.6.2.tgz", - "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.3.0.tgz", + "integrity": "sha512-i7qQt+puYusxOoiNyq/M6EyNcfEbvKvqOp89FbiHfm6/POTxgzpp5wAmoS9+BAssoX20t7Zt1A1M7yT3FLVvdg==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.2.5", "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2" + "jest-get-type": "^27.0.6", + "jest-util": "^27.3.0", + "pretty-format": "^27.3.0" }, "dependencies": { "ansi-styles": { @@ -5564,9 +4994,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5606,141 +5036,85 @@ } }, "jest-environment-jsdom": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", - "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.3.0.tgz", + "integrity": "sha512-2R1w1z7ZlQkK22bo/MrMp7ItuCxXXFspn3HNdbusbtW4OfutaPNWPmAch1Shtuu7G75jEnDb2q0PXSfFD6kEHQ==", "dev": true, "requires": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/environment": "^27.3.0", + "@jest/fake-timers": "^27.3.0", + "@jest/types": "^27.2.5", "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2", - "jsdom": "^16.4.0" + "jest-mock": "^27.3.0", + "jest-util": "^27.3.0", + "jsdom": "^16.6.0" } }, "jest-environment-node": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.6.2.tgz", - "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.3.0.tgz", + "integrity": "sha512-bH2Zb73K4x2Yw8j83mmlJUUOFJLzwIpupRvlS9PXiCeIgVTPxL5syBeq5lz310DQBQkNLDTSD5+yYRhheVKvWg==", "dev": true, "requires": { - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/environment": "^27.3.0", + "@jest/fake-timers": "^27.3.0", + "@jest/types": "^27.2.5", "@types/node": "*", - "jest-mock": "^26.6.2", - "jest-util": "^26.6.2" + "jest-mock": "^27.3.0", + "jest-util": "^27.3.0" } }, "jest-get-type": { - "version": "26.3.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.0.6.tgz", + "integrity": "sha512-XTkK5exIeUbbveehcSR8w0bhH+c0yloW/Wpl+9vZrjzztCPWrxhHwkIFpZzCt71oRBsgxmuUfxEqOYoZI2macg==", "dev": true }, "jest-haste-map": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.6.2.tgz", - "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.3.0.tgz", + "integrity": "sha512-HV7BXCWhHFuQyLCnmy+VzvYQDccTdt5gpmt2abwIrWTnQiHNAklLB3Djq7Ze3OypTmWBMLgF8AHcKNmLKx8Rzw==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.2.5", "@types/graceful-fs": "^4.1.2", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", - "fsevents": "^2.1.2", + "fsevents": "^2.3.2", "graceful-fs": "^4.2.4", - "jest-regex-util": "^26.0.0", - "jest-serializer": "^26.6.2", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", - "micromatch": "^4.0.2", - "sane": "^4.0.3", + "jest-regex-util": "^27.0.6", + "jest-serializer": "^27.0.6", + "jest-util": "^27.3.0", + "jest-worker": "^27.3.0", + "micromatch": "^4.0.4", "walker": "^1.0.7" - }, - "dependencies": { - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dev": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } - } } }, "jest-jasmine2": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", - "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.3.0.tgz", + "integrity": "sha512-c12xS913sE56pBYZYIuukttDyMJTgK+T/aYKuHse/jyBHk2r78IFxrEl0BL8iiezLZw6g6bKtyww/j9XWOVxqg==", "dev": true, "requires": { "@babel/traverse": "^7.1.0", - "@jest/environment": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/environment": "^27.3.0", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.3.0", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", - "expect": "^26.6.2", + "expect": "^27.3.0", "is-generator-fn": "^2.0.0", - "jest-each": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "pretty-format": "^26.6.2", - "throat": "^5.0.0" + "jest-each": "^27.3.0", + "jest-matcher-utils": "^27.3.0", + "jest-message-util": "^27.3.0", + "jest-runtime": "^27.3.0", + "jest-snapshot": "^27.3.0", + "jest-util": "^27.3.0", + "pretty-format": "^27.3.0", + "throat": "^6.0.1" }, "dependencies": { "ansi-styles": { @@ -5753,9 +5127,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5795,25 +5169,25 @@ } }, "jest-leak-detector": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", - "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.3.0.tgz", + "integrity": "sha512-xlCDZUaVVpCOAAiW7b8sgxIzTkEmpElwmWe9wVdU01WnFCvQ0aQiq2JTNbeCgalhjxJVeZlACRHIsLjWrmtlRA==", "dev": true, "requires": { - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "jest-get-type": "^27.0.6", + "pretty-format": "^27.3.0" } }, "jest-matcher-utils": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", - "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.3.0.tgz", + "integrity": "sha512-AK2ds5J29PJcZhfJ/5J8ycbjCXTHnwc6lQeOV1a1GahU1MCpSvyHG1iIevyvp6PXPy6r0q9ywGdCObWHmkK16g==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "pretty-format": "^26.6.2" + "jest-diff": "^27.3.0", + "jest-get-type": "^27.0.6", + "pretty-format": "^27.3.0" }, "dependencies": { "ansi-styles": { @@ -5826,9 +5200,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5868,20 +5242,20 @@ } }, "jest-message-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.6.2.tgz", - "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.3.0.tgz", + "integrity": "sha512-0c79aomiyE3mlta4NCWsICydvv2W0HlM/eVx46YEO+vdDuwUvNuQn8LqOtcHC1hSd25i03RrPvscrWgHBJQpRQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/types": "^26.6.2", + "@babel/code-frame": "^7.12.13", + "@jest/types": "^27.2.5", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", - "micromatch": "^4.0.2", - "pretty-format": "^26.6.2", + "micromatch": "^4.0.4", + "pretty-format": "^27.3.0", "slash": "^3.0.0", - "stack-utils": "^2.0.2" + "stack-utils": "^2.0.3" }, "dependencies": { "ansi-styles": { @@ -5893,19 +5267,10 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -5927,37 +5292,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -5972,25 +5312,16 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, "jest-mock": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-26.6.2.tgz", - "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.3.0.tgz", + "integrity": "sha512-ziZiLk0elZOQjD08bLkegBzv5hCABu/c8Ytx45nJKkysQwGaonvmTxwjLqEA4qGdasq9o2I8/HtdGMNnVsMTGw==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.2.5", "@types/node": "*" } }, @@ -6001,24 +5332,26 @@ "dev": true }, "jest-regex-util": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz", - "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz", + "integrity": "sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ==", "dev": true }, "jest-resolve": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.6.2.tgz", - "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.3.0.tgz", + "integrity": "sha512-SZxjtEkM0+f5vxJVpaGztQfnzEqgVnQqHzeGW1P9UON9qDtAET01HWaPCnb10SNUaNRG9NhhOMP418zl44FaIA==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.2.5", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", + "jest-haste-map": "^27.3.0", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^26.6.2", - "read-pkg-up": "^7.0.1", - "resolve": "^1.18.1", + "jest-util": "^27.3.0", + "jest-validate": "^27.3.0", + "resolve": "^1.20.0", + "resolve.exports": "^1.1.0", "slash": "^3.0.0" }, "dependencies": { @@ -6032,9 +5365,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -6056,104 +5389,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parse-json": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", - "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "dependencies": { - "type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true - } - } - }, - "read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - } - }, "slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -6172,42 +5413,44 @@ } }, "jest-resolve-dependencies": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", - "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.3.0.tgz", + "integrity": "sha512-YVmlWHdSUCOLrJl8lOIjda6+DtbgOCfExfoSx9gvHFYaXPq0UP2EELiX514H0rURTbSaLsDTodLNyqqEd/IqeA==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-snapshot": "^26.6.2" + "@jest/types": "^27.2.5", + "jest-regex-util": "^27.0.6", + "jest-snapshot": "^27.3.0" } }, "jest-runner": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-26.6.3.tgz", - "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.3.0.tgz", + "integrity": "sha512-gbkXXJdV5YpGjHvHZAAl5905qAgi+HLYO9lvLqGBxAWpx+oPOpBcMZfkRef7u86heZj1lmULzEdLjY459Z+rNQ==", "dev": true, "requires": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/console": "^27.3.0", + "@jest/environment": "^27.3.0", + "@jest/test-result": "^27.3.0", + "@jest/transform": "^27.3.0", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", - "emittery": "^0.7.1", + "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-docblock": "^26.0.0", - "jest-haste-map": "^26.6.2", - "jest-leak-detector": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", - "jest-runtime": "^26.6.3", - "jest-util": "^26.6.2", - "jest-worker": "^26.6.2", + "jest-docblock": "^27.0.6", + "jest-environment-jsdom": "^27.3.0", + "jest-environment-node": "^27.3.0", + "jest-haste-map": "^27.3.0", + "jest-leak-detector": "^27.3.0", + "jest-message-util": "^27.3.0", + "jest-resolve": "^27.3.0", + "jest-runtime": "^27.3.0", + "jest-util": "^27.3.0", + "jest-worker": "^27.3.0", "source-map-support": "^0.5.6", - "throat": "^5.0.0" + "throat": "^6.0.1" }, "dependencies": { "ansi-styles": { @@ -6220,9 +5463,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -6262,38 +5505,37 @@ } }, "jest-runtime": { - "version": "26.6.3", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.6.3.tgz", - "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", - "dev": true, - "requires": { - "@jest/console": "^26.6.2", - "@jest/environment": "^26.6.2", - "@jest/fake-timers": "^26.6.2", - "@jest/globals": "^26.6.2", - "@jest/source-map": "^26.6.2", - "@jest/test-result": "^26.6.2", - "@jest/transform": "^26.6.2", - "@jest/types": "^26.6.2", - "@types/yargs": "^15.0.0", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.3.0.tgz", + "integrity": "sha512-CRhIM45UlYVY2u5IfCx+0jsCm6DLvY9fz34CzDi3c4W1prb7hGKLOJlxbayQIHHMhUx22WhK4eRqXjOKDnKdAQ==", + "dev": true, + "requires": { + "@jest/console": "^27.3.0", + "@jest/environment": "^27.3.0", + "@jest/globals": "^27.3.0", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.3.0", + "@jest/transform": "^27.3.0", + "@jest/types": "^27.2.5", + "@types/yargs": "^16.0.0", "chalk": "^4.0.0", - "cjs-module-lexer": "^0.6.0", + "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", + "execa": "^5.0.0", "exit": "^0.1.2", "glob": "^7.1.3", "graceful-fs": "^4.2.4", - "jest-config": "^26.6.3", - "jest-haste-map": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-mock": "^26.6.2", - "jest-regex-util": "^26.0.0", - "jest-resolve": "^26.6.2", - "jest-snapshot": "^26.6.2", - "jest-util": "^26.6.2", - "jest-validate": "^26.6.2", + "jest-haste-map": "^27.3.0", + "jest-message-util": "^27.3.0", + "jest-mock": "^27.3.0", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.0", + "jest-snapshot": "^27.3.0", + "jest-util": "^27.3.0", + "jest-validate": "^27.3.0", "slash": "^3.0.0", "strip-bom": "^4.0.0", - "yargs": "^15.4.1" + "yargs": "^16.2.0" }, "dependencies": { "ansi-styles": { @@ -6306,9 +5548,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -6360,9 +5602,9 @@ } }, "jest-serializer": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.6.2.tgz", - "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz", + "integrity": "sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA==", "dev": true, "requires": { "@types/node": "*", @@ -6370,26 +5612,34 @@ } }, "jest-snapshot": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.6.2.tgz", - "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.3.0.tgz", + "integrity": "sha512-JaFXNS6D1BxvU2ORKaQwpen3Qic7IJAtGb09lbYiYk/GXXlde67Ts990i2nC5oBs0CstbeQE3jTeRayIZpM1Pw==", "dev": true, "requires": { + "@babel/core": "^7.7.2", + "@babel/generator": "^7.7.2", + "@babel/parser": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", "@babel/types": "^7.0.0", - "@jest/types": "^26.6.2", + "@jest/transform": "^27.3.0", + "@jest/types": "^27.2.5", "@types/babel__traverse": "^7.0.4", - "@types/prettier": "^2.0.0", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^26.6.2", + "expect": "^27.3.0", "graceful-fs": "^4.2.4", - "jest-diff": "^26.6.2", - "jest-get-type": "^26.3.0", - "jest-haste-map": "^26.6.2", - "jest-matcher-utils": "^26.6.2", - "jest-message-util": "^26.6.2", - "jest-resolve": "^26.6.2", + "jest-diff": "^27.3.0", + "jest-get-type": "^27.0.6", + "jest-haste-map": "^27.3.0", + "jest-matcher-utils": "^27.3.0", + "jest-message-util": "^27.3.0", + "jest-resolve": "^27.3.0", + "jest-util": "^27.3.0", "natural-compare": "^1.4.0", - "pretty-format": "^26.6.2", + "pretty-format": "^27.3.0", "semver": "^7.3.2" }, "dependencies": { @@ -6403,9 +5653,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -6454,17 +5704,17 @@ } }, "jest-util": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-26.6.2.tgz", - "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.3.0.tgz", + "integrity": "sha512-SFSDBGKkxXi4jClmU1WLp/cMMlb4YX6+5Lb0CUySxmonArio8yJ2NALMWvQuXchgySiH7Rb912hVZ2QZ6t3x7w==", "dev": true, "requires": { - "@jest/types": "^26.6.2", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", - "is-ci": "^2.0.0", - "micromatch": "^4.0.2" + "is-ci": "^3.0.0", + "picomatch": "^2.2.3" }, "dependencies": { "ansi-styles": { @@ -6476,19 +5726,10 @@ "color-convert": "^2.0.1" } }, - "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "requires": { - "fill-range": "^7.0.1" - } - }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -6510,37 +5751,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "requires": { - "to-regex-range": "^5.0.1" - } - }, "has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6549,30 +5765,21 @@ "requires": { "has-flag": "^4.0.0" } - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "requires": { - "is-number": "^7.0.0" - } } } }, "jest-validate": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-26.6.2.tgz", - "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.3.0.tgz", + "integrity": "sha512-5oqWnb9MrkicE+ywR+BxoZr0L7H3WBDAt6LZggnyFHieAk8nnIQAKRpSodNPhiNJTwaMSbNjCe7SxAzKwTsBoA==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "camelcase": "^6.0.0", + "@jest/types": "^27.2.5", + "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^26.3.0", + "jest-get-type": "^27.0.6", "leven": "^3.1.0", - "pretty-format": "^26.6.2" + "pretty-format": "^27.3.0" }, "dependencies": { "ansi-styles": { @@ -6591,9 +5798,9 @@ "dev": true }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -6633,17 +5840,17 @@ } }, "jest-watcher": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.6.2.tgz", - "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.3.0.tgz", + "integrity": "sha512-xpTFRhqzUnNwTGaSBoHcyXROGbAfj2u4LS7Xosb+hzgrFgWgiHtCy3PWyN1DQk31Na98bBjXKxAbfSBACrvEiQ==", "dev": true, "requires": { - "@jest/test-result": "^26.6.2", - "@jest/types": "^26.6.2", + "@jest/test-result": "^27.3.0", + "@jest/types": "^27.2.5", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^26.6.2", + "jest-util": "^27.3.0", "string-length": "^4.0.1" }, "dependencies": { @@ -6657,9 +5864,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { "ansi-styles": "^4.1.0", @@ -6699,14 +5906,14 @@ } }, "jest-worker": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.3.0.tgz", + "integrity": "sha512-xTTvvJqOjKBqE1AmwDHiQN8qzp9VoT981LtfXA+XiJVxHn4435vpnrzVcJ6v/ESiuB+IXPjZakn/ppT00xBCWA==", "dev": true, "requires": { "@types/node": "*", "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" + "supports-color": "^8.0.0" }, "dependencies": { "has-flag": { @@ -6716,9 +5923,9 @@ "dev": true }, "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { "has-flag": "^4.0.0" @@ -6733,29 +5940,30 @@ "dev": true }, "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "argparse": "^2.0.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + } } }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, "jsdom": { - "version": "16.5.3", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.5.3.tgz", - "integrity": "sha512-Qj1H+PEvUsOtdPJ056ewXM4UJPCi4hhLA8wpiz9F2YvsRBhuFsXxtrIFAgGBDynQA9isAMGE91PfUYbdMPXuTA==", + "version": "16.7.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", + "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", "dev": true, "requires": { "abab": "^2.0.5", - "acorn": "^8.1.0", + "acorn": "^8.2.4", "acorn-globals": "^6.0.0", "cssom": "^0.4.4", "cssstyle": "^2.3.0", @@ -6763,12 +5971,13 @@ "decimal.js": "^10.2.1", "domexception": "^2.0.1", "escodegen": "^2.0.0", + "form-data": "^3.0.0", "html-encoding-sniffer": "^2.0.1", - "is-potential-custom-element-name": "^1.0.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-potential-custom-element-name": "^1.0.1", "nwsapi": "^2.2.0", "parse5": "6.0.1", - "request": "^2.88.2", - "request-promise-native": "^1.0.9", "saxes": "^5.0.1", "symbol-tree": "^3.2.4", "tough-cookie": "^4.0.0", @@ -6778,15 +5987,35 @@ "whatwg-encoding": "^1.0.5", "whatwg-mimetype": "^2.3.0", "whatwg-url": "^8.5.0", - "ws": "^7.4.4", + "ws": "^7.4.6", "xml-name-validator": "^3.0.0" }, "dependencies": { - "acorn": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.1.1.tgz", - "integrity": "sha512-xYiIVjNuqtKXMxlRMDc6mZUhXehod4a3gbZ1qRlM7icK4EbxUFNLhWoPblCvFtB2Y9CIqHP3CF/rdxLItaQv8g==", + "tr46": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", + "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", + "dev": true, + "requires": { + "punycode": "^2.1.1" + } + }, + "webidl-conversions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", "dev": true + }, + "whatwg-url": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", + "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", + "dev": true, + "requires": { + "lodash": "^4.7.0", + "tr46": "^2.1.0", + "webidl-conversions": "^6.1.0" + } } } }, @@ -6796,18 +6025,6 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -6820,12 +6037,6 @@ "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, "json5": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", @@ -6835,18 +6046,6 @@ "minimist": "^1.2.0" } }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, "jsx-ast-utils": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.0.tgz", @@ -6857,12 +6056,6 @@ "object.assign": "^4.1.2" } }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, "kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -6900,32 +6093,6 @@ "type-check": "~0.4.0" } }, - "lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - }, "locate-path": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", @@ -6942,22 +6109,16 @@ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "lodash.flatten": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", - "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, "loose-envify": { @@ -6976,14 +6137,6 @@ "dev": true, "requires": { "yallist": "^4.0.0" - }, - "dependencies": { - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - } } }, "make-dir": { @@ -7005,21 +6158,6 @@ "tmpl": "1.0.x" } }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, "merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", @@ -7033,39 +6171,28 @@ "dev": true }, "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" } }, "mime-db": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.47.0.tgz", - "integrity": "sha512-QBmA/G2y+IfeS4oktet3qRZ+P5kPhCKRXxXnQEudYqUaEioAU1/Lq2us3D/t1Jfo4hE9REQPrbB7K5sOczJVIw==", + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz", + "integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==", "dev": true }, "mime-types": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.30.tgz", - "integrity": "sha512-crmjA4bLtR8m9qLpHvgxSChT+XoSlZi8J4n/aIdn3z92e/U47Z0V/yl+Wh9W046GgFVAmoNR/fmdbZYcSSIUeg==", + "version": "2.1.33", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz", + "integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==", "dev": true, "requires": { - "mime-db": "1.47.0" + "mime-db": "1.50.0" } }, "mimic-fn": { @@ -7096,125 +6223,57 @@ "dev": true }, "minipass": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz", - "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.5.tgz", + "integrity": "sha512-+8NzxD82XQoNKNrl1d/FSi+X8wAEWR+sbYAfIvub4Nz0d22plFG72CEVVaufV8PNf4qSslFTD8VMOxNVhHCjTw==", "dev": true, "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" + "yallist": "^4.0.0" } }, "minizlib": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz", - "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==", - "dev": true, - "requires": { - "minipass": "^2.9.0" - } - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", "dev": true, "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } + "minipass": "^3.0.0", + "yallist": "^4.0.0" } }, "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "nan": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", - "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", "dev": true }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "needle": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/needle/-/needle-2.6.0.tgz", - "integrity": "sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg==", + "node-fetch": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz", + "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==", "dev": true, "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - } + "whatwg-url": "^5.0.0" } }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, "node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -7227,77 +6286,19 @@ "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", "dev": true }, - "node-notifier": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-8.0.2.tgz", - "integrity": "sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==", - "dev": true, - "optional": true, - "requires": { - "growly": "^1.3.0", - "is-wsl": "^2.2.0", - "semver": "^7.3.2", - "shellwords": "^0.1.1", - "uuid": "^8.3.0", - "which": "^2.0.2" - }, - "dependencies": { - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "optional": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "node-pre-gyp": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.15.0.tgz", - "integrity": "sha512-7QcZa8/fpaU/BKenjcaeFF9hLz2+7S9AqyXFhlH/rilsQ/hPZKK32RtR5EQHJElgu+q5RfbJ34KriI79UWaorA==", - "dev": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.3", - "needle": "^2.5.0", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4.4.2" - } - }, "node-releases": { - "version": "1.1.71", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", - "integrity": "sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.0.tgz", + "integrity": "sha512-aA87l0flFYMzCHpTM3DERFSYxc6lv/BltdbRTOMZuxZ0cwZCD3mejE5n9vLhSJCN++/eOqr77G1IO5uXxlQYWA==", "dev": true }, "nopt": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", - "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", - "dev": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", "dev": true, "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "abbrev": "1" } }, "normalize-path": { @@ -7306,47 +6307,13 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, - "npm-bundled": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz", - "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==", - "dev": true, - "requires": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "dev": true - }, - "npm-packlist": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz", - "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==", - "dev": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "requires": { - "path-key": "^2.0.0" - }, - "dependencies": { - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - } + "path-key": "^3.0.0" } }, "npmlog": { @@ -7373,49 +6340,12 @@ "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", "dev": true }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "object-inspect": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.2.tgz", @@ -7428,15 +6358,6 @@ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, "object.assign": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", @@ -7462,36 +6383,218 @@ } }, "object.fromentries": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.4.tgz", - "integrity": "sha512-EsFBshs5RUUpQEY1D4q/m59kMfz4YJvxuNCJcv/jWwOJr34EaVnG11ZrZa0UHB3wnzV1wx8m58T4hQL8IuNXlQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has": "^1.0.3" + "es-abstract": "^1.19.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "dev": true + } } }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "object.hasown": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz", + "integrity": "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg==", "dev": true, "requires": { - "isobject": "^3.0.1" + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "dev": true + } } }, "object.values": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.3.tgz", - "integrity": "sha512-nkF6PfDB9alkOUxpf1HNm/QlkeW3SReqL5WXeBLpEJJnlPSvRaDQpW3gQTksTN3fgJX4hL42RzKyOin6ff3tyw==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has": "^1.0.3" + "es-abstract": "^1.19.1" + }, + "dependencies": { + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "dev": true + } } }, "once": { @@ -7523,43 +6626,9 @@ "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "dev": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" + "word-wrap": "^1.2.3" } }, - "p-each-series": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-2.2.0.tgz", - "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", - "dev": true - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, "p-limit": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", @@ -7593,34 +6662,12 @@ "callsites": "^3.0.0" } }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "^1.2.0" - } - }, "parse5": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true, - "optional": true - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -7640,38 +6687,27 @@ "dev": true }, "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "^2.0.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, "picomatch": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.3.tgz", - "integrity": "sha512-KpELjfwcCDUb9PeigTs2mBJzXUPzAuP2oPcA989He8Rte0+YUAjw1JVedDhuTKPkHjSYzMN3npC9luThGYEKdg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", "dev": true }, "pify": { @@ -7698,12 +6734,6 @@ "find-up": "^2.1.0" } }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, "prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -7711,39 +6741,21 @@ "dev": true }, "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.0.tgz", + "integrity": "sha512-Nkdd0xmxZdjCe6GoJomHnrLcCYGYzZKI/fRnUX0sCwDai2mmCHJfC9Ecx33lYgaxAFS/pJCAqhfxmWlm1wNVag==", "dev": true, "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", + "@jest/types": "^27.2.5", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", "react-is": "^17.0.1" }, "dependencies": { "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true } } @@ -7761,9 +6773,9 @@ "dev": true }, "prompts": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.1.tgz", - "integrity": "sha512-EQyfIuO2hPDsX1L/blblV+H7I0knhgAd82cVneCwcdND9B8AuCDuRcBH6yIcG4dFzlOUqbazQqwGjx5xmsNLuQ==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, "requires": { "kleur": "^3.0.3", @@ -7795,73 +6807,24 @@ "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", "dev": true }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true - }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, "react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", "dev": true }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "^2.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "^2.0.0", - "read-pkg": "^2.0.0" - } - }, "readable-stream": { "version": "2.3.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", @@ -7878,15 +6841,13 @@ } }, "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "optional": true, "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "picomatch": "^2.2.1" } }, "regenerate": { @@ -7896,12 +6857,12 @@ "dev": true }, "regenerate-unicode-properties": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", - "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz", + "integrity": "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA==", "dev": true, "requires": { - "regenerate": "^1.4.0" + "regenerate": "^1.4.2" } }, "regenerator-runtime": { @@ -7919,16 +6880,6 @@ "@babel/runtime": "^7.8.4" } }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - } - }, "regexp.prototype.flags": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz", @@ -7940,23 +6891,23 @@ } }, "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true }, "regexpu-core": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", - "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", + "integrity": "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg==", "dev": true, "requires": { - "regenerate": "^1.4.0", - "regenerate-unicode-properties": "^8.2.0", - "regjsgen": "^0.5.1", - "regjsparser": "^0.6.4", - "unicode-match-property-ecmascript": "^1.0.4", - "unicode-match-property-value-ecmascript": "^1.2.0" + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^9.0.0", + "regjsgen": "^0.5.2", + "regjsparser": "^0.7.0", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" } }, "regjsgen": { @@ -7966,9 +6917,9 @@ "dev": true }, "regjsparser": { - "version": "0.6.9", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.9.tgz", - "integrity": "sha512-ZqbNRz1SNjLAiYuwY0zoXW8Ne675IX5q+YHioAGbCw4X96Mjl2+dcX9B2ciaeyYjViDAfvIjFpQjJgLttTEERQ==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz", + "integrity": "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ==", "dev": true, "requires": { "jsesc": "~0.5.0" @@ -7982,120 +6933,12 @@ } } }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - } - } - }, - "request-promise-core": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.4.tgz", - "integrity": "sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==", - "dev": true, - "requires": { - "lodash": "^4.17.19" - } - }, - "request-promise-native": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.9.tgz", - "integrity": "sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==", - "dev": true, - "requires": { - "request-promise-core": "1.1.4", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - }, - "dependencies": { - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - } - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, - "require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, "resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", @@ -8129,16 +6972,10 @@ "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "resolve.exports": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz", + "integrity": "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ==", "dev": true }, "reusify": { @@ -8148,20 +6985,14 @@ "dev": true }, "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" } }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true - }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -8177,44 +7008,12 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "dev": true, - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, "saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", @@ -8236,29 +7035,6 @@ "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", "dev": true }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -8274,13 +7050,6 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true, - "optional": true - }, "side-channel": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", @@ -8293,9 +7062,9 @@ } }, "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", + "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", "dev": true }, "simple-concat": { @@ -8327,179 +7096,16 @@ "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - } - } - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "source-map": { "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true }, "source-map-support": { - "version": "0.5.19", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", - "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", + "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -8514,80 +7120,16 @@ } } }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true - }, - "spdx-correct": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", - "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", - "dev": true - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", "dev": true }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, "stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", + "integrity": "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA==", "dev": true, "requires": { "escape-string-regexp": "^2.0.0" @@ -8601,33 +7143,6 @@ } } }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true - }, "string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -8639,12 +7154,12 @@ }, "dependencies": { "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } } } @@ -8661,18 +7176,80 @@ } }, "string.prototype.matchall": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.4.tgz", - "integrity": "sha512-pknFIWVachNcyqRfaQSeu/FUfpvJTe4uskUSZ9Wc1RijsPuzbZ8TyYT8WCNnntCjUEqQ3vUHMAfVj2+wLAisPQ==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", + "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.18.0-next.2", - "has-symbols": "^1.0.1", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.2", "internal-slot": "^1.0.3", "regexp.prototype.flags": "^1.3.1", "side-channel": "^1.0.4" + }, + "dependencies": { + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "object-inspect": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", + "dev": true + } } }, "string.prototype.trimend": { @@ -8727,12 +7304,6 @@ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, "strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -8740,9 +7311,9 @@ "dev": true }, "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true }, "supports-color": { @@ -8787,82 +7358,18 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "table": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/table/-/table-6.3.0.tgz", - "integrity": "sha512-gM9kB7aNIuSagW89Fh+SdL49uhKnVSORxMcV72u/dfptFdqExInNn5M21wgq/Uf5UdJpsboFhNe/0SoNKjaxzg==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "lodash.clonedeep": "^4.5.0", - "lodash.flatten": "^4.4.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0" - }, - "dependencies": { - "ajv": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.1.0.tgz", - "integrity": "sha512-B/Sk2Ix7A36fs/ZkuGLIR86EdjbgR6fsAcbx9lOP/QBSXujDNbVmIS/U4Itz5k8fPFDeVZl/zQ/gJW4Jrq6XjQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - } - } - }, "tar": { - "version": "4.4.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz", - "integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==", + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", "dev": true, "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" } }, "terminal-link": { @@ -8893,15 +7400,15 @@ "dev": true }, "throat": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", - "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz", + "integrity": "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w==", "dev": true }, "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, "to-fast-properties": { @@ -8910,46 +7417,13 @@ "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "^7.0.0" } }, "tough-cookie": { @@ -8964,18 +7438,15 @@ } }, "tr46": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz", - "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", - "dev": true, - "requires": { - "punycode": "^2.1.1" - } + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=", + "dev": true }, "tsconfig-paths": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz", - "integrity": "sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw==", + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.11.0.tgz", + "integrity": "sha512-7ecdYDnIdmv639mmDwslG6KQg1Z9STTz1j7Gcz0xa+nshh/gKDAHcPxRbWOsA3SPp0tXP2leTcY9Kw+NAkfZzA==", "dev": true, "requires": { "@types/json5": "^0.0.29", @@ -8999,21 +7470,6 @@ "tslib": "^1.8.1" } }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -9030,9 +7486,9 @@ "dev": true }, "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, "typedarray-to-buffer": { @@ -9057,98 +7513,39 @@ } }, "unicode-canonical-property-names-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", - "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true }, "unicode-match-property-ecmascript": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", - "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", "dev": true, "requires": { - "unicode-canonical-property-names-ecmascript": "^1.0.4", - "unicode-property-aliases-ecmascript": "^1.0.4" + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" } }, "unicode-match-property-value-ecmascript": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", - "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", "dev": true }, "unicode-property-aliases-ecmascript": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", - "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", + "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", "dev": true }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true, - "optional": true - }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -9158,31 +7555,12 @@ "punycode": "^2.1.0" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "optional": true - }, "v8-compile-cache": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", @@ -9190,9 +7568,9 @@ "dev": true }, "v8-to-istanbul": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.1.tgz", - "integrity": "sha512-p0BB09E5FRjx0ELN6RgusIPsSPhtgexSRcKETybEs6IGOTXJSZqfwxp7r//55nnu0f1AxltY5VvdVqy2vZf9AA==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz", + "integrity": "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.1", @@ -9208,27 +7586,6 @@ } } }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -9257,9 +7614,9 @@ } }, "webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=", "dev": true }, "whatwg-encoding": { @@ -9278,14 +7635,13 @@ "dev": true }, "whatwg-url": { - "version": "8.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.5.0.tgz", - "integrity": "sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", "dev": true, "requires": { - "lodash": "^4.7.0", - "tr46": "^2.0.2", - "webidl-conversions": "^6.1.0" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, "which": { @@ -9310,19 +7666,13 @@ "is-symbol": "^1.0.3" } }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "dev": true, "requires": { - "string-width": "^1.0.2 || 2" + "string-width": "^1.0.2 || 2 || 3 || 4" } }, "word-wrap": { @@ -9332,9 +7682,9 @@ "dev": true }, "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "requires": { "ansi-styles": "^4.0.0", @@ -9373,23 +7723,23 @@ "dev": true }, "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } } } @@ -9413,9 +7763,9 @@ } }, "ws": { - "version": "7.4.5", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.5.tgz", - "integrity": "sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", + "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", "dev": true }, "xml-name-validator": { @@ -9431,122 +7781,65 @@ "dev": true }, "y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, "yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" }, "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "strip-ansi": "^6.0.1" } }, "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^5.0.0" + "ansi-regex": "^5.0.1" } } } }, "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true } } } diff --git a/package.json b/package.json index f77d87ff50..305c750591 100644 --- a/package.json +++ b/package.json @@ -35,18 +35,18 @@ }, "homepage": "https://github.com/trekhleb/javascript-algorithms#readme", "devDependencies": { - "@babel/cli": "7.12.10", - "@babel/preset-env": "7.12.11", - "@types/jest": "26.0.19", - "canvas": "^2.7.0", - "eslint": "7.16.0", + "@babel/cli": "7.15.7", + "@babel/preset-env": "7.15.8", + "@types/jest": "27.0.2", + "canvas": "2.8.0", + "eslint": "8.0.1", "eslint-config-airbnb": "18.2.1", - "eslint-plugin-import": "2.22.1", - "eslint-plugin-jest": "24.1.3", + "eslint-plugin-import": "2.25.2", + "eslint-plugin-jest": "25.2.2", "eslint-plugin-jsx-a11y": "6.4.1", - "eslint-plugin-react": "7.21.5", - "husky": "6.0.0", - "jest": "26.6.3" + "eslint-plugin-react": "7.26.1", + "husky": "7.0.2", + "jest": "27.3.0" }, "engines": { "node": ">=12.0.0", From 99945f30deba9fb0ec5077e07ed093d0a531f1c1 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Fri, 22 Oct 2021 09:56:44 +0200 Subject: [PATCH 103/264] Add the "Weighted Random" algorithm (#792) * Add the link to the Weighted Random algorithm to the main README. * Add Weighted Random implementation and tests. * Add Weighted Random README. * Add Weighted Random README. * Add Weighted Random README. --- README.md | 2 + .../statistics/weighted-random/README.md | 141 ++++++++++++++++++ .../__test__/weightedRandom.test.js | 64 ++++++++ .../weighted-random/weightedRandom.js | 52 +++++++ 4 files changed, 259 insertions(+) create mode 100644 src/algorithms/statistics/weighted-random/README.md create mode 100644 src/algorithms/statistics/weighted-random/__test__/weightedRandom.test.js create mode 100644 src/algorithms/statistics/weighted-random/weightedRandom.js diff --git a/README.md b/README.md index d00945e5a5..826a3a45b8 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,8 @@ a set of rules that precisely define a sequence of operations. * `B` [k-Means](src/algorithms/ml/k-means) - k-Means clustering algorithm * **Image Processing** * `B` [Seam Carving](src/algorithms/image-processing/seam-carving) - content-aware image resizing algorithm +* **Statistics** + * `B` [Weighted Random](src/algorithms/statistics/weighted-random) - select the random item from the list based on items' weights * **Uncategorized** * `B` [Tower of Hanoi](src/algorithms/uncategorized/hanoi-tower) * `B` [Square Matrix Rotation](src/algorithms/uncategorized/square-matrix-rotation) - in-place algorithm diff --git a/src/algorithms/statistics/weighted-random/README.md b/src/algorithms/statistics/weighted-random/README.md new file mode 100644 index 0000000000..1c700d41d6 --- /dev/null +++ b/src/algorithms/statistics/weighted-random/README.md @@ -0,0 +1,141 @@ +# Weighted Random + +## What is "Weighted Random" + +Let's say you have a list of **items**. Item could be anything. For example, we may have a list of fruits and vegetables that you like to eat: `[ '🍌', '🍎', '🥕' ]`. + +The list of **weights** represent the weight (or probability, or importance) of each item. Weights are numbers. For example, the weights like `[3, 7, 1]` would say that: + +- you would like to eat `🍎 apples` more often (`7` out of `3 + 7 + 1 = 11` times), +- then you would like to eat `bananas 🍌` less often (only `3` out of `11` times), +- and the `carrots 🥕` you really don't like (want to eat it only `1` out of `11` times). + +> If we speak in terms of probabilities than the weights list might be an array of floats that sum up to `1` (i.e. `[0.1, 0.5, 0.2, 0.2]`). + +The **Weighted Random** in this case will be the function that will randomly return you the item from the list, and it will take each item's weight into account, so that items with the higher weight will be picked more often. + +Example of the function interface: + +```javascript +const items = [ '🍌', '🍎', '🥕' ]; +const weights = [ 3, 7, 1 ]; + +function weightedRandom(items, weights) { + // implementation goes here ... +} + +const nextSnackToEat = weightedRandom(items, weights); // Could be '🍎' +``` + +## Applications of Weighted Random + +- In [Genetic Algorithm](https://en.wikipedia.org/wiki/Genetic_algorithm) the weighted random is used during the "Selection" phase, when we need to select the fittest/strongest individuums based on their fitness score for mating and for producing the next stronger generation. You may find an **example** in the [Self-Parking Car in 500 Lines of Code](https://trekhleb.dev/blog/2021/self-parking-car-evolution/) article. +- In [Recurrent Neural Networks (RNN)](https://en.wikipedia.org/wiki/Recurrent_neural_network) when trying to decide what letter to choose next (to form the sentence) based on the next letter probability. You may find an **example** in the [Recipe Generation using Recurrent Neural Network (RNN)](https://nbviewer.org/github/trekhleb/machine-learning-experiments/blob/master/experiments/recipe_generation_rnn/recipe_generation_rnn.ipynb) Jupyter notebook. +- In [Nginx Load Balancing](https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/) to send HTTP requests more often to the servers with the higher weights. +- And more... + +## The Algorithm + +The **straightforward approach** would be to: + +1. Repeat each item in the list according to its weight. +2. Pick the random item from the list. + +For example in our case with fruits and vegetables we could generate the following list of size `3 + 7 + 1 = 11`: + +```javascript +const items = [ '🍌', '🍎', '🥕' ]; +const weights = [ 3, 7, 1 ]; + +// Repeating the items based on weights. +const weightedItems = [ + '🍌', '🍌', '🍌', + '🍎', '🍎', '🍎', '🍎', '🍎', '🍎', '🍎', + '🥕', +]; + +// And now just pick the random item from weightedItems array. +``` + +However, as you may see, this approach may require a lot of memory, in case if the objects are heavy, and in case if we have a lot of them to repeat in `weightedItems` list. + +The **more efficient approach** would be to: + +1. Prepare the list of cumulative weights for each item (i.e. the `cumulativeWeights` list which will have the same number of elements as the original `weights` list). In our case it will look like this: `cumulativeWeights = [3, 3 + 7, 3 + 7 + 1] = [3, 10, 11]` +2. Generate the random number `randomNumber` from `0` to the highest cumulative weight value. In our case the random number will be in a range of `[0..11]`. Let's say that we have `randomNumber = 8`. +3. Go through the `cumulativeWeights` list from left to right and pick the first element which is higher or equal to the `randomNumber`. The index of such element we will use to pick the item from the `items` array. + +The idea behind this approach is that the higher weights will "occupy" more numeric space. Therefore, there is a higher chance that the random number will fall into the "higher weight numeric bucket". + +```javascript +const weights = [3, 7, 1 ]; +const cumulativeWeights = [3, 10, 11]; + +// In a pseudo-representation we may think about the cumulativeWeights array like this. +const pseudoCumulativeWeights = [ + 1, 2, 3, // <-- [3] numbers + 4, 5, 6, 7, 8, 9, 10, // <-- [7] numbers + 11, // <-- [1] number +]; +``` + +Here is an example of how the `weightedRandom` function might be implemented: + +```javascript +/** + * Picks the random item based on its weight. + * The items with higher weight will be picked more often (with a higher probability). + * + * For example: + * - items = ['banana', 'orange', 'apple'] + * - weights = [0, 0.2, 0.8] + * - weightedRandom(items, weights) in 80% of cases will return 'apple', in 20% of cases will return + * 'orange' and it will never return 'banana' (because probability of picking the banana is 0%) + * + * @param {any[]} items + * @param {number[]} weights + * @returns {{item: any, index: number}} + */ +export default function weightedRandom(items, weights) { + if (items.length !== weights.length) { + throw new Error('Items and weights must be of the same size'); + } + + if (!items.length) { + throw new Error('Items must not be empty'); + } + + // Preparing the cumulative weights array. + // For example: + // - weights = [1, 4, 3] + // - cumulativeWeights = [1, 5, 8] + const cumulativeWeights = []; + for (let i = 0; i < weights.length; i += 1) { + cumulativeWeights[i] = weights[i] + (cumulativeWeights[i - 1] || 0); + } + + // Getting the random number in a range of [0...sum(weights)] + // For example: + // - weights = [1, 4, 3] + // - maxCumulativeWeight = 8 + // - range for the random number is [0...8] + const maxCumulativeWeight = cumulativeWeights[cumulativeWeights.length - 1]; + const randomNumber = maxCumulativeWeight * Math.random(); + + // Picking the random item based on its weight. + // The items with higher weight will be picked more often. + for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) { + if (cumulativeWeights[itemIndex] >= randomNumber) { + return { + item: items[itemIndex], + index: itemIndex, + }; + } + } +} +``` + +## Implementation + +- Check the [weightedRandom.js](weightedRandom.js) file for the implementation of the `weightedRandom()` function. +- Check the [weightedRandom.test.js](__test__/weightedRandom.test.js) file for the tests-cases. diff --git a/src/algorithms/statistics/weighted-random/__test__/weightedRandom.test.js b/src/algorithms/statistics/weighted-random/__test__/weightedRandom.test.js new file mode 100644 index 0000000000..1b0b267627 --- /dev/null +++ b/src/algorithms/statistics/weighted-random/__test__/weightedRandom.test.js @@ -0,0 +1,64 @@ +import weightedRandom from '../weightedRandom'; + +describe('weightedRandom', () => { + it('should throw an error when the number of weights does not match the number of items', () => { + const getWeightedRandomWithInvalidInputs = () => { + weightedRandom(['a', 'b', 'c'], [10, 0]); + }; + expect(getWeightedRandomWithInvalidInputs).toThrow('Items and weights must be of the same size'); + }); + + it('should throw an error when the number of weights or items are empty', () => { + const getWeightedRandomWithInvalidInputs = () => { + weightedRandom([], []); + }; + expect(getWeightedRandomWithInvalidInputs).toThrow('Items must not be empty'); + }); + + it('should correctly do random selection based on wights in straightforward cases', () => { + expect(weightedRandom(['a', 'b', 'c'], [1, 0, 0])).toEqual({ index: 0, item: 'a' }); + expect(weightedRandom(['a', 'b', 'c'], [0, 1, 0])).toEqual({ index: 1, item: 'b' }); + expect(weightedRandom(['a', 'b', 'c'], [0, 0, 1])).toEqual({ index: 2, item: 'c' }); + expect(weightedRandom(['a', 'b', 'c'], [0, 1, 1])).not.toEqual({ index: 0, item: 'a' }); + expect(weightedRandom(['a', 'b', 'c'], [1, 0, 1])).not.toEqual({ index: 1, item: 'b' }); + expect(weightedRandom(['a', 'b', 'c'], [1, 1, 0])).not.toEqual({ index: 2, item: 'c' }); + }); + + it('should correctly do random selection based on wights', () => { + // Number of times we're going to select the random items based on their weights. + const ATTEMPTS_NUM = 1000; + // The +/- delta in the number of times each item has been actually selected. + // I.e. if we want the item 'a' to be selected 300 times out of 1000 cases (30%) + // then 267 times is acceptable since it is bigger that 250 (which is 300 - 50) + // ans smaller than 350 (which is 300 + 50) + const THRESHOLD = 50; + + const items = ['a', 'b', 'c']; // The actual items values don't matter. + const weights = [0.1, 0.3, 0.6]; + + const counter = []; + for (let i = 0; i < ATTEMPTS_NUM; i += 1) { + const randomItem = weightedRandom(items, weights); + if (!counter[randomItem.index]) { + counter[randomItem.index] = 1; + } else { + counter[randomItem.index] += 1; + } + } + + for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) { + /* + i.e. item with the index of 0 must be selected 100 times (ideally) + or with the threshold of [100 - 50, 100 + 50] times. + + i.e. item with the index of 1 must be selected 300 times (ideally) + or with the threshold of [300 - 50, 300 + 50] times. + + i.e. item with the index of 2 must be selected 600 times (ideally) + or with the threshold of [600 - 50, 600 + 50] times. + */ + expect(counter[itemIndex]).toBeGreaterThan(ATTEMPTS_NUM * weights[itemIndex] - THRESHOLD); + expect(counter[itemIndex]).toBeLessThan(ATTEMPTS_NUM * weights[itemIndex] + THRESHOLD); + } + }); +}); diff --git a/src/algorithms/statistics/weighted-random/weightedRandom.js b/src/algorithms/statistics/weighted-random/weightedRandom.js new file mode 100644 index 0000000000..0d58a504f8 --- /dev/null +++ b/src/algorithms/statistics/weighted-random/weightedRandom.js @@ -0,0 +1,52 @@ +/** + * Picks the random item based on its weight. + * The items with higher weight will be picked more often (with a higher probability). + * + * For example: + * - items = ['banana', 'orange', 'apple'] + * - weights = [0, 0.2, 0.8] + * - weightedRandom(items, weights) in 80% of cases will return 'apple', in 20% of cases will return + * 'orange' and it will never return 'banana' (because probability of picking the banana is 0%) + * + * @param {any[]} items + * @param {number[]} weights + * @returns {{item: any, index: number}} + */ +/* eslint-disable consistent-return */ +export default function weightedRandom(items, weights) { + if (items.length !== weights.length) { + throw new Error('Items and weights must be of the same size'); + } + + if (!items.length) { + throw new Error('Items must not be empty'); + } + + // Preparing the cumulative weights array. + // For example: + // - weights = [1, 4, 3] + // - cumulativeWeights = [1, 5, 8] + const cumulativeWeights = []; + for (let i = 0; i < weights.length; i += 1) { + cumulativeWeights[i] = weights[i] + (cumulativeWeights[i - 1] || 0); + } + + // Getting the random number in a range of [0...sum(weights)] + // For example: + // - weights = [1, 4, 3] + // - maxCumulativeWeight = 8 + // - range for the random number is [0...8] + const maxCumulativeWeight = cumulativeWeights[cumulativeWeights.length - 1]; + const randomNumber = maxCumulativeWeight * Math.random(); + + // Picking the random item based on its weight. + // The items with higher weight will be picked more often. + for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) { + if (cumulativeWeights[itemIndex] >= randomNumber) { + return { + item: items[itemIndex], + index: itemIndex, + }; + } + } +} From 17bfb551c0d1d38de5ff3ec4ef9c587678ce6ea9 Mon Sep 17 00:00:00 2001 From: Oleksii Trekhleb Date: Fri, 22 Oct 2021 10:16:37 +0200 Subject: [PATCH 104/264] Add Weighted Random cover. --- .../statistics/weighted-random/README.md | 2 ++ .../weighted-random/images/cover.png | Bin 0 -> 303430 bytes 2 files changed, 2 insertions(+) create mode 100644 src/algorithms/statistics/weighted-random/images/cover.png diff --git a/src/algorithms/statistics/weighted-random/README.md b/src/algorithms/statistics/weighted-random/README.md index 1c700d41d6..8b9c8890d7 100644 --- a/src/algorithms/statistics/weighted-random/README.md +++ b/src/algorithms/statistics/weighted-random/README.md @@ -1,5 +1,7 @@ # Weighted Random +![Weighted Random](images/cover.png) + ## What is "Weighted Random" Let's say you have a list of **items**. Item could be anything. For example, we may have a list of fruits and vegetables that you like to eat: `[ '🍌', '🍎', '🥕' ]`. diff --git a/src/algorithms/statistics/weighted-random/images/cover.png b/src/algorithms/statistics/weighted-random/images/cover.png new file mode 100644 index 0000000000000000000000000000000000000000..924f81a8aea5c9e21f270e2dd7cb56d1d5dfaa7e GIT binary patch literal 303430 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�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