From 22fbc62f882b989b06d5941b78276759e2323ba7 Mon Sep 17 00:00:00 2001
From: Oliver Eyton-Williams
Date: Tue, 15 Dec 2020 16:52:02 +0100
Subject: [PATCH] chore: format curriculum (#37912)
---
lerna.json | 2 +
tools/scripts/formatter/README.txt | 35 +
.../__fixtures__/amicable-pairs.md | 130 +
.../__fixtures__/amicable-pairs.md.formatted | 141 ++
.../__fixtures__/billion-names.md | 103 +
.../__fixtures__/billion-names.md.formatted | 115 +
.../__fixtures__/bootstrap-block-button.md | 179 ++
.../bootstrap-block-button.md.formatted | 193 ++
.../fcc-md-to-gfm/__fixtures__/css.md | 146 ++
.../__fixtures__/css.md.formatted | 156 ++
.../fcc-md-to-gfm/__fixtures__/dead-links.md | 71 +
.../__fixtures__/dead-links.md.formatted | 80 +
.../__fixtures__/disjoint-sublist.md | 83 +
.../disjoint-sublist.md.formatted | 95 +
.../__fixtures__/drum-machine.md | 53 +
.../__fixtures__/drum-machine.md.formatted | 72 +
.../fcc-md-to-gfm/__fixtures__/entropy.md | 91 +
.../__fixtures__/entropy.md.formatted | 99 +
.../fcc-md-to-gfm/__fixtures__/hello.md | 63 +
.../__fixtures__/hello.md.formatted | 80 +
.../fcc-md-to-gfm/__fixtures__/hofstadter.md | 136 +
.../__fixtures__/hofstadter.md.formatted | 152 ++
.../__fixtures__/link-external.md | 77 +
.../__fixtures__/link-external.md.formatted | 87 +
.../__fixtures__/link-internal.md | 101 +
.../__fixtures__/link-internal.md.formatted | 114 +
.../fcc-md-to-gfm/__fixtures__/nest-anchor.md | 100 +
.../__fixtures__/nest-anchor.md.formatted | 105 +
.../__fixtures__/spiral-matrix.md | 84 +
.../__fixtures__/spiral-matrix.md.formatted | 90 +
.../fcc-md-to-gfm/__fixtures__/word-blanks.md | 91 +
.../__fixtures__/word-blanks.md.formatted | 102 +
.../fcc-md-to-gfm/acceptance.test.js | 65 +
.../fcc-md-to-gfm/code-to-backticks.js | 88 +
.../fcc-md-to-gfm/formatCurriculum.js | 21 +
.../formatter/fcc-md-to-gfm/insert-spaces.js | 257 ++
.../fcc-md-to-gfm/insert-spaces.test.js | 313 +++
.../formatter/fcc-md-to-gfm/package-lock.json | 2087 ++++++++++++++++
.../formatter/fcc-md-to-gfm/package.json | 31 +
.../fcc-md-to-gfm/transformChallenges.js | 57 +
.../fcc-md-to-gfm/transformChallenges.test.js | 30 +
.../formatter/fcc-md-to-gfm/validate-text.js | 14 +
.../scripts/formatter/md-to-mdx/create-mdx.js | 440 ++++
.../scripts/formatter/md-to-mdx/md-to-mdx.js | 28 +
.../md-to-mdx/plugins/section-to-heading.js | 22 +
.../md-to-mdx/plugins/tests-to-data.js | 24 +
.../md-to-mdx/plugins/text-to-data.js | 30 +
.../formatter/md-to-mdx/transform-to-mdx.js | 24 +
.../md-to-mdx/utils/get-all-between.js | 19 +
.../formatter/md-to-mdx/validate-hints.js | 19 +
tools/scripts/formatter/package-lock.json | 2185 +++++++++++++++++
tools/scripts/formatter/package.json | 41 +
52 files changed, 9021 insertions(+)
create mode 100644 tools/scripts/formatter/README.txt
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/amicable-pairs.md
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/amicable-pairs.md.formatted
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/billion-names.md
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/billion-names.md.formatted
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/bootstrap-block-button.md
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/bootstrap-block-button.md.formatted
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/css.md
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/css.md.formatted
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/dead-links.md
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/dead-links.md.formatted
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/disjoint-sublist.md
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/disjoint-sublist.md.formatted
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/drum-machine.md
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/drum-machine.md.formatted
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/entropy.md
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/entropy.md.formatted
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hello.md
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hello.md.formatted
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hofstadter.md
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hofstadter.md.formatted
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-external.md
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-external.md.formatted
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-internal.md
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-internal.md.formatted
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/nest-anchor.md
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/nest-anchor.md.formatted
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/spiral-matrix.md
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/spiral-matrix.md.formatted
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/word-blanks.md
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/word-blanks.md.formatted
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/acceptance.test.js
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/code-to-backticks.js
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/formatCurriculum.js
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/insert-spaces.js
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/insert-spaces.test.js
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/package-lock.json
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/package.json
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/transformChallenges.js
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/transformChallenges.test.js
create mode 100644 tools/scripts/formatter/fcc-md-to-gfm/validate-text.js
create mode 100644 tools/scripts/formatter/md-to-mdx/create-mdx.js
create mode 100644 tools/scripts/formatter/md-to-mdx/md-to-mdx.js
create mode 100644 tools/scripts/formatter/md-to-mdx/plugins/section-to-heading.js
create mode 100644 tools/scripts/formatter/md-to-mdx/plugins/tests-to-data.js
create mode 100644 tools/scripts/formatter/md-to-mdx/plugins/text-to-data.js
create mode 100644 tools/scripts/formatter/md-to-mdx/transform-to-mdx.js
create mode 100644 tools/scripts/formatter/md-to-mdx/utils/get-all-between.js
create mode 100644 tools/scripts/formatter/md-to-mdx/validate-hints.js
create mode 100644 tools/scripts/formatter/package-lock.json
create mode 100644 tools/scripts/formatter/package.json
diff --git a/lerna.json b/lerna.json
index d99e98f322..72b3c6ee01 100644
--- a/lerna.json
+++ b/lerna.json
@@ -8,6 +8,8 @@
"tools/challenge-md-parser/mdx",
"tools/scripts/seed",
"tools/scripts/build",
+ "tools/scripts/formatter",
+ "tools/scripts/formatter/fcc-md-to-gfm",
"tools/challenge-helper-scripts"
],
"version": "independent"
diff --git a/tools/scripts/formatter/README.txt b/tools/scripts/formatter/README.txt
new file mode 100644
index 0000000000..9712f5f358
--- /dev/null
+++ b/tools/scripts/formatter/README.txt
@@ -0,0 +1,35 @@
+# How the formatter works
+
+## Validation
+
+There are two scripts that validate challenges: validate-text and
+validate-hints. validate-text ensures that any code inside tags can
+be converted to backticks. For example var x = 'y';
is fine, but
+not okay is not, since `not okay ` becomes
+<span>not okay</span> which is not the intention.
+
+In contrast <span>span we want</span> is perfectly fine.
+The script will parse this and replace it with `span we want `.
+
+Some challenges will break, so it's worth checking how they're rendered after
+transform-challenges has done its work.
+
+validate-hints operates differently. It checks to see if there is any markdown
+syntax inside the test text and flags up challenges that *may* not be being
+rendered correctly. Unfortunately there are a lot of false positives, a human
+needs to see if the challenge author intended for the text to be parsed as
+markdown or not. Also bare email addresses name@address.com should be
+highlighted by this tool and will need wrapping with backticks.
+
+## How to use
+
+mmv is great, so I recommend installing that first. Then:
+
+cd curriculum/challenges/chinese/12-certificates
+mmv ";*.md" "#1#2.markdown"
+cd ../../../../tools/scripts/formatter/fcc-md-to-gfm/
+node formatCurriculum.js
+cd ../md-to-mdx
+node md-to-mdx # this might have warnings and errors. Errors need fixing, but warnings just need checking
+cd ../../../../curriculum/challenges/chinese/
+mmv -md ";*.mdx" "#1#2.md"
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/amicable-pairs.md b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/amicable-pairs.md
new file mode 100644
index 0000000000..477bbf721f
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/amicable-pairs.md
@@ -0,0 +1,130 @@
+---
+title: Amicable pairs
+id: 5949b579404977fbaefcd737
+challengeType: 5
+forumTopicId: 302225
+---
+
+## Description
+
+Two integers $N$ and $M$ are said to be amicable pairs if $N \neq M$ and the sum of the proper divisors of $N$ ($\mathrm{sum}(\mathrm{propDivs}(N))$) $= M$ as well as $\mathrm{sum}(\mathrm{propDivs}(M)) = N$.
+Example:
+1184 and 1210 are an amicable pair, with proper divisors:
+
+ 1, 2, 4, 8, 16, 32, 37, 74, 148, 296, 592 and
+ 1, 2, 5, 10, 11, 22, 55, 110, 121, 242, 605 respectively.
+
+
+
+## Instructions
+
+Calculate and show here the Amicable pairs below 20,000 (there are eight).
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: amicablePairsUpTo
should be a function.
+ testString: assert(typeof amicablePairsUpTo === 'function');
+ - text: amicablePairsUpTo(300)
should return [[220,284]]
.
+ testString: assert.deepEqual(amicablePairsUpTo(300), answer300);
+ - text: amicablePairsUpTo(3000)
should return [[220,284],[1184,1210],[2620,2924]]
.
+ testString: assert.deepEqual(amicablePairsUpTo(3000), answer3000);
+ - text: amicablePairsUpTo(20000)
should return [[220,284],[1184,1210],[2620,2924],[5020,5564],[6232,6368],[10744,10856],[12285,14595],[17296,18416]]
.
+ testString: assert.deepEqual(amicablePairsUpTo(20000), answer20000);
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+```js
+function amicablePairsUpTo(maxNum) {
+ // Good luck!
+ return true;
+}
+```
+
+
+
+
+### After Test
+
+
+```js
+const answer300 = [[220, 284]];
+const answer3000 = [
+ [220, 284],
+ [1184, 1210],
+ [2620, 2924]
+];
+const answer20000 = [
+ [220, 284],
+ [1184, 1210],
+ [2620, 2924],
+ [5020, 5564],
+ [6232, 6368],
+ [10744, 10856],
+ [12285, 14595],
+ [17296, 18416]
+];
+```
+
+
+
+
+
+## Solution
+
+
+
+```js
+// amicablePairsUpTo :: Int -> [(Int, Int)]
+function amicablePairsUpTo(maxNum) {
+ return range(1, maxNum)
+ .map(x => properDivisors(x)
+ .reduce((a, b) => a + b, 0))
+ .reduce((a, m, i, lst) => {
+ const n = i + 1;
+
+ return (m > n) && lst[m - 1] === n ?
+ a.concat([
+ [n, m]
+ ]) : a;
+ }, []);
+}
+
+// properDivisors :: Int -> [Int]
+function properDivisors(n) {
+ if (n < 2) return [];
+
+ const rRoot = Math.sqrt(n);
+ const intRoot = Math.floor(rRoot);
+ const blnPerfectSquare = rRoot === intRoot;
+ const lows = range(1, intRoot)
+ .filter(x => (n % x) === 0);
+
+ return lows.concat(lows.slice(1)
+ .map(x => n / x)
+ .reverse()
+ .slice(blnPerfectSquare | 0));
+}
+
+// Int -> Int -> Maybe Int -> [Int]
+function range(m, n, step) {
+ const d = (step || 1) * (n >= m ? 1 : -1);
+
+ return Array.from({
+ length: Math.floor((n - m) / d) + 1
+ }, (_, i) => m + (i * d));
+}
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/amicable-pairs.md.formatted b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/amicable-pairs.md.formatted
new file mode 100644
index 0000000000..a3302bb221
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/amicable-pairs.md.formatted
@@ -0,0 +1,141 @@
+---
+title: Amicable pairs
+id: 5949b579404977fbaefcd737
+challengeType: 5
+forumTopicId: 302225
+---
+
+## Description
+
+
+
+Two integers $N$ and $M$ are said to be [amicable pairs]( "wp: Amicable numbers") if $N \\neq M$ and the sum of the [proper divisors]( "Proper divisors") of $N$ ($\\mathrm{sum}(\\mathrm{propDivs}(N))$) $= M$ as well as $\\mathrm{sum}(\\mathrm{propDivs}(M)) = N$.
+
+**Example:**
+
+**1184** and **1210** are an amicable pair, with proper divisors:
+
+
+ 1, 2, 4, 8, 16, 32, 37, 74, 148, 296, 592 and
+ 1, 2, 5, 10, 11, 22, 55, 110, 121, 242, 605 respectively.
+
+
+
+
+## Instructions
+
+
+
+Calculate and show here the Amicable pairs below 20,000 (there are eight).
+
+
+
+## Tests
+
+
+
+```yml
+tests:
+ - text: amicablePairsUpTo
should be a function.
+ testString: assert(typeof amicablePairsUpTo === 'function');
+ - text: amicablePairsUpTo(300)
should return [[220,284]]
.
+ testString: assert.deepEqual(amicablePairsUpTo(300), answer300);
+ - text: amicablePairsUpTo(3000)
should return [[220,284],[1184,1210],[2620,2924]]
.
+ testString: assert.deepEqual(amicablePairsUpTo(3000), answer3000);
+ - text: amicablePairsUpTo(20000)
should return [[220,284],[1184,1210],[2620,2924],[5020,5564],[6232,6368],[10744,10856],[12285,14595],[17296,18416]]
.
+ testString: assert.deepEqual(amicablePairsUpTo(20000), answer20000);
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+
+```js
+function amicablePairsUpTo(maxNum) {
+ // Good luck!
+ return true;
+}
+```
+
+
+
+### After Test
+
+
+
+```js
+const answer300 = [[220, 284]];
+const answer3000 = [
+ [220, 284],
+ [1184, 1210],
+ [2620, 2924]
+];
+const answer20000 = [
+ [220, 284],
+ [1184, 1210],
+ [2620, 2924],
+ [5020, 5564],
+ [6232, 6368],
+ [10744, 10856],
+ [12285, 14595],
+ [17296, 18416]
+];
+```
+
+
+
+
+
+## Solution
+
+
+
+```js
+// amicablePairsUpTo :: Int -> [(Int, Int)]
+function amicablePairsUpTo(maxNum) {
+ return range(1, maxNum)
+ .map(x => properDivisors(x)
+ .reduce((a, b) => a + b, 0))
+ .reduce((a, m, i, lst) => {
+ const n = i + 1;
+
+ return (m > n) && lst[m - 1] === n ?
+ a.concat([
+ [n, m]
+ ]) : a;
+ }, []);
+}
+
+// properDivisors :: Int -> [Int]
+function properDivisors(n) {
+ if (n < 2) return [];
+
+ const rRoot = Math.sqrt(n);
+ const intRoot = Math.floor(rRoot);
+ const blnPerfectSquare = rRoot === intRoot;
+ const lows = range(1, intRoot)
+ .filter(x => (n % x) === 0);
+
+ return lows.concat(lows.slice(1)
+ .map(x => n / x)
+ .reverse()
+ .slice(blnPerfectSquare | 0));
+}
+
+// Int -> Int -> Maybe Int -> [Int]
+function range(m, n, step) {
+ const d = (step || 1) * (n >= m ? 1 : -1);
+
+ return Array.from({
+ length: Math.floor((n - m) / d) + 1
+ }, (_, i) => m + (i * d));
+}
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/billion-names.md b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/billion-names.md
new file mode 100644
index 0000000000..1ee4b148f9
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/billion-names.md
@@ -0,0 +1,103 @@
+---
+title: 9 billion names of God the integer
+id: 5949b579404977fbaefcd736
+challengeType: 5
+forumTopicId: 302219
+---
+
+## Description
+
+This task is a variation of the short story by Arthur C. Clarke .
+(Solvers should be aware of the consequences of completing this task.)
+In detail, to specify what is meant by a "name":
+
+ The integer 1 has 1 name "1".
+ The integer 2 has 2 names "1+1" and "2".
+ The integer 3 has 3 names "1+1+1", "2+1", and "3".
+ The integer 4 has 5 names "1+1+1+1", "2+1+1", "2+2", "3+1", "4".
+ The integer 5 has 7 names "1+1+1+1+1", "2+1+1+1", "2+2+1", "3+1+1", "3+2", "4+1", "5".
+
+This can be visualized in the following form:
+
+ 1
+ 1 1
+ 1 1 1
+ 1 2 1 1
+ 1 2 2 1 1
+1 3 3 2 1 1
+
+Where row $n$ corresponds to integer $n$, and each column $C$ in row $m$ from left to right corresponds to the number of names beginning with $C$.
+Optionally note that the sum of the $n$-th row $P(n)$ is the integer partition function.
+
+
+## Instructions
+
+Implement a function that returns the sum of the $n$-th row.
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: numberOfNames
is a function.
+ testString: assert(typeof numberOfNames === 'function');
+ - text: numberOfNames(5)
should equal 7.
+ testString: assert.equal(numberOfNames(5), 7);
+ - text: numberOfNames(12)
should equal 77.
+ testString: assert.equal(numberOfNames(12), 77);
+ - text: numberOfNames(18)
should equal 385.
+ testString: assert.equal(numberOfNames(18), 385);
+ - text: numberOfNames(23)
should equal 1255.
+ testString: assert.equal(numberOfNames(23), 1255);
+ - text: numberOfNames(42)
should equal 53174.
+ testString: assert.equal(numberOfNames(42), 53174);
+ - text: numberOfNames(123)
should equal 2552338241.
+ testString: assert.equal(numberOfNames(123), 2552338241);
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+```js
+function numberOfNames(num) {
+ // Good luck!
+ return true;
+}
+```
+
+
+
+
+
+
+
+## Solution
+
+
+
+```js
+function numberOfNames(num) {
+ const cache = [
+ [1]
+ ];
+ for (let l = cache.length; l < num + 1; l++) {
+ let Aa;
+ let Mi;
+ const r = [0];
+ for (let x = 1; x < l + 1; x++) {
+ r.push(r[r.length - 1] + (Aa = cache[l - x < 0 ? cache.length - (l - x) : l - x])[(Mi = Math.min(x, l - x)) < 0 ? Aa.length - Mi : Mi]);
+ }
+ cache.push(r);
+ }
+ return cache[num][cache[num].length - 1];
+}
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/billion-names.md.formatted b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/billion-names.md.formatted
new file mode 100644
index 0000000000..3a4265367c
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/billion-names.md.formatted
@@ -0,0 +1,115 @@
+---
+title: 9 billion names of God the integer
+id: 5949b579404977fbaefcd736
+challengeType: 5
+forumTopicId: 302219
+---
+
+## Description
+
+
+
+This task is a variation of the [short story by Arthur C. Clarke]( "wp: The Nine Billion Names of God#Plot_summary").
+
+(Solvers should be aware of the consequences of completing this task.)
+
+In detail, to specify what is meant by a "name":
+
+
+ The integer 1 has 1 name "1".
+ The integer 2 has 2 names "1+1" and "2".
+ The integer 3 has 3 names "1+1+1", "2+1", and "3".
+ The integer 4 has 5 names "1+1+1+1", "2+1+1", "2+2", "3+1", "4".
+ The integer 5 has 7 names "1+1+1+1+1", "2+1+1+1", "2+2+1", "3+1+1", "3+2", "4+1", "5".
+
+
+This can be visualized in the following form:
+
+ 1
+ 1 1
+ 1 1 1
+ 1 2 1 1
+ 1 2 2 1 1
+1 3 3 2 1 1
+
+
+Where row $n$ corresponds to integer $n$, and each column $C$ in row $m$ from left to right corresponds to the number of names beginning with $C$.
+
+Optionally note that the sum of the $n$-th row $P(n)$ is the integer partition function.
+
+
+
+## Instructions
+
+
+
+Implement a function that returns the sum of the $n$-th row.
+
+
+
+## Tests
+
+
+
+```yml
+tests:
+ - text: numberOfNames
is a function.
+ testString: assert(typeof numberOfNames === 'function');
+ - text: numberOfNames(5)
should equal 7.
+ testString: assert.equal(numberOfNames(5), 7);
+ - text: numberOfNames(12)
should equal 77.
+ testString: assert.equal(numberOfNames(12), 77);
+ - text: numberOfNames(18)
should equal 385.
+ testString: assert.equal(numberOfNames(18), 385);
+ - text: numberOfNames(23)
should equal 1255.
+ testString: assert.equal(numberOfNames(23), 1255);
+ - text: numberOfNames(42)
should equal 53174.
+ testString: assert.equal(numberOfNames(42), 53174);
+ - text: numberOfNames(123)
should equal 2552338241.
+ testString: assert.equal(numberOfNames(123), 2552338241);
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+
+```js
+function numberOfNames(num) {
+ // Good luck!
+ return true;
+}
+```
+
+
+
+
+
+## Solution
+
+
+
+```js
+function numberOfNames(num) {
+ const cache = [
+ [1]
+ ];
+ for (let l = cache.length; l < num + 1; l++) {
+ let Aa;
+ let Mi;
+ const r = [0];
+ for (let x = 1; x < l + 1; x++) {
+ r.push(r[r.length - 1] + (Aa = cache[l - x < 0 ? cache.length - (l - x) : l - x])[(Mi = Math.min(x, l - x)) < 0 ? Aa.length - Mi : Mi]);
+ }
+ cache.push(r);
+ }
+ return cache[num][cache[num].length - 1];
+}
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/bootstrap-block-button.md b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/bootstrap-block-button.md
new file mode 100644
index 0000000000..e59fa1e473
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/bootstrap-block-button.md
@@ -0,0 +1,179 @@
+---
+id: bad87fee1348cd8acef08812
+title: Create a Block Element Bootstrap Button
+challengeType: 0
+forumTopicId: 16810
+---
+
+## Description
+
+Normally, your button
elements with the btn
and btn-default
classes are only as wide as the text that they contain. For example:
+<button class="btn btn-default">Submit</button>
+This button would only be as wide as the word "Submit".
+Submit
+By making them block elements with the additional class of btn-block
, your button will stretch to fill your page's entire horizontal space and any elements following it will flow onto a "new line" below the block.
+<button class="btn btn-default btn-block">Submit</button>
+This button would take up 100% of the available width.
+Submit
+Note that these buttons still need the btn
class.
+Add Bootstrap's btn-block
class to your Bootstrap button.
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: Your button should still have the btn
and btn-default
classes.
+ testString: assert($("button").hasClass("btn") && $("button").hasClass("btn-default"));
+ - text: Your button should have the class btn-block
.
+ testString: assert($("button").hasClass("btn-block"));
+ - text: All of your button
elements should have closing tags.
+ testString: assert(code.match(/<\/button>/g) && code.match(//g).length === code.match(/
+
+## Challenge Seed
+
+
+
+
+```html
+
+
+
+
+
CatPhotoApp
+
+
Click here for cat photos .
+
+
+
+
+
Like
+
Things cats love:
+
+ cat nip
+ laser pointers
+ lasagna
+
+
Top 3 things cats hate:
+
+ flea treatment
+ thunder
+ other cats
+
+
+
+```
+
+
+
+
+
+
+
+## Solution
+
+
+```html
+
+
+
+
+
CatPhotoApp
+
+
Click here for cat photos .
+
+
+
+
+
Like
+
Things cats love:
+
+ cat nip
+ laser pointers
+ lasagna
+
+
Top 3 things cats hate:
+
+ flea treatment
+ thunder
+ other cats
+
+
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/bootstrap-block-button.md.formatted b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/bootstrap-block-button.md.formatted
new file mode 100644
index 0000000000..abd9d23829
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/bootstrap-block-button.md.formatted
@@ -0,0 +1,193 @@
+---
+id: bad87fee1348cd8acef08812
+title: Create a Block Element Bootstrap Button
+challengeType: 0
+forumTopicId: 16810
+---
+
+## Description
+
+
+
+Normally, your `button` elements with the `btn` and `btn-default` classes are only as wide as the text that they contain. For example:
+
+`Submit `
+
+This button would only be as wide as the word "Submit".
+
+Submit
+
+By making them block elements with the additional class of `btn-block`, your button will stretch to fill your page's entire horizontal space and any elements following it will flow onto a "new line" below the block.
+
+`Submit `
+
+This button would take up 100% of the available width.
+
+Submit
+
+Note that these buttons still need the `btn` class.
+
+Add Bootstrap's `btn-block` class to your Bootstrap button.
+
+
+
+## Instructions
+
+
+
+## Tests
+
+
+
+```yml
+tests:
+ - text: Your button should still have the btn
and btn-default
classes.
+ testString: assert($("button").hasClass("btn") && $("button").hasClass("btn-default"));
+ - text: Your button should have the class btn-block
.
+ testString: assert($("button").hasClass("btn-block"));
+ - text: All of your button
elements should have closing tags.
+ testString: assert(code.match(/<\/button>/g) && code.match(//g).length === code.match(/
+
+## Challenge Seed
+
+
+
+
+
+```html
+
+
+
+
+
CatPhotoApp
+
+
Click here for cat photos .
+
+
+
+
+
Like
+
Things cats love:
+
+ cat nip
+ laser pointers
+ lasagna
+
+
Top 3 things cats hate:
+
+ flea treatment
+ thunder
+ other cats
+
+
+
+```
+
+
+
+
+
+## Solution
+
+
+
+```html
+
+
+
+
+
CatPhotoApp
+
+
Click here for cat photos .
+
+
+
+
+
Like
+
Things cats love:
+
+ cat nip
+ laser pointers
+ lasagna
+
+
Top 3 things cats hate:
+
+ flea treatment
+ thunder
+ other cats
+
+
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/css.md b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/css.md
new file mode 100644
index 0000000000..2f65cb7ee7
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/css.md
@@ -0,0 +1,146 @@
+---
+id: bad87fee1348bd9aedf08805
+title: Use CSS Selectors to Style Elements
+challengeType: 0
+videoUrl: 'https://scrimba.com/c/cJKMBT2'
+forumTopicId: 18349
+---
+
+## Description
+
+With CSS, there are hundreds of CSS properties that you can use to change the way an element looks on your page.
+When you entered <h2 style="color: red;">CatPhotoApp</h2>
, you were styling that individual h2
element with inline CSS, which stands for Cascading Style Sheets.
+That's one way to specify the style of an element, but there's a better way to apply CSS.
+At the top of your code, create a style
block like this:
+
+```html
+
+```
+
+Inside that style block, you can create a CSS selector for all h2
elements. For example, if you wanted all h2
elements to be red, you would add a style rule that looks like this:
+
+```html
+
+```
+
+Note that it's important to have both opening and closing curly braces ({
and }
) around each element's style rule(s). You also need to make sure that your element's style definition is between the opening and closing style tags. Finally, be sure to add a semicolon to the end of each of your element's style rules.
+
+
+## Instructions
+
+Delete your h2
element's style attribute, and instead create a CSS style
block. Add the necessary CSS to turn all h2
elements blue.
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: The style attribute should be removed from your h2
element.
+ testString: assert(!$("h2").attr("style"));
+ - text: You should create a style
element.
+ testString: assert($("style") && $("style").length >= 1);
+ - text: Your h2
element should be blue.
+ testString: assert($("h2").css("color") === "rgb(0, 0, 255)");
+ - text: Your stylesheet h2
declaration should be valid with a semicolon and closing brace.
+ testString: assert(code.match(/h2\s*\{\s*color\s*:.*;\s*\}/g));
+ - text: All your style
elements should be valid and have closing tags.
+ testString: assert(code.match(/<\/style>/g) && code.match(/<\/style>/g).length === (code.match(/
+CatPhotoApp
+
+ Click here to view more cat photos .
+
+
+
+
+
Things cats love:
+
+ cat nip
+ laser pointers
+ lasagna
+
+
Top 3 things cats hate:
+
+ flea treatment
+ thunder
+ other cats
+
+
+
+
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/css.md.formatted b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/css.md.formatted
new file mode 100644
index 0000000000..c925d77191
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/css.md.formatted
@@ -0,0 +1,156 @@
+---
+id: bad87fee1348bd9aedf08805
+title: Use CSS Selectors to Style Elements
+challengeType: 0
+videoUrl: 'https://scrimba.com/c/cJKMBT2'
+forumTopicId: 18349
+---
+
+## Description
+
+
+
+With CSS, there are hundreds of CSS properties that you can use to change the way an element looks on your page.
+
+When you entered `CatPhotoApp `, you were styling that individual `h2` element with inline CSS, which stands for Cascading Style Sheets.
+
+That's one way to specify the style of an element, but there's a better way to apply CSS.
+
+At the top of your code, create a `style` block like this:
+
+```html
+
+```
+
+Inside that style block, you can create a CSS selector for all `h2` elements. For example, if you wanted all `h2` elements to be red, you would add a style rule that looks like this:
+
+```html
+
+```
+
+Note that it's important to have both opening and closing curly braces (`{` and `}`) around each element's style rule(s). You also need to make sure that your element's style definition is between the opening and closing style tags. Finally, be sure to add a semicolon to the end of each of your element's style rules.
+
+
+
+## Instructions
+
+
+
+Delete your `h2` element's style attribute, and instead create a CSS `style` block. Add the necessary CSS to turn all `h2` elements blue.
+
+
+
+## Tests
+
+
+
+```yml
+tests:
+ - text: The style attribute should be removed from your h2
element.
+ testString: assert(!$("h2").attr("style"));
+ - text: You should create a style
element.
+ testString: assert($("style") && $("style").length >= 1);
+ - text: Your h2
element should be blue.
+ testString: assert($("h2").css("color") === "rgb(0, 0, 255)");
+ - text: Your stylesheet h2
declaration should be valid with a semicolon and closing brace.
+ testString: assert(code.match(/h2\s*\{\s*color\s*:.*;\s*\}/g));
+ - text: All your style
elements should be valid and have closing tags.
+ testString: assert(code.match(/<\/style>/g) && code.match(/<\/style>/g).length === (code.match(/
+CatPhotoApp
+
+ Click here to view more cat photos .
+
+
+
+
+
Things cats love:
+
+ cat nip
+ laser pointers
+ lasagna
+
+
Top 3 things cats hate:
+
+ flea treatment
+ thunder
+ other cats
+
+
+
+
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/dead-links.md b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/dead-links.md
new file mode 100644
index 0000000000..7abe72d762
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/dead-links.md
@@ -0,0 +1,71 @@
+---
+id: bad87fee1348bd9aedf08817
+title: Make Dead Links Using the Hash Symbol
+challengeType: 0
+videoUrl: 'https://scrimba.com/p/pVMPUv/cMdkytL'
+forumTopicId: 18230
+---
+
+## Description
+
+Sometimes you want to add a
elements to your website before you know where they will link.
+This is also handy when you're changing the behavior of a link using JavaScript
, which we'll learn about later.
+
+
+## Instructions
+
+The current value of the href
attribute is a link that points to "http://freecatphotoapp.com". Replace the href
attribute value with a #
, also known as a hash symbol, to create a dead link.
+For example: href="#"
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: Your a
element should be a dead link with the value of the href
attribute set to "#".
+ testString: assert($("a").attr("href") === "#");
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+```html
+
CatPhotoApp
+
+ Click here to view more cat photos .
+
+
+
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+
+```
+
+
+
+
+
+
+
+## Solution
+
+
+```html
+CatPhotoApp
+
+ Click here to view more cat photos .
+
+
+
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/dead-links.md.formatted b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/dead-links.md.formatted
new file mode 100644
index 0000000000..95593225bf
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/dead-links.md.formatted
@@ -0,0 +1,80 @@
+---
+id: bad87fee1348bd9aedf08817
+title: Make Dead Links Using the Hash Symbol
+challengeType: 0
+videoUrl: 'https://scrimba.com/p/pVMPUv/cMdkytL'
+forumTopicId: 18230
+---
+
+## Description
+
+
+
+Sometimes you want to add `a` elements to your website before you know where they will link.
+
+This is also handy when you're changing the behavior of a link using `JavaScript`, which we'll learn about later.
+
+
+
+## Instructions
+
+
+
+The current value of the `href` attribute is a link that points to "`http://freecatphotoapp.com`". Replace the `href` attribute value with a `#`, also known as a hash symbol, to create a dead link.
+
+For example: `href="#"`
+
+
+
+## Tests
+
+
+
+```yml
+tests:
+ - text: Your a
element should be a dead link with the value of the href
attribute set to "#".
+ testString: assert($("a").attr("href") === "#");
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+
+```html
+
CatPhotoApp
+
+ Click here to view more cat photos .
+
+
+
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+
+```
+
+
+
+
+
+## Solution
+
+
+
+```html
+CatPhotoApp
+
+ Click here to view more cat photos .
+
+
+
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/disjoint-sublist.md b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/disjoint-sublist.md
new file mode 100644
index 0000000000..83a4d315b2
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/disjoint-sublist.md
@@ -0,0 +1,83 @@
+---
+id: 5a23c84252665b21eecc8000
+title: Sort disjoint sublist
+challengeType: 5
+forumTopicId: 302307
+---
+
+## Description
+
+Given a list of values and a set of integer indices into that value list, the task is to sort the values at the given indices, but preserving the values at indices outside the set of those to be sorted.
+Make your function work with the following list of values and set of indices:
+ values: [7, 6 , 5, 4, 3, 2, 1 , 0 ]
+ indices(0-based): {6, 1, 7}
+Where the correct result would be:
+[7, 0 , 5, 4, 3, 2, 1 , 6 ]
.
+
+
+## Instructions
+
+
+## Tests
+
+
+``` yml
+tests:
+ - text: sortDisjoint
should be a function.
+ testString: assert(typeof sortDisjoint == 'function', 'sortDisjoint
should be a function.');
+ - text: sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [6, 1, 7])
should return an array.
+ testString: assert(Array.isArray(sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [6, 1, 7])), 'sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [6, 1, 7])
should return an array.');
+ - text: sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [6, 1, 7])
should return [7, 0, 5, 4, 3, 2, 1, 6]
.
+ testString: assert.deepEqual(sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [6, 1, 7]), [7, 0, 5, 4, 3, 2, 1, 6], 'sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [6, 1, 7])
should return [7, 0, 5, 4, 3, 2, 1, 6]
.');
+ - text: sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [1, 2, 5, 6])
should return [7, 1, 2, 4, 3, 5, 6, 0]
.
+ testString: assert.deepEqual(sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [1, 2, 5, 6]), [7, 1, 2, 4, 3, 5, 6, 0], 'sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [1, 2, 5, 6])
should return [7, 1, 2, 4, 3, 5, 6, 0]
.');
+ - text: sortDisjoint([8, 7, 6, 5, 4, 3, 2, 1], [6, 1, 7])
should return [8, 1, 6, 5, 4, 3, 2, 7]
.
+ testString: assert.deepEqual(sortDisjoint([8, 7, 6, 5, 4, 3, 2, 1], [6, 1, 7]), [8, 1, 6, 5, 4, 3, 2, 7], 'sortDisjoint([8, 7, 6, 5, 4, 3, 2, 1], [6, 1, 7])
should return [8, 1, 6, 5, 4, 3, 2, 7]
.');
+ - text: sortDisjoint([8, 7, 6, 5, 4, 3, 2, 1], [1, 3, 5, 6])
should return [8, 2, 6, 3, 4, 5, 7, 1]
.
+ testString: assert.deepEqual(sortDisjoint([8, 7, 6, 5, 4, 3, 2, 1], [1, 3, 5, 6]), [8, 2, 6, 3, 4, 5, 7, 1], 'sortDisjoint([8, 7, 6, 5, 4, 3, 2, 1], [1, 3, 5, 6])
should return [8, 2, 6, 3, 4, 5, 7, 1]
.');
+ - text: sortDisjoint([6, 1, 7, 1, 3, 5, 6], [6, 1, 5, 4])
should return [6, 1, 7, 1, 3, 5, 6]
.
+ testString: assert.deepEqual(sortDisjoint([6, 1, 7, 1, 3, 5, 6], [6, 1, 5, 4]), [6, 1, 7, 1, 3, 5, 6],'sortDisjoint([6, 1, 7, 1, 3, 5, 6], [6, 1, 5, 4])
should return [6, 1, 7, 1, 3, 5, 6]
.');
+```
+
+
+
+## Challenge Seed
+
+
+
+```js
+function sortDisjoint(values, indices) {
+ // Good luck!
+}
+```
+
+
+
+
+
+## Solution
+
+
+```js
+function sortDisjoint(values, indices) {
+ let sublist = [];
+
+ indices.sort(function (a, b) { return a - b; });
+
+ for (let i = 0; i < indices.length; i++) {
+ sublist.push(values[indices[i]]);
+ }
+
+ sublist.sort((a, b) => { return a - b; });
+
+ for (let i = 0; i < indices.length; i++) {
+ values[indices[i]] = sublist[i];
+ }
+
+ return values;
+}
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/disjoint-sublist.md.formatted b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/disjoint-sublist.md.formatted
new file mode 100644
index 0000000000..fe16839605
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/disjoint-sublist.md.formatted
@@ -0,0 +1,95 @@
+---
+id: 5a23c84252665b21eecc8000
+title: Sort disjoint sublist
+challengeType: 5
+forumTopicId: 302307
+---
+
+## Description
+
+
+
+Given a list of values and a set of integer indices into that value list, the task is to sort the values at the given indices, but preserving the values at indices outside the set of those to be sorted.
+
+Make your function work with the following list of values and set of indices:
+
+values: [7, 6 , 5, 4, 3, 2, 1 , 0 ]
+
+`indices(0-based): {6, 1, 7}`
+
+Where the correct result would be:
+
+[7, 0 , 5, 4, 3, 2, 1 , 6 ]
.
+
+
+
+## Instructions
+
+
+
+## Tests
+
+
+
+```yml
+tests:
+ - text: sortDisjoint
should be a function.
+ testString: assert(typeof sortDisjoint == 'function', 'sortDisjoint
should be a function.');
+ - text: sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [6, 1, 7])
should return an array.
+ testString: assert(Array.isArray(sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [6, 1, 7])), 'sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [6, 1, 7])
should return an array.');
+ - text: sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [6, 1, 7])
should return [7, 0, 5, 4, 3, 2, 1, 6]
.
+ testString: assert.deepEqual(sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [6, 1, 7]), [7, 0, 5, 4, 3, 2, 1, 6], 'sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [6, 1, 7])
should return [7, 0, 5, 4, 3, 2, 1, 6]
.');
+ - text: sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [1, 2, 5, 6])
should return [7, 1, 2, 4, 3, 5, 6, 0]
.
+ testString: assert.deepEqual(sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [1, 2, 5, 6]), [7, 1, 2, 4, 3, 5, 6, 0], 'sortDisjoint([7, 6, 5, 4, 3, 2, 1, 0], [1, 2, 5, 6])
should return [7, 1, 2, 4, 3, 5, 6, 0]
.');
+ - text: sortDisjoint([8, 7, 6, 5, 4, 3, 2, 1], [6, 1, 7])
should return [8, 1, 6, 5, 4, 3, 2, 7]
.
+ testString: assert.deepEqual(sortDisjoint([8, 7, 6, 5, 4, 3, 2, 1], [6, 1, 7]), [8, 1, 6, 5, 4, 3, 2, 7], 'sortDisjoint([8, 7, 6, 5, 4, 3, 2, 1], [6, 1, 7])
should return [8, 1, 6, 5, 4, 3, 2, 7]
.');
+ - text: sortDisjoint([8, 7, 6, 5, 4, 3, 2, 1], [1, 3, 5, 6])
should return [8, 2, 6, 3, 4, 5, 7, 1]
.
+ testString: assert.deepEqual(sortDisjoint([8, 7, 6, 5, 4, 3, 2, 1], [1, 3, 5, 6]), [8, 2, 6, 3, 4, 5, 7, 1], 'sortDisjoint([8, 7, 6, 5, 4, 3, 2, 1], [1, 3, 5, 6])
should return [8, 2, 6, 3, 4, 5, 7, 1]
.');
+ - text: sortDisjoint([6, 1, 7, 1, 3, 5, 6], [6, 1, 5, 4])
should return [6, 1, 7, 1, 3, 5, 6]
.
+ testString: assert.deepEqual(sortDisjoint([6, 1, 7, 1, 3, 5, 6], [6, 1, 5, 4]), [6, 1, 7, 1, 3, 5, 6],'sortDisjoint([6, 1, 7, 1, 3, 5, 6], [6, 1, 5, 4])
should return [6, 1, 7, 1, 3, 5, 6]
.');
+```
+
+
+
+## Challenge Seed
+
+
+
+
+```js
+function sortDisjoint(values, indices) {
+ // Good luck!
+}
+```
+
+
+
+
+
+## Solution
+
+
+
+```js
+function sortDisjoint(values, indices) {
+ let sublist = [];
+
+ indices.sort(function (a, b) { return a - b; });
+
+ for (let i = 0; i < indices.length; i++) {
+ sublist.push(values[indices[i]]);
+ }
+
+ sublist.sort((a, b) => { return a - b; });
+
+ for (let i = 0; i < indices.length; i++) {
+ values[indices[i]] = sublist[i];
+ }
+
+ return values;
+}
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/drum-machine.md b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/drum-machine.md
new file mode 100644
index 0000000000..479507c0b0
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/drum-machine.md
@@ -0,0 +1,53 @@
+---
+id: 587d7dbc367417b2b2512bae
+title: Build a Drum Machine
+isRequired: true
+challengeType: 3
+forumTopicId: 301370
+---
+
+## Description
+
+Objective: Build a CodePen.io app that is functionally similar to this: https://codepen.io/freeCodeCamp/full/MJyNMd .
+Fulfill the below user stories and get all of the tests to pass. Give it your own personal style.
+You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!
+User Story #1: I should be able to see an outer container with a corresponding id="drum-machine"
that contains all other elements.
+User Story #2: Within #drum-machine
I can see an element with a corresponding id="display"
.
+User Story #3: Within #drum-machine
I can see 9 clickable drum pad elements, each with a class name of drum-pad
, a unique id that describes the audio clip the drum pad will be set up to trigger, and an inner text that corresponds to one of the following keys on the keyboard: Q, W, E, A, S, D, Z, X, C. The drum pads MUST be in this order.
+User Story #4: Within each .drum-pad
, there should be an HTML5 audio
element which has a src
attribute pointing to an audio clip, a class name of clip
, and an id corresponding to the inner text of its parent .drum-pad
(e.g. id="Q"
, id="W"
, id="E"
etc.).
+User Story #5: When I click on a .drum-pad
element, the audio clip contained in its child audio
element should be triggered.
+User Story #6: When I press the trigger key associated with each .drum-pad
, the audio clip contained in its child audio
element should be triggered (e.g. pressing the Q key should trigger the drum pad which contains the string "Q", pressing the W key should trigger the drum pad which contains the string "W", etc.).
+User Story #7: When a .drum-pad
is triggered, a string describing the associated audio clip is displayed as the inner text of the #display
element (each string must be unique).
+You can build your project by forking this CodePen pen . Or you can use this CDN link to run the tests in any environment you like: https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js
+Once you're done, submit the URL to your working project with all its tests passing.
+Remember to use the Read-Search-Ask method if you get stuck.
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests: []
+
+```
+
+
+
+## Challenge Seed
+
+
+## Solution
+
+
+```js
+// solution required
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/drum-machine.md.formatted b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/drum-machine.md.formatted
new file mode 100644
index 0000000000..219d7a0b8c
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/drum-machine.md.formatted
@@ -0,0 +1,72 @@
+---
+id: 587d7dbc367417b2b2512bae
+title: Build a Drum Machine
+isRequired: true
+challengeType: 3
+forumTopicId: 301370
+---
+
+## Description
+
+
+
+**Objective:** Build a [CodePen.io](https://codepen.io) app that is functionally similar to this: .
+
+Fulfill the below [user stories](https://en.wikipedia.org/wiki/User_story) and get all of the tests to pass. Give it your own personal style.
+
+You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!
+
+**User Story #1:** I should be able to see an outer container with a corresponding `id="drum-machine"` that contains all other elements.
+
+**User Story #2:** Within `#drum-machine` I can see an element with a corresponding `id="display"`.
+
+**User Story #3:** Within `#drum-machine` I can see 9 clickable drum pad elements, each with a class name of `drum-pad`, a unique id that describes the audio clip the drum pad will be set up to trigger, and an inner text that corresponds to one of the following keys on the keyboard: Q, W, E, A, S, D, Z, X, C. The drum pads MUST be in this order.
+
+**User Story #4:** Within each `.drum-pad`, there should be an HTML5 `audio` element which has a `src` attribute pointing to an audio clip, a class name of `clip`, and an id corresponding to the inner text of its parent `.drum-pad` (e.g. `id="Q"`, `id="W"`, `id="E"` etc.).
+
+**User Story #5:** When I click on a `.drum-pad` element, the audio clip contained in its child `audio` element should be triggered.
+
+**User Story #6:** When I press the trigger key associated with each `.drum-pad`, the audio clip contained in its child `audio` element should be triggered (e.g. pressing the Q key should trigger the drum pad which contains the string "Q", pressing the W key should trigger the drum pad which contains the string "W", etc.).
+
+**User Story #7:** When a `.drum-pad` is triggered, a string describing the associated audio clip is displayed as the inner text of the `#display` element (each string must be unique).
+
+You can build your project by forking [this CodePen pen](http://codepen.io/freeCodeCamp/pen/MJjpwO). Or you can use this CDN link to run the tests in any environment you like: `https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js`
+
+Once you're done, submit the URL to your working project with all its tests passing.
+
+Remember to use the [Read-Search-Ask](https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514) method if you get stuck.
+
+
+
+## Instructions
+
+
+
+## Tests
+
+
+
+```yml
+tests: []
+
+```
+
+
+
+## Challenge Seed
+
+
+
+## Solution
+
+
+
+```js
+// solution required
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/entropy.md b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/entropy.md
new file mode 100644
index 0000000000..c3c366c289
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/entropy.md
@@ -0,0 +1,91 @@
+---
+title: Entropy
+id: 599d15309e88c813a40baf58
+challengeType: 5
+forumTopicId: 302254
+---
+
+## Description
+
+Calculate the Shannon entropy H of a given input string.
+Given the discreet random variable $X$ that is a string of $N$ "symbols" (total characters) consisting of $n$ different characters (n=2 for binary), the Shannon entropy of X in bits/symbol is:
+$H_2(X) = -\sum_{i=1}^n \frac{count_i}{N} \log_2 \left(\frac{count_i}{N}\right)$
+where $count_i$ is the count of character $n_i$.
+A bit extra <> to test http://bare-url-handling.com!
+
+
+## Instructions
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: entropy
should be a function.
+ testString: assert(typeof entropy === 'function');
+ - text: entropy("0")
should return 0
+ testString: assert.equal(entropy('0'), 0);
+ - text: entropy("01")
should return 1
+ testString: assert.equal(entropy('01'), 1);
+ - text: entropy("0123")
should return 2
+ testString: assert.equal(entropy('0123'), 2);
+ - text: entropy("01234567")
should return 3
+ testString: assert.equal(entropy('01234567'), 3);
+ - text: entropy("0123456789abcdef")
should return 4
+ testString: assert.equal(entropy('0123456789abcdef'), 4);
+ - text: entropy("1223334444")
should return 1.8464393446710154
+ testString: assert.equal(entropy('1223334444'), 1.8464393446710154);
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+```js
+function entropy(s) {
+ // Good luck!
+}
+```
+
+
+
+
+
+
+
+## Solution
+
+
+
+```js
+function entropy(s) {
+ // Create a dictionary of character frequencies and iterate over it.
+ function process(s, evaluator) {
+ let h = Object.create(null),
+ k;
+ s.split('').forEach(c => {
+ h[c] && h[c]++ || (h[c] = 1); });
+ if (evaluator) for (k in h) evaluator(k, h[k]);
+ return h;
+ }
+ // Measure the entropy of a string in bits per symbol.
+
+ let sum = 0,
+ len = s.length;
+ process(s, (k, f) => {
+ const p = f / len;
+ sum -= p * Math.log(p) / Math.log(2);
+ });
+ return sum;
+}
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/entropy.md.formatted b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/entropy.md.formatted
new file mode 100644
index 0000000000..df06fda747
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/entropy.md.formatted
@@ -0,0 +1,99 @@
+---
+title: Entropy
+id: 599d15309e88c813a40baf58
+challengeType: 5
+forumTopicId: 302254
+---
+
+## Description
+
+
+
+Calculate the Shannon entropy H of a given input string.
+
+Given the discreet random variable $X$ that is a string of $N$ "symbols" (total characters) consisting of $n$ different characters (n=2 for binary), the Shannon entropy of X in bits/symbol is:
+
+$H_2(X) = -\\sum\_{i=1}^n \\frac{count_i}{N} \\log_2 \\left(\\frac{count_i}{N}\\right)$
+
+where $count_i$ is the count of character $n_i$.
+
+A bit extra <> to test `http://bare-url-handling.com`!
+
+
+
+## Instructions
+
+
+
+## Tests
+
+
+
+```yml
+tests:
+ - text: entropy
should be a function.
+ testString: assert(typeof entropy === 'function');
+ - text: entropy("0")
should return 0
+ testString: assert.equal(entropy('0'), 0);
+ - text: entropy("01")
should return 1
+ testString: assert.equal(entropy('01'), 1);
+ - text: entropy("0123")
should return 2
+ testString: assert.equal(entropy('0123'), 2);
+ - text: entropy("01234567")
should return 3
+ testString: assert.equal(entropy('01234567'), 3);
+ - text: entropy("0123456789abcdef")
should return 4
+ testString: assert.equal(entropy('0123456789abcdef'), 4);
+ - text: entropy("1223334444")
should return 1.8464393446710154
+ testString: assert.equal(entropy('1223334444'), 1.8464393446710154);
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+
+```js
+function entropy(s) {
+ // Good luck!
+}
+```
+
+
+
+
+
+## Solution
+
+
+
+```js
+function entropy(s) {
+ // Create a dictionary of character frequencies and iterate over it.
+ function process(s, evaluator) {
+ let h = Object.create(null),
+ k;
+ s.split('').forEach(c => {
+ h[c] && h[c]++ || (h[c] = 1); });
+ if (evaluator) for (k in h) evaluator(k, h[k]);
+ return h;
+ }
+ // Measure the entropy of a string in bits per symbol.
+
+ let sum = 0,
+ len = s.length;
+ process(s, (k, f) => {
+ const p = f / len;
+ sum -= p * Math.log(p) / Math.log(2);
+ });
+ return sum;
+}
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hello.md b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hello.md
new file mode 100644
index 0000000000..3ca5c69699
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hello.md
@@ -0,0 +1,63 @@
+---
+id: bd7123c8c441eddfaeb5bdef
+title: Say Hello to HTML Elements
+challengeType: 0
+videoUrl: 'https://scrimba.com/p/pVMPUv/cE8Gpt2'
+forumTopicId: 18276
+---
+
+## Description
+
+Welcome to freeCodeCamp's HTML coding challenges. These will walk you through web development step-by-step.
+First, you'll start by building a simple web page using HTML. You can edit code in your code editor, which is embedded into this web page.
+Do you see the code in your code editor that says <h1>Hello</h1>
? That's an HTML element.
+Most HTML elements have an opening tag and a closing tag.
+Opening tags look like this:
+<h1>
+Closing tags look like this:
+</h1>
+The only difference between opening and closing tags is the forward slash after the opening bracket of a closing tag.
+Each challenge has tests you can run at any time by clicking the "Run tests" button. When you pass all tests, you'll be prompted to submit your solution and go to the next coding challenge.
+Note: Testing non-breaking note stuff.
+
+
+## Instructions
+
+To pass the test on this challenge, change your h1
element's text to say "Hello World".
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: Your h1
element should have the text "Hello World".
+ testString: assert.isTrue((/hello(\s)+world/gi).test($('h1').text()));
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+```html
+
Hello
+```
+
+
+
+
+
+
+
+## Solution
+
+
+```html
+Hello World
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hello.md.formatted b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hello.md.formatted
new file mode 100644
index 0000000000..88e4374c8b
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hello.md.formatted
@@ -0,0 +1,80 @@
+---
+id: bd7123c8c441eddfaeb5bdef
+title: Say Hello to HTML Elements
+challengeType: 0
+videoUrl: 'https://scrimba.com/p/pVMPUv/cE8Gpt2'
+forumTopicId: 18276
+---
+
+## Description
+
+
+
+Welcome to freeCodeCamp's HTML coding challenges. These will walk you through web development step-by-step.
+
+First, you'll start by building a simple web page using HTML. You can edit code in your code editor, which is embedded into this web page.
+
+Do you see the code in your code editor that says `Hello `? That's an HTML element.
+
+Most HTML elements have an opening tag and a closing tag.
+
+Opening tags look like this:
+
+``
+
+Closing tags look like this:
+
+` `
+
+The only difference between opening and closing tags is the forward slash after the opening bracket of a closing tag.
+
+Each challenge has tests you can run at any time by clicking the "Run tests" button. When you pass all tests, you'll be prompted to submit your solution and go to the next coding challenge.
+
+**Note:** Testing non-breaking note stuff.
+
+
+
+## Instructions
+
+
+
+To pass the test on this challenge, change your `h1` element's text to say "Hello World".
+
+
+
+## Tests
+
+
+
+```yml
+tests:
+ - text: Your h1
element should have the text "Hello World".
+ testString: assert.isTrue((/hello(\s)+world/gi).test($('h1').text()));
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+
+```html
+
Hello
+```
+
+
+
+
+
+## Solution
+
+
+
+```html
+Hello World
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hofstadter.md b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hofstadter.md
new file mode 100644
index 0000000000..a5354d096b
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hofstadter.md
@@ -0,0 +1,136 @@
+---
+title: Hofstadter Figure-Figure sequences
+id: 59622f89e4e137560018a40e
+challengeType: 5
+forumTopicId: 302286
+---
+
+## Description
+
+These two sequences of positive integers are defined as:
+$R(1)=1\ ;\ S(1)=2 \\R(n)=R(n-1)+S(n-1), \quad n>1.$
+The sequence $S(n)$ is further defined as the sequence of positive integers not present in $R(n)$ .
+Sequence $R$ starts:
+1, 3, 7, 12, 18, ...
+Sequence $S$ starts:
+2, 4, 5, 6, 8, ...
+
+
+## Instructions
+
+Create two functions named ffr
and ffs
that when given n
return R(n)
or S(n)
respectively. (Note that R(1) = 1 and S(1) = 2 to avoid off-by-one errors).
+No maximum value for n
should be assumed.
+References
+
+
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: ffr
should be a function.
+ testString: assert(typeof ffr === 'function');
+ - text: ffs
should be a function.
+ testString: assert(typeof ffs === 'function');
+ - text: ffr
should return integer.
+ testString: assert(Number.isInteger(ffr(1)));
+ - text: ffs
should return integer.
+ testString: assert(Number.isInteger(ffs(1)));
+ - text: ffr()
should return 69
+ testString: assert.equal(ffr(ffrParamRes[0][0]), ffrParamRes[0][1]);
+ - text: ffr()
should return 1509
+ testString: assert.equal(ffr(ffrParamRes[1][0]), ffrParamRes[1][1]);
+ - text: ffr()
should return 5764
+ testString: assert.equal(ffr(ffrParamRes[2][0]), ffrParamRes[2][1]);
+ - text: ffr()
should return 526334
+ testString: assert.equal(ffr(ffrParamRes[3][0]), ffrParamRes[3][1]);
+ - text: ffs()
should return 14
+ testString: assert.equal(ffs(ffsParamRes[0][0]), ffsParamRes[0][1]);
+ - text: ffs()
should return 59
+ testString: assert.equal(ffs(ffsParamRes[1][0]), ffsParamRes[1][1]);
+ - text: ffs()
should return 112
+ testString: assert.equal(ffs(ffsParamRes[2][0]), ffsParamRes[2][1]);
+ - text: ffs()
should return 1041
+ testString: assert.equal(ffs(ffsParamRes[3][0]), ffsParamRes[3][1]);
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+```js
+// noprotect
+function ffr(n) {
+ return n;
+}
+
+function ffs(n) {
+ return n;
+}
+```
+
+
+
+
+### After Test
+
+
+```js
+const ffrParamRes = [[10, 69], [50, 1509], [100, 5764], [1000, 526334]];
+const ffsParamRes = [[10, 14], [50, 59], [100, 112], [1000, 1041]];
+
+```
+
+
+
+
+
+## Solution
+
+
+
+```js
+// noprotect
+const R = [null, 1];
+const S = [null, 2];
+
+function extendSequences (n) {
+ let current = Math.max(R[R.length - 1], S[S.length - 1]);
+ let i;
+ while (R.length <= n || S.length <= n) {
+ i = Math.min(R.length, S.length) - 1;
+ current += 1;
+ if (current === R[i] + S[i]) {
+ R.push(current);
+ } else {
+ S.push(current);
+ }
+ }
+}
+
+function ffr (n) {
+ extendSequences(n);
+ return R[n];
+}
+
+function ffs (n) {
+ extendSequences(n);
+ return S[n];
+}
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hofstadter.md.formatted b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hofstadter.md.formatted
new file mode 100644
index 0000000000..9899218bc1
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/hofstadter.md.formatted
@@ -0,0 +1,152 @@
+---
+title: Hofstadter Figure-Figure sequences
+id: 59622f89e4e137560018a40e
+challengeType: 5
+forumTopicId: 302286
+---
+
+## Description
+
+
+
+These two sequences of positive integers are defined as:
+
+$R(1)=1\\ ;\\ S(1)=2 \\\\R(n)=R(n-1)+S(n-1), \\quad n>1.$
+
+The sequence $S(n)$ is further defined as the sequence of positive integers not present in $R(n)$.
+
+Sequence $R$ starts:
+
+1, 3, 7, 12, 18, ...
+
+Sequence $S$ starts:
+
+2, 4, 5, 6, 8, ...
+
+
+
+## Instructions
+
+
+
+Create two functions named `ffr` and `ffs` that when given `n` return `R(n)` or `S(n)` respectively. (Note that R(1) = 1 and S(1) = 2 to avoid off-by-one errors).
+
+No maximum value for `n` should be assumed.
+
+**References**
+
+
+
+
+
+## Tests
+
+
+
+```yml
+tests:
+ - text: ffr
should be a function.
+ testString: assert(typeof ffr === 'function');
+ - text: ffs
should be a function.
+ testString: assert(typeof ffs === 'function');
+ - text: ffr
should return integer.
+ testString: assert(Number.isInteger(ffr(1)));
+ - text: ffs
should return integer.
+ testString: assert(Number.isInteger(ffs(1)));
+ - text: ffr()
should return 69
+ testString: assert.equal(ffr(ffrParamRes[0][0]), ffrParamRes[0][1]);
+ - text: ffr()
should return 1509
+ testString: assert.equal(ffr(ffrParamRes[1][0]), ffrParamRes[1][1]);
+ - text: ffr()
should return 5764
+ testString: assert.equal(ffr(ffrParamRes[2][0]), ffrParamRes[2][1]);
+ - text: ffr()
should return 526334
+ testString: assert.equal(ffr(ffrParamRes[3][0]), ffrParamRes[3][1]);
+ - text: ffs()
should return 14
+ testString: assert.equal(ffs(ffsParamRes[0][0]), ffsParamRes[0][1]);
+ - text: ffs()
should return 59
+ testString: assert.equal(ffs(ffsParamRes[1][0]), ffsParamRes[1][1]);
+ - text: ffs()
should return 112
+ testString: assert.equal(ffs(ffsParamRes[2][0]), ffsParamRes[2][1]);
+ - text: ffs()
should return 1041
+ testString: assert.equal(ffs(ffsParamRes[3][0]), ffsParamRes[3][1]);
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+
+```js
+// noprotect
+function ffr(n) {
+ return n;
+}
+
+function ffs(n) {
+ return n;
+}
+```
+
+
+
+### After Test
+
+
+
+```js
+const ffrParamRes = [[10, 69], [50, 1509], [100, 5764], [1000, 526334]];
+const ffsParamRes = [[10, 14], [50, 59], [100, 112], [1000, 1041]];
+
+```
+
+
+
+
+
+## Solution
+
+
+
+```js
+// noprotect
+const R = [null, 1];
+const S = [null, 2];
+
+function extendSequences (n) {
+ let current = Math.max(R[R.length - 1], S[S.length - 1]);
+ let i;
+ while (R.length <= n || S.length <= n) {
+ i = Math.min(R.length, S.length) - 1;
+ current += 1;
+ if (current === R[i] + S[i]) {
+ R.push(current);
+ } else {
+ S.push(current);
+ }
+ }
+}
+
+function ffr (n) {
+ extendSequences(n);
+ return R[n];
+}
+
+function ffs (n) {
+ extendSequences(n);
+ return S[n];
+}
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-external.md b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-external.md
new file mode 100644
index 0000000000..0d7aec6f17
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-external.md
@@ -0,0 +1,77 @@
+---
+id: bad87fee1348bd9aedf08816
+title: Link to External Pages with Anchor Elements
+challengeType: 0
+videoUrl: 'https://scrimba.com/p/pVMPUv/c8EkncB'
+forumTopicId: 18226
+---
+
+## Description
+
+You can use a
(anchor ) elements to link to content outside of your web page.
+a
elements need a destination web address called an href
attribute. They also need anchor text. Here's an example:
+EXAMPLE REMOVED AS IT'S NESTED
+Then your browser will display the text "this links to freecodecamp.org" as a link you can click. And that link will take you to the web address https://www.freecodecamp.org .
+
+
+## Instructions
+
+Create an a
element that links to http://freecatphotoapp.com
and has "cat photos" as its anchor text.
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: Your a
element should have the anchor text of "cat photos".
+ testString: assert((/cat photos/gi).test($("a").text()));
+ - text: You need an a
element that links to http://freecatphotoapp.com
+ testString: assert(/http:\/\/(www\.)?freecatphotoapp\.com/gi.test($("a").attr("href")));
+ - text: Make sure your a
element has a closing tag.
+ testString: assert(code.match(/<\/a>/g) && code.match(/<\/a>/g).length === code.match(/
+
+## Challenge Seed
+
+
+
+
+```html
+
CatPhotoApp
+
+
+
+
+
+
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+
+```
+
+
+
+
+
+
+
+## Solution
+
+
+```html
+CatPhotoApp
+
+
+
+
+ cat photos
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-external.md.formatted b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-external.md.formatted
new file mode 100644
index 0000000000..809f0fbc01
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-external.md.formatted
@@ -0,0 +1,87 @@
+---
+id: bad87fee1348bd9aedf08816
+title: Link to External Pages with Anchor Elements
+challengeType: 0
+videoUrl: 'https://scrimba.com/p/pVMPUv/c8EkncB'
+forumTopicId: 18226
+---
+
+## Description
+
+
+
+You can use `a` (*anchor*) elements to link to content outside of your web page.
+
+`a` elements need a destination web address called an `href` attribute. They also need anchor text. Here's an example:
+
+EXAMPLE REMOVED AS IT'S NESTED
+
+Then your browser will display the text **"this links to freecodecamp.org"** as a link you can click. And that link will take you to the web address **`https://www.freecodecamp.org`**.
+
+
+
+## Instructions
+
+
+
+Create an `a` element that links to `http://freecatphotoapp.com` and has "cat photos" as its anchor text.
+
+
+
+## Tests
+
+
+
+```yml
+tests:
+ - text: Your a
element should have the anchor text of "cat photos".
+ testString: assert((/cat photos/gi).test($("a").text()));
+ - text: You need an a
element that links to http://freecatphotoapp.com
+ testString: assert(/http:\/\/(www\.)?freecatphotoapp\.com/gi.test($("a").attr("href")));
+ - text: Make sure your a
element has a closing tag.
+ testString: assert(code.match(/<\/a>/g) && code.match(/<\/a>/g).length === code.match(/
+
+## Challenge Seed
+
+
+
+
+
+```html
+
CatPhotoApp
+
+
+
+
+
+
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+
+```
+
+
+
+
+
+## Solution
+
+
+
+```html
+CatPhotoApp
+
+
+
+
+ cat photos
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-internal.md b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-internal.md
new file mode 100644
index 0000000000..4f0bd39120
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-internal.md
@@ -0,0 +1,101 @@
+---
+id: bad88fee1348bd9aedf08816
+title: Link to Internal Sections of a Page with Anchor Elements
+challengeType: 0
+videoUrl: 'https://scrimba.com/p/pVMPUv/cyrDRUL'
+forumTopicId: 301098
+---
+
+## Description
+
+a
(anchor ) elements can also be used to create internal links to jump to different sections within a webpage.
+To create an internal link, you assign a link's href
attribute to a hash symbol #
plus the value of the id
attribute for the element that you want to internally link to, usually further down the page. You then need to add the same id
attribute to the element you are linking to. An id
is an attribute that uniquely describes an element.
+Below is an example of an internal anchor link and its target element:
+
+```html
+Contacts
+...
+
+```
+
+When users click the Contacts link, they'll be taken to the section of the webpage with the Contacts header element.
+
+
+## Instructions
+
+Change your external link to an internal link by changing the href
attribute to "#footer" and the text from "cat photos" to "Jump to Bottom".
+Remove the target="_blank"
attribute from the anchor tag since this causes the linked document to open in a new window tab.
+Then add an id
attribute with a value of "footer" to the <footer>
element at the bottom of the page.
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: There should be only one anchor tag on your page.
+ testString: assert($('a').length == 1);
+ - text: There should be only one footer
tag on your page.
+ testString: assert($('footer').length == 1);
+ - text: The a
tag should have an href
attribute set to "#footer".
+ testString: assert($('a').eq(0).attr('href') == "#footer");
+ - text: The a
tag should not have a target
attribute
+ testString: assert(typeof $('a').eq(0).attr('target') == typeof undefined || $('a').eq(0).attr('target') == true);
+ - text: The a
text should be "Jump to Bottom".
+ testString: assert($('a').eq(0).text().match(/Jump to Bottom/gi));
+ - text: The footer
tag should have an id
attribute set to "footer".
+ testString: assert($('footer').eq(0).attr('id') == "footer");
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+```html
+
CatPhotoApp
+
+
+ cat photos
+
+
+
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff. Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched. Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched. Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff. Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+ Meowwww loved it, hated it, loved it, hated it yet spill litter box, scratch at owner, destroy all furniture, especially couch or lay on arms while you're using the keyboard. Missing until dinner time toy mouse squeak roll over. With tail in the air lounge in doorway. Man running from cops stops to pet cats, goes to jail.
+ Intently stare at the same spot poop in the plant pot but kitten is playing with dead mouse. Get video posted to internet for chasing red dot leave fur on owners clothes meow to be let out and mesmerizing birds leave fur on owners clothes or favor packaging over toy so purr for no reason. Meow to be let out play time intently sniff hand run outside as soon as door open yet destroy couch.
+
+
+
+
+```
+
+
+
+
+
+## Solution
+
+
+```html
+CatPhotoApp
+
+
+ Jump to Bottom
+
+
+
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff. Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched. Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched. Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff. Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+ Meowwww loved it, hated it, loved it, hated it yet spill litter box, scratch at owner, destroy all furniture, especially couch or lay on arms while you're using the keyboard. Missing until dinner time toy mouse squeak roll over. With tail in the air lounge in doorway. Man running from cops stops to pet cats, goes to jail.
+ Intently stare at the same spot poop in the plant pot but kitten is playing with dead mouse. Get video posted to internet for chasing red dot leave fur on owners clothes meow to be let out and mesmerizing birds leave fur on owners clothes or favor packaging over toy so purr for no reason. Meow to be let out play time intently sniff hand run outside as soon as door open yet destroy couch.
+
+
+
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-internal.md.formatted b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-internal.md.formatted
new file mode 100644
index 0000000000..0f6a48de2a
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/link-internal.md.formatted
@@ -0,0 +1,114 @@
+---
+id: bad88fee1348bd9aedf08816
+title: Link to Internal Sections of a Page with Anchor Elements
+challengeType: 0
+videoUrl: 'https://scrimba.com/p/pVMPUv/cyrDRUL'
+forumTopicId: 301098
+---
+
+## Description
+
+
+
+`a` (*anchor*) elements can also be used to create internal links to jump to different sections within a webpage.
+
+To create an internal link, you assign a link's `href` attribute to a hash symbol `#` plus the value of the `id` attribute for the element that you want to internally link to, usually further down the page. You then need to add the same `id` attribute to the element you are linking to. An `id` is an attribute that uniquely describes an element.
+
+Below is an example of an internal anchor link and its target element:
+
+```html
+Contacts
+...
+
+```
+
+When users click the Contacts link, they'll be taken to the section of the webpage with the **Contacts** header element.
+
+
+
+## Instructions
+
+
+
+Change your external link to an internal link by changing the `href` attribute to "#footer" and the text from "cat photos" to "Jump to Bottom".
+
+Remove the `target="_blank"` attribute from the anchor tag since this causes the linked document to open in a new window tab.
+
+Then add an `id` attribute with a value of "footer" to the `` element at the bottom of the page.
+
+
+
+## Tests
+
+
+
+```yml
+tests:
+ - text: There should be only one anchor tag on your page.
+ testString: assert($('a').length == 1);
+ - text: There should be only one footer
tag on your page.
+ testString: assert($('footer').length == 1);
+ - text: The a
tag should have an href
attribute set to "#footer".
+ testString: assert($('a').eq(0).attr('href') == "#footer");
+ - text: The a
tag should not have a target
attribute
+ testString: assert(typeof $('a').eq(0).attr('target') == typeof undefined || $('a').eq(0).attr('target') == true);
+ - text: The a
text should be "Jump to Bottom".
+ testString: assert($('a').eq(0).text().match(/Jump to Bottom/gi));
+ - text: The footer
tag should have an id
attribute set to "footer".
+ testString: assert($('footer').eq(0).attr('id') == "footer");
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+
+```html
+
CatPhotoApp
+
+
+ cat photos
+
+
+
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff. Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched. Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched. Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff. Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+ Meowwww loved it, hated it, loved it, hated it yet spill litter box, scratch at owner, destroy all furniture, especially couch or lay on arms while you're using the keyboard. Missing until dinner time toy mouse squeak roll over. With tail in the air lounge in doorway. Man running from cops stops to pet cats, goes to jail.
+ Intently stare at the same spot poop in the plant pot but kitten is playing with dead mouse. Get video posted to internet for chasing red dot leave fur on owners clothes meow to be let out and mesmerizing birds leave fur on owners clothes or favor packaging over toy so purr for no reason. Meow to be let out play time intently sniff hand run outside as soon as door open yet destroy couch.
+
+
+
+
+```
+
+
+
+
+
+## Solution
+
+
+
+```html
+CatPhotoApp
+
+
+ Jump to Bottom
+
+
+
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff. Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched. Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched. Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff. Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+ Meowwww loved it, hated it, loved it, hated it yet spill litter box, scratch at owner, destroy all furniture, especially couch or lay on arms while you're using the keyboard. Missing until dinner time toy mouse squeak roll over. With tail in the air lounge in doorway. Man running from cops stops to pet cats, goes to jail.
+ Intently stare at the same spot poop in the plant pot but kitten is playing with dead mouse. Get video posted to internet for chasing red dot leave fur on owners clothes meow to be let out and mesmerizing birds leave fur on owners clothes or favor packaging over toy so purr for no reason. Meow to be let out play time intently sniff hand run outside as soon as door open yet destroy couch.
+
+
+
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/nest-anchor.md b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/nest-anchor.md
new file mode 100644
index 0000000000..6a3ce65165
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/nest-anchor.md
@@ -0,0 +1,100 @@
+---
+id: bad87fee1348bd9aede08817
+title: Nest an Anchor Element within a Paragraph
+challengeType: 0
+videoUrl: 'https://scrimba.com/p/pVMPUv/cb6k8Cb'
+forumTopicId: 18244
+---
+
+## Description
+
+
+You can nest links within other text elements.
+
+```html
+
+ Here's a link to freecodecamp.org for you to follow.
+
+```
+
+Let's break down the example:
+Normal text is wrapped in the p
element: <p> Here's a ... for you to follow. </p>
+Next is the anchor element <a>
(which requires a closing tag </a>
): <a> ... </a>
+target
is an anchor tag attribute that specifies where to open the link and the value "_blank"
specifies to open the link in a new tab
+href
is an anchor tag attribute that contains the URL address of the link: ` ... `
+The text, "link to freecodecamp.org" , within the a
element called anchor text
, will display a link to click: <a href=" ... ">link to freecodecamp.org</a>
+The final output of the example will look like this:Here's a link to freecodecamp.org for you to follow.
+
+
+## Instructions
+
+
+Now nest the existing a
element within a new p
element (just after the existing main
element). The new paragraph should have text that says "View more cat photos", where "cat photos" is a link, and the rest of the text is plain text.
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: You need an a
element that links to "http://freecatphotoapp.com".
+ testString: assert(($("a[href=\"http://freecatphotoapp.com\"]").length > 0 || $("a[href=\"http://www.freecatphotoapp.com\"]").length > 0));
+ - text: Your a
element should have the anchor text of "cat photos"
+ testString: assert($("a").text().match(/cat\sphotos/gi));
+ - text: Create a new p
element around your a
element. There should be at least 3 total p
tags in your HTML code.
+ testString: assert($("p") && $("p").length > 2);
+ - text: Your a
element should be nested within your new p
element.
+ testString: assert(($("a[href=\"http://freecatphotoapp.com\"]").parent().is("p") || $("a[href=\"http://www.freecatphotoapp.com\"]").parent().is("p")));
+ - text: Your p
element should have the text "View more " (with a space after it).
+ testString: assert(($("a[href=\"http://freecatphotoapp.com\"]").parent().text().match(/View\smore\s/gi) || $("a[href=\"http://www.freecatphotoapp.com\"]").parent().text().match(/View\smore\s/gi)));
+ - text: Your a
element should not have the text "View more".
+ testString: assert(!$("a").text().match(/View\smore/gi));
+ - text: Make sure each of your p
elements has a closing tag.
+ testString: assert(code.match(/<\/p>/g) && code.match(//g).length === code.match(/
a
elements has a closing tag.
+ testString: assert(code.match(/<\/a>/g) && code.match(//g).length === code.match(/
+
+## Challenge Seed
+
+
+
+
+```html
+
CatPhotoApp
+
+
+ cat photos
+
+
+
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+
+```
+
+
+
+
+
+
+
+## Solution
+
+
+```html
+CatPhotoApp
+
+ View more cat photos
+
+
+
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/nest-anchor.md.formatted b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/nest-anchor.md.formatted
new file mode 100644
index 0000000000..c8e843908f
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/nest-anchor.md.formatted
@@ -0,0 +1,105 @@
+---
+id: bad87fee1348bd9aede08817
+title: Nest an Anchor Element within a Paragraph
+challengeType: 0
+videoUrl: 'https://scrimba.com/p/pVMPUv/cb6k8Cb'
+forumTopicId: 18244
+---
+
+## Description
+
+
+
+You can nest links within other text elements.
+
+```html
+
+ Here's a link to freecodecamp.org for you to follow.
+
+```
+
+Let's break down the example: Normal text is wrapped in the `p` element:
+` Here's a ... for you to follow.
` Next is the *anchor* element `` (which requires a closing tag ` `):
+` ... ` `target` is an anchor tag attribute that specifies where to open the link and the value `"_blank"` specifies to open the link in a new tab `href` is an anchor tag attribute that contains the URL address of the link:
+` ... ` The text, **"link to freecodecamp.org"**, within the `a` element called `anchor text`, will display a link to click:
+`link to freecodecamp.org ` The final output of the example will look like this:
+
+Here's a [link to freecodecamp.org](http://freecodecamp.org) for you to follow.
+
+
+
+## Instructions
+
+
+
+Now nest the existing `a` element within a new `p` element (just after the existing `main` element). The new paragraph should have text that says "View more cat photos", where "cat photos" is a link, and the rest of the text is plain text.
+
+
+
+## Tests
+
+
+
+```yml
+tests:
+ - text: You need an a
element that links to "http://freecatphotoapp.com".
+ testString: assert(($("a[href=\"http://freecatphotoapp.com\"]").length > 0 || $("a[href=\"http://www.freecatphotoapp.com\"]").length > 0));
+ - text: Your a
element should have the anchor text of "cat photos"
+ testString: assert($("a").text().match(/cat\sphotos/gi));
+ - text: Create a new p
element around your a
element. There should be at least 3 total p
tags in your HTML code.
+ testString: assert($("p") && $("p").length > 2);
+ - text: Your a
element should be nested within your new p
element.
+ testString: assert(($("a[href=\"http://freecatphotoapp.com\"]").parent().is("p") || $("a[href=\"http://www.freecatphotoapp.com\"]").parent().is("p")));
+ - text: Your p
element should have the text "View more " (with a space after it).
+ testString: assert(($("a[href=\"http://freecatphotoapp.com\"]").parent().text().match(/View\smore\s/gi) || $("a[href=\"http://www.freecatphotoapp.com\"]").parent().text().match(/View\smore\s/gi)));
+ - text: Your a
element should not have the text "View more".
+ testString: assert(!$("a").text().match(/View\smore/gi));
+ - text: Make sure each of your p
elements has a closing tag.
+ testString: assert(code.match(/<\/p>/g) && code.match(//g).length === code.match(/
a
elements has a closing tag.
+ testString: assert(code.match(/<\/a>/g) && code.match(//g).length === code.match(/
+
+## Challenge Seed
+
+
+
+
+
+```html
+
CatPhotoApp
+
+
+ cat photos
+
+
+
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+
+```
+
+
+
+
+
+## Solution
+
+
+
+```html
+CatPhotoApp
+
+ View more cat photos
+
+
+
+ Kitty ipsum dolor sit amet, shed everywhere shed everywhere stretching attack your ankles chase the red dot, hairball run catnip eat the grass sniff.
+ Purr jump eat the grass rip the couch scratched sunbathe, shed everywhere rip the couch sleep in the sink fluffy fur catnip scratched.
+
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/spiral-matrix.md b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/spiral-matrix.md
new file mode 100644
index 0000000000..ed05cf2518
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/spiral-matrix.md
@@ -0,0 +1,84 @@
+---
+id: 5a23c84252665b21eecc801c
+title: Spiral matrix
+challengeType: 5
+forumTopicId: 302321
+---
+
+## Description
+
+
+Produce a spiral array.
+A spiral array is a square arrangement of the first N2 natural numbers, where the numbers increase sequentially as you go around the edges of the array spiraling inwards.
+For example, given 5 , produce this array:
+
+0 1 2 3 4
+15 16 17 18 5
+14 23 24 19 6
+13 22 21 20 7
+12 11 10 9 8
+
+
+
+## Instructions
+
+
+## Tests
+
+
+``` yml
+tests:
+ - text: spiralArray
should be a function.
+ testString: assert(typeof spiralArray=='function','spiralArray
should be a function.');
+ - text: spiralArray(3)
should return an array.
+ testString: assert(Array.isArray(spiralArray(3)), 'spiralArray(3)
should return an array.');
+ - text: spiralArray(3)
should return [[0, 1, 2],[7, 8, 3],[6, 5, 4]]
.
+ testString: assert.deepEqual(spiralArray(3), [[0, 1, 2], [7, 8, 3], [6, 5, 4]], 'spiralArray(3)
should return [[0, 1, 2],[7, 8, 3],[6, 5, 4]]
.');
+ - text: spiralArray(4)
should return [[0, 1, 2, 3],[11, 12, 13, 4],[10, 15, 14, 5],[9, 8, 7, 6]]
.
+ testString: assert.deepEqual(spiralArray(4), [[0, 1, 2, 3], [11, 12, 13, 4], [10, 15, 14, 5], [9, 8, 7, 6]], 'spiralArray(4)
should return [[0, 1, 2, 3],[11, 12, 13, 4],[10, 15, 14, 5],[9, 8, 7, 6]]
.');
+ - text: spiralArray(5)
should return [[0, 1, 2, 3, 4],[15, 16, 17, 18, 5],[14, 23, 24, 19, 6],[13, 22, 21, 20, 7],[12, 11, 10, 9, 8]]
.
+ testString: assert.deepEqual(spiralArray(5), [[0, 1, 2, 3, 4], [15, 16, 17, 18, 5], [14, 23, 24, 19, 6], [13, 22, 21, 20, 7], [12, 11, 10, 9, 8]], 'spiralArray(5)
should return [[0, 1, 2, 3, 4],[15, 16, 17, 18, 5],[14, 23, 24, 19, 6],[13, 22, 21, 20, 7],[12, 11, 10, 9, 8]]
.');
+```
+
+
+
+## Challenge Seed
+
+
+
+
+```js
+function spiralArray(n) {
+ // Good luck!
+}
+```
+
+
+
+
+## Solution
+
+
+```js
+function spiralArray(n) {
+ var arr = Array(n),
+ x = 0, y = n,
+ total = n * n--,
+ dx = 1, dy = 0,
+ i = 0, j = 0;
+ while (y) arr[--y] = [];
+ while (i < total) {
+ arr[y][x] = i++;
+ x += dx; y += dy;
+ if (++j == n) {
+ if (dy < 0) {x++; y++; n -= 2}
+ j = dx; dx = -dy; dy = j; j = 0;
+ }
+ }
+ return arr;
+}
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/spiral-matrix.md.formatted b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/spiral-matrix.md.formatted
new file mode 100644
index 0000000000..7283fda55a
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/spiral-matrix.md.formatted
@@ -0,0 +1,90 @@
+---
+id: 5a23c84252665b21eecc801c
+title: Spiral matrix
+challengeType: 5
+forumTopicId: 302321
+---
+
+## Description
+
+
+
+Produce a spiral array. A *spiral array* is a square arrangement of the first N2 natural numbers, where the numbers increase sequentially as you go around the edges of the array spiraling inwards. For example, given **5**, produce this array:
+
+
+0 1 2 3 4
+15 16 17 18 5
+14 23 24 19 6
+13 22 21 20 7
+12 11 10 9 8
+
+
+
+
+## Instructions
+
+
+
+## Tests
+
+
+
+```yml
+tests:
+ - text: spiralArray
should be a function.
+ testString: assert(typeof spiralArray=='function','spiralArray
should be a function.');
+ - text: spiralArray(3)
should return an array.
+ testString: assert(Array.isArray(spiralArray(3)), 'spiralArray(3)
should return an array.');
+ - text: spiralArray(3)
should return [[0, 1, 2],[7, 8, 3],[6, 5, 4]]
.
+ testString: assert.deepEqual(spiralArray(3), [[0, 1, 2], [7, 8, 3], [6, 5, 4]], 'spiralArray(3)
should return [[0, 1, 2],[7, 8, 3],[6, 5, 4]]
.');
+ - text: spiralArray(4)
should return [[0, 1, 2, 3],[11, 12, 13, 4],[10, 15, 14, 5],[9, 8, 7, 6]]
.
+ testString: assert.deepEqual(spiralArray(4), [[0, 1, 2, 3], [11, 12, 13, 4], [10, 15, 14, 5], [9, 8, 7, 6]], 'spiralArray(4)
should return [[0, 1, 2, 3],[11, 12, 13, 4],[10, 15, 14, 5],[9, 8, 7, 6]]
.');
+ - text: spiralArray(5)
should return [[0, 1, 2, 3, 4],[15, 16, 17, 18, 5],[14, 23, 24, 19, 6],[13, 22, 21, 20, 7],[12, 11, 10, 9, 8]]
.
+ testString: assert.deepEqual(spiralArray(5), [[0, 1, 2, 3, 4], [15, 16, 17, 18, 5], [14, 23, 24, 19, 6], [13, 22, 21, 20, 7], [12, 11, 10, 9, 8]], 'spiralArray(5)
should return [[0, 1, 2, 3, 4],[15, 16, 17, 18, 5],[14, 23, 24, 19, 6],[13, 22, 21, 20, 7],[12, 11, 10, 9, 8]]
.');
+```
+
+
+
+## Challenge Seed
+
+
+
+
+
+```js
+function spiralArray(n) {
+ // Good luck!
+}
+```
+
+
+
+
+
+## Solution
+
+
+
+```js
+function spiralArray(n) {
+ var arr = Array(n),
+ x = 0, y = n,
+ total = n * n--,
+ dx = 1, dy = 0,
+ i = 0, j = 0;
+ while (y) arr[--y] = [];
+ while (i < total) {
+ arr[y][x] = i++;
+ x += dx; y += dy;
+ if (++j == n) {
+ if (dy < 0) {x++; y++; n -= 2}
+ j = dx; dx = -dy; dy = j; j = 0;
+ }
+ }
+ return arr;
+}
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/word-blanks.md b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/word-blanks.md
new file mode 100644
index 0000000000..f211620231
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/word-blanks.md
@@ -0,0 +1,91 @@
+---
+id: 56533eb9ac21ba0edf2244bb
+title: Word Blanks
+challengeType: 1
+videoUrl: 'https://scrimba.com/c/caqn8zuP'
+forumTopicId: 18377
+---
+
+## Description
+
+We will now use our knowledge of strings to build a "Mad Libs " style word game we're calling "Word Blanks". You will create an (optionally humorous) "Fill in the Blanks" style sentence.
+In a "Mad Libs" game, you are provided sentences with some missing words, like nouns, verbs, adjectives and adverbs. You then fill in the missing pieces with words of your choice in a way that the completed sentence makes sense.
+Consider this sentence - "It was really ____ , and we ____ ourselves ____ ". This sentence has three missing pieces- an adjective, a verb and an adverb, and we can add words of our choice to complete it. We can then assign the completed sentence to a variable as follows:
+
+```js
+var sentence = "It was really " + "hot" + ", and we " + "laughed" + " ourselves " + "silly" + ".";
+```
+
+
+
+## Instructions
+
+In this challenge, we provide you with a noun, a verb, an adjective and an adverb. You need to form a complete sentence using words of your choice, along with the words we provide.
+You will need to use the string concatenation operator +
to build a new string, using the provided variables: myNoun
, myAdjective
, myVerb
, and myAdverb
. You will then assign the formed string to the wordBlanks
variable. You should not change the words assigned to the variables.
+You will also need to account for spaces in your string, so that the final sentence has spaces between all the words. The result should be a complete sentence.
+
+
+## Tests
+
+
+```yml
+tests:
+ - text: wordBlanks
should be a string.
+ testString: assert(typeof wordBlanks === 'string');
+ - text: You should not change the values assigned to myNoun
, myVerb
, myAdjective
or myAdverb
.
+ testString: assert(myNoun === "dog" && myVerb === "ran" && myAdjective === "big" && myAdverb === "quickly");
+ - text: You should not directly use the values "dog", "ran", "big", or "quickly" to create wordBlanks
.
+ testString: const newCode = removeAssignments(code); assert(!/dog/.test(newCode) && !/ran/.test(newCode) && !/big/.test(newCode) && !/quickly/.test(newCode));
+ - text: wordBlanks
should contain all of the words assigned to the variables myNoun
, myVerb
, myAdjective
and myAdverb
separated by non-word characters (and any additional words in your madlib).
+ testString: assert(/\bdog\b/.test(wordBlanks) && /\bbig\b/.test(wordBlanks) && /\bran\b/.test(wordBlanks) && /\bquickly\b/.test(wordBlanks));
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+```js
+var myNoun = "dog";
+var myAdjective = "big";
+var myVerb = "ran";
+var myAdverb = "quickly";
+
+var wordBlanks = ""; // Only change this line;
+
+```
+
+
+
+
+
+```js
+const removeAssignments = str => str
+ .replace(/myNoun\s*=\s*["']dog["']/g, '')
+ .replace(/myAdjective\s*=\s*["']big["']/g, '')
+ .replace(/myVerb\s*=\s*["']ran["']/g, '')
+ .replace(/myAdverb\s*=\s*["']quickly["']/g, '');
+```
+
+
+
+
+
+## Solution
+
+
+
+```js
+var myNoun = "dog";
+var myAdjective = "big";
+var myVerb = "ran";
+var myAdverb = "quickly";
+
+var wordBlanks = "Once there was a " + myNoun + " which was very " + myAdjective + ". ";
+wordBlanks += "It " + myVerb + " " + myAdverb + " around the yard.";
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/word-blanks.md.formatted b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/word-blanks.md.formatted
new file mode 100644
index 0000000000..bd73df3e89
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/__fixtures__/word-blanks.md.formatted
@@ -0,0 +1,102 @@
+---
+id: 56533eb9ac21ba0edf2244bb
+title: Word Blanks
+challengeType: 1
+videoUrl: 'https://scrimba.com/c/caqn8zuP'
+forumTopicId: 18377
+---
+
+## Description
+
+
+
+We will now use our knowledge of strings to build a "[Mad Libs](https://en.wikipedia.org/wiki/Mad_Libs)" style word game we're calling "Word Blanks". You will create an (optionally humorous) "Fill in the Blanks" style sentence.
+
+In a "Mad Libs" game, you are provided sentences with some missing words, like nouns, verbs, adjectives and adverbs. You then fill in the missing pieces with words of your choice in a way that the completed sentence makes sense.
+
+Consider this sentence - "It was really **\_\_\_\_**, and we **\_\_\_\_** ourselves **\_\_\_\_**". This sentence has three missing pieces- an adjective, a verb and an adverb, and we can add words of our choice to complete it. We can then assign the completed sentence to a variable as follows:
+
+```js
+var sentence = "It was really " + "hot" + ", and we " + "laughed" + " ourselves " + "silly" + ".";
+```
+
+
+
+## Instructions
+
+
+
+In this challenge, we provide you with a noun, a verb, an adjective and an adverb. You need to form a complete sentence using words of your choice, along with the words we provide.
+
+You will need to use the string concatenation operator `+` to build a new string, using the provided variables: `myNoun`, `myAdjective`, `myVerb`, and `myAdverb`. You will then assign the formed string to the `wordBlanks` variable. You should not change the words assigned to the variables.
+
+You will also need to account for spaces in your string, so that the final sentence has spaces between all the words. The result should be a complete sentence.
+
+
+
+## Tests
+
+
+
+```yml
+tests:
+ - text: wordBlanks
should be a string.
+ testString: assert(typeof wordBlanks === 'string');
+ - text: You should not change the values assigned to myNoun
, myVerb
, myAdjective
or myAdverb
.
+ testString: assert(myNoun === "dog" && myVerb === "ran" && myAdjective === "big" && myAdverb === "quickly");
+ - text: You should not directly use the values "dog", "ran", "big", or "quickly" to create wordBlanks
.
+ testString: const newCode = removeAssignments(code); assert(!/dog/.test(newCode) && !/ran/.test(newCode) && !/big/.test(newCode) && !/quickly/.test(newCode));
+ - text: wordBlanks
should contain all of the words assigned to the variables myNoun
, myVerb
, myAdjective
and myAdverb
separated by non-word characters (and any additional words in your madlib).
+ testString: assert(/\bdog\b/.test(wordBlanks) && /\bbig\b/.test(wordBlanks) && /\bran\b/.test(wordBlanks) && /\bquickly\b/.test(wordBlanks));
+
+```
+
+
+
+## Challenge Seed
+
+
+
+
+
+```js
+var myNoun = "dog";
+var myAdjective = "big";
+var myVerb = "ran";
+var myAdverb = "quickly";
+
+var wordBlanks = ""; // Only change this line;
+
+```
+
+
+
+
+
+```js
+const removeAssignments = str => str
+ .replace(/myNoun\s*=\s*["']dog["']/g, '')
+ .replace(/myAdjective\s*=\s*["']big["']/g, '')
+ .replace(/myVerb\s*=\s*["']ran["']/g, '')
+ .replace(/myAdverb\s*=\s*["']quickly["']/g, '');
+```
+
+
+
+
+
+## Solution
+
+
+
+```js
+var myNoun = "dog";
+var myAdjective = "big";
+var myVerb = "ran";
+var myAdverb = "quickly";
+
+var wordBlanks = "Once there was a " + myNoun + " which was very " + myAdjective + ". ";
+wordBlanks += "It " + myVerb + " " + myAdverb + " around the yard.";
+```
+
+
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/acceptance.test.js b/tools/scripts/formatter/fcc-md-to-gfm/acceptance.test.js
new file mode 100644
index 0000000000..98a3166777
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/acceptance.test.js
@@ -0,0 +1,65 @@
+/* global expect */
+
+const fs = require('fs');
+const path = require('path');
+
+const {
+ insertSpaces,
+ codeToBackticks,
+ prettify
+} = require('./transformChallenges');
+
+// NOTE: As far as html rendering is concerned, it doesn't matter if you write
+
+/*
+ two spaces
+
+*/
+
+// or
+
+/*
+
+ two spaces
+
+*/
+// so the html parser trims any leading spaces.
+const fixtures = [
+ 'amicable-pairs.md',
+ 'entropy.md',
+ 'dead-links.md',
+ 'nest-anchor.md',
+ 'hello.md',
+ 'billion-names.md',
+ 'link-internal.md',
+ 'link-external.md',
+ 'drum-machine.md',
+ 'word-blanks.md',
+ 'css.md',
+ 'disjoint-sublist.md',
+ 'spiral-matrix.md',
+ 'bootstrap-block-button.md',
+ 'hofstadter.md'
+];
+
+describe('Challenge formatter', () => {
+ fixtures.forEach(fixture =>
+ it(`should transform ${fixture} into GFM correctly`, () => {
+ return insertSpaces(
+ path.resolve(__dirname, '__fixtures__/' + fixture),
+ true
+ )
+ .then(codeToBackticks)
+ .then(prettify)
+ .then(output => {
+ const formattedMd = fs.readFileSync(
+ path.resolve(__dirname, '__fixtures__/' + fixture + '.formatted'),
+ {
+ encoding: 'utf8'
+ }
+ );
+ expect(output).toEqual(formattedMd);
+ });
+ })
+ );
+});
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/code-to-backticks.js b/tools/scripts/formatter/fcc-md-to-gfm/code-to-backticks.js
new file mode 100644
index 0000000000..0747902329
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/code-to-backticks.js
@@ -0,0 +1,88 @@
+const visit = require('unist-util-visit');
+const toHast = require('mdast-util-to-hast');
+const raw = require('hast-util-raw');
+const toMdast = require('hast-util-to-mdast');
+const toHtml = require('hast-util-to-html');
+const inlineCode = require('hast-util-to-mdast/lib/handlers/inline-code');
+
+function getCodeToInline(shouldThrow) {
+ return (h, node) => {
+ if (node.children.length > 1) {
+ if (shouldThrow) {
+ console.log('Leaving code block as it does not just contain text');
+ console.log(node);
+ throw Error('Too many children');
+ } else {
+ return rawHtml(h, node);
+ }
+ } else {
+ return inlineCode(h, node);
+ }
+ };
+}
+
+function rawHtml(h, node) {
+ return {
+ type: 'html',
+ value: toHtml(node, {
+ allowDangerousCharacters: true,
+ allowDangerousHtml: true,
+ quote: "'"
+ })
+ };
+}
+
+function plugin({ shouldThrow = false, pre = false }) {
+ const codeToInline = getCodeToInline(shouldThrow);
+ return transformer;
+
+ function transformer(tree) {
+ if (pre) {
+ visit(tree, 'html', preVisitor);
+ } else {
+ visit(tree, 'paragraph', visitor);
+ }
+
+ function visitor(node, id, parent) {
+ const hast = toHast(node, { allowDangerousHtml: true });
+ const lastChild = hast.children.slice(-1)[0];
+
+ if (
+ shouldThrow &&
+ lastChild &&
+ lastChild.value &&
+ lastChild.value.match(/<\w*>/) &&
+ !lastChild.value.match(/ /)
+ ) {
+ console.log('Unclosed tag', lastChild.value);
+ throw Error('Unclosed tag in paragraph.');
+ }
+
+ const paragraph = raw(hast);
+ parent.children[id] = toMdast(paragraph, {
+ handlers: {
+ code: codeToInline,
+ dfn: rawHtml,
+ sup: rawHtml,
+ sub: rawHtml,
+ button: rawHtml
+ }
+ });
+ }
+
+ function preVisitor(node, id, parent) {
+ const paragraph = raw(toHast(node, { allowDangerousHtml: true }));
+ parent.children[id] = toMdast(paragraph, {
+ handlers: {
+ pre: codeToInline,
+ dfn: rawHtml,
+ sup: rawHtml,
+ sub: rawHtml,
+ button: rawHtml
+ }
+ });
+ }
+ }
+}
+
+module.exports = plugin;
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/formatCurriculum.js b/tools/scripts/formatter/fcc-md-to-gfm/formatCurriculum.js
new file mode 100644
index 0000000000..b7680f81e3
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/formatCurriculum.js
@@ -0,0 +1,21 @@
+const {
+ insertSpaces,
+ codeToBackticks,
+ prettify
+} = require('./transformChallenges');
+const readDirP = require('readdirp-walk');
+const fs = require('fs');
+
+const challengeDir = '../../../../curriculum/challenges/chinese';
+
+readDirP({ root: challengeDir, fileFilter: ['*.md'] }).on('data', file => {
+ if (file.stat.isFile()) {
+ insertSpaces(file.fullPath, true)
+ .then(codeToBackticks)
+ .then(prettify)
+ .then(text => fs.writeFileSync(file.fullPath, text))
+ .catch(() => {
+ console.log(file.path);
+ });
+ }
+});
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/insert-spaces.js b/tools/scripts/formatter/fcc-md-to-gfm/insert-spaces.js
new file mode 100644
index 0000000000..555710c13c
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/insert-spaces.js
@@ -0,0 +1,257 @@
+const unified = require('unified');
+const visit = require('unist-util-visit');
+const toHast = require('mdast-util-to-hast');
+const raw = require('hast-util-raw');
+const toHtml = require('hast-util-to-html');
+const isEmpty = require('lodash/isEmpty');
+const hastToMdast = require('hast-util-to-mdast');
+const remarkStringify = require('remark-stringify');
+const remarkParse = require('remark-parse');
+const { text } = require('mdast-builder');
+const parseEntities = require('parse-entities');
+const find = require('unist-util-find');
+const h = require('hastscript');
+const phrasing = require('hast-util-phrasing');
+
+const blankLine = { type: 'text', value: '\n\n' };
+
+/* Currently the challenge parser behaves differently depending on whether a
+section starts with an empty line or not. If it does not, the parser interprets
+single new-line (\n) characters as paragraph breaks. It also does not parse
+markdown syntax (such as `). This makes formatting challenges harder than it
+needs to be, since normal markdown rules do not apply (some of the time!)
+
+For example
+
+Sentence1.
+Sentence2 `var x = 'y'`.
+...
+
+becomes
+
+
+Sentence1.
+
+Sentence2 `var x = 'y'`.
+
+
+in the challenge, but should become
+
+
+Sentence1. Sentence2 var x = 'y'
.
+
+---
+
+This file converts the instructions and descriptions. After this there will be
+no need to handle the case where the first line is not empty and markdown syntax
+will alway work. The linter can check that the first blank line exists.
+*/
+
+var parser = unified().use(remarkParse);
+var mdCompiler = unified().use(remarkStringify);
+
+function stringifyMd(mdast) {
+ return mdCompiler.stringify(mdast);
+}
+
+function parseMd(text) {
+ return parser.parse(text);
+}
+
+function escapeMd(hastNode) {
+ // defensive copy because stringify mutates objects its called on...
+ hastNode = { ...hastNode };
+ // These are added by getParagraphs so must not be touched
+ if (hastNode.value === '\n\n') return hastNode;
+ // A trailing space gets converted to \n, because hastToMdast will be told
+ // told this is a paragraph, which it isn't
+ const trailingSpace = /\s/.test(hastNode.value[hastNode.value.length - 1]);
+ // leading spaces also get ignored, but need to be added in, since they can
+ // be following html elements.
+ const leadingSpace = /\s/.test(hastNode.value[0]);
+ // fake a hast tree. Is there a less hacky approach?
+ const hastTree = {
+ type: 'root',
+ children: [hastNode]
+ };
+ let value = stringifyMd(hastToMdast(hastTree));
+ // Removing the last character is always necessary, since stringify appends \n
+ value = value.slice(0, -1);
+ if (trailingSpace) value += ' ';
+ if (leadingSpace) value = ' ' + value;
+ // convert html entities into their characters
+ return { type: 'text', value: parseEntities(value) };
+}
+
+function wrapBareUrls(hastNode) {
+ const rawText = hastNode.value;
+ // blank lines can't have urls.
+ if (/^\s*$/.test(rawText)) return null;
+ return wrapRecursive(rawText);
+}
+
+function wrapRecursive(rawText) {
+ const mdNode = parseMd(rawText);
+
+ const link = find(mdNode, { type: 'link' });
+
+ if (link) {
+ const url = correctUrl(link.url);
+ const pos = rawText.indexOf(url);
+ const head = rawText.slice(0, pos);
+ const tail = rawText.slice(pos + url.length);
+ return [text(head), h('code', url)].concat(wrapRecursive(tail));
+ } else {
+ return [text(rawText)];
+ }
+}
+
+// remark-parse is overly eager when it comes to urls, this works around that.
+function correctUrl(url) {
+ var match = url.match(/"|'|!/);
+ if (match) {
+ return url.split(match[0])[0];
+ } else {
+ return url;
+ }
+}
+
+function getParagraphs(node) {
+ // Splitting generates unwanted expty nodes.
+ if (node.value === '\n') {
+ return blankLine;
+ }
+
+ let paragraphs = node.value.split('\n');
+ // nothing to split
+ if (paragraphs.length <= 1) {
+ return node;
+ }
+
+ let children = paragraphs.reduce((acc, curr) => {
+ return acc.concat([{ type: 'text', value: curr }, blankLine]);
+ }, []);
+
+ children = children.filter(({ value }) => value !== '');
+
+ // Remove the trailing newLine.
+ children.pop();
+ return children;
+}
+
+function sectionFromTemplate(section, sectionContent, closingTag) {
+ return (
+ `` +
+ '\n' +
+ sectionContent +
+ '\n' +
+ closingTag
+ );
+}
+
+function htmlVisitor(node) {
+ // 'html' nodes contain un-parsed html strings, so we first convert them
+ // to hast and then parse them to produce a syntax tree (so we can locate
+ // and modify the instructions and description)
+ const section = raw(toHast(node, { allowDangerousHtml: true }));
+ if (
+ section.type === 'element' &&
+ (section.properties.id === 'instructions' ||
+ section.properties.id === 'description') &&
+ !isEmpty(section.children)
+ ) {
+ const hasClosingTag = /<\/section>\s*$/.test(node.value);
+ // section contains the section tag and all the text up to the first
+ // blank line.
+
+ // This replaces single line breaks with empty lines, so
+ // that the section text that previously required special treatment
+ // becomes standard markdown.
+
+ // Has to start with an empty line
+ section.children.unshift(blankLine);
+
+ // break the lines into paragraphs
+ section.children = section.children.reduce(
+ (acc, child) =>
+ acc.concat(child.type === 'text' ? getParagraphs(child) : [child]),
+ []
+ );
+
+ // next we escape the text nodes, so that syntax like * doesn't start
+ // altering the formatting when it's interpretted as markdown
+
+ visit(section, (node, id, parent) => {
+ // no need to dive into non-phrasing nodes (once we're inside section)
+ // since they don't get parsed as markdown.
+ // An exception is made for 'big' because it is not considered to be
+ // phrasing, but can have markdown (that will be parsed!) inside it.
+ if (
+ node.tagName &&
+ node.tagName !== 'section' &&
+ node.tagName !== 'big' &&
+ !phrasing(node)
+ ) {
+ return visit.SKIP;
+ } else if (node.type === 'text') {
+ parent.children[id] = escapeMd(node);
+ return visit.CONTINUE;
+ } else {
+ return visit.CONTINUE;
+ }
+ });
+
+ // then wrap bare urls in code tags.
+ visit(section, 'text', (node, id, parent) => {
+ // skip if it's inside an anchor element
+ if (parent.tagName && parent.tagName === 'a') return visit.CONTINUE;
+ const wrapped = wrapBareUrls(node);
+ if (wrapped) {
+ parent.children.splice(id, 1, ...wrapped);
+ return id + wrapped.length;
+ } else {
+ return visit.CONTINUE;
+ }
+ });
+
+ // This can come from an unclosed , so we have to pretend it's
+ // a root element (otherwise it gets wrapped in a tag) and add the
+ // opening back in by hand.
+ const sectionContent = toHtml(
+ { type: 'root', children: section.children },
+ {
+ allowDangerousCharacters: true,
+ allowDangerousHtml: true,
+ quote: "'"
+ }
+ );
+
+ const closingTag = hasClosingTag ? ' \n' : '';
+
+ node.value = sectionFromTemplate(section, sectionContent, closingTag);
+ }
+
+ // If there is still a closing tag here, it should be seperated from the rest
+ // of the html, so that it will be parsed as a distinct html element. This
+ // will be important when we convert to mdx.
+ const hasClosingTag = /<\/section>\s*$/.test(node.value);
+
+ if (hasClosingTag) {
+ node.value = node.value.replace(/<\/section>\s*$/, '\n\n \n');
+ }
+}
+
+function plugin() {
+ return transformer;
+
+ function transformer(tree) {
+ return visit(tree, 'html', htmlVisitor);
+ }
+}
+
+exports.insertSpaces = plugin;
+exports.escapeMd = escapeMd;
+exports.getParagraphs = getParagraphs;
+exports.wrapBareUrls = wrapBareUrls;
+exports.correctUrl = correctUrl;
+exports.htmlVisitor = htmlVisitor;
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/insert-spaces.test.js b/tools/scripts/formatter/fcc-md-to-gfm/insert-spaces.test.js
new file mode 100644
index 0000000000..4525dc852d
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/insert-spaces.test.js
@@ -0,0 +1,313 @@
+/* global expect */
+
+const h = require('hastscript');
+const u = require('unist-builder');
+const toHtml = require('hast-util-to-html');
+
+const {
+ escapeMd,
+ getParagraphs,
+ htmlVisitor,
+ wrapBareUrls
+} = require('./insert-spaces');
+
+const blankLine = u('text', '\n\n');
+
+describe('insert-spaces', () => {
+ describe('htmlVisitor', () => {
+ it('should separate html elements into paragraphs', () => {
+ /* eslint-disable max-len*/
+ const twoStrong = {
+ type: 'html',
+ value:
+ "\nExample: \n1184 and 1210 are"
+ };
+ /* eslint-enable max-len*/
+ htmlVisitor(twoStrong);
+ expect(twoStrong.value).toMatch(/<\/strong>\n\n1184<\/strong>/);
+ });
+ });
+ describe('getParagraphs', () => {
+ it('should return a node unchanged if it has no newlines', () => {
+ const oneLine = { type: 'text', value: 'ab' };
+ expect(getParagraphs(oneLine)).toEqual(oneLine);
+ });
+ it('should split a text node at a newline', () => {
+ const twoLines = { type: 'text', value: 'a\nb' };
+ expect(getParagraphs(twoLines)).toHaveLength(3);
+ const threeLines = { type: 'text', value: 'a\nb\nc' };
+ expect(getParagraphs(threeLines)).toHaveLength(5);
+ });
+ it('should create blank lines to replace \\n', () => {
+ const twoLines = { type: 'text', value: 'a\nb' };
+ const expected = [
+ { type: 'text', value: 'a' },
+ { type: 'text', value: '\n\n' },
+ { type: 'text', value: 'b' }
+ ];
+ expect(getParagraphs(twoLines)).toEqual(expected);
+ });
+ it('should replace a single \\n with a blank line', () => {
+ const newline = { type: 'text', value: '\n' };
+ const expected = { type: 'text', value: '\n\n' };
+ expect(getParagraphs(newline)).toEqual(expected);
+ });
+ it('should give a sentence starting \\n a starting blank line', () => {
+ const startingNewline = { type: 'text', value: '\na' };
+ const expected = [
+ { type: 'text', value: '\n\n' },
+ { type: 'text', value: 'a' }
+ ];
+ expect(getParagraphs(startingNewline)).toEqual(expected);
+ });
+ });
+
+ describe('escapeMd', () => {
+ it('should not add a trailing newline', () => {
+ const alreadyEscaped = { type: 'text', value: 'hi!' };
+ expect(escapeMd(alreadyEscaped)).toEqual(alreadyEscaped);
+ });
+ it('should not escape a double newline', () => {
+ // they're needed to separate the paragraphs
+ const newLine = { type: 'text', value: '\n\n' };
+ expect(escapeMd(newLine)).toEqual(newLine);
+ });
+
+ /* This would be nice, but I don't know how to do it */
+ // it('should preserve newlines', () => {
+ // const newLine = { type: 'text', value: ' before \n after ' };
+ // Object.freeze(newLine);
+ // expect(escapeMd(newLine)).toEqual(newLine);
+ // });
+
+ it('should not escape urls', () => {
+ const url = { type: 'text', value: 'https://www.example.com' };
+ expect(escapeMd(url)).toEqual(url);
+ });
+
+ it('should escape MathJax', () => {
+ const mathJax = { type: 'text', value: '$H_2(X) = -\\sum_{i=1}^n$' };
+ const mathJaxEscaped = {
+ type: 'text',
+ value: '$H_2(X) = -\\\\sum\\_{i=1}^n$'
+ };
+ expect(escapeMd(mathJax)).toEqual(mathJaxEscaped);
+ });
+
+ it('should escape slashes', () => {
+ const mathJax = {
+ type: 'text',
+ value: '$R(1)=1\\ ;\\ S(1)=2 \\\\R(n)=R(n-1)+S(n-1), \\quad n>1.$'
+ };
+ const mathJaxEscaped = {
+ type: 'text',
+ value:
+ '$R(1)=1\\\\ ;\\\\ S(1)=2 \\\\\\\\R(n)=R(n-1)+S(n-1), \\\\quad n>1.$'
+ };
+ expect(escapeMd(mathJax)).toEqual(mathJaxEscaped);
+ });
+ });
+
+ describe('wrapBareUrls', () => {
+ it('should skip blank line nodes', () => {
+ expect(wrapBareUrls(blankLine)).toEqual(null);
+ });
+
+ it('should not modify nodes without bare urls', () => {
+ const noBareUrls = u('text', 'Just some words.');
+ const expected = toHtml(h('', 'Just some words.'));
+ const actualHast = h('');
+ actualHast.children = wrapBareUrls(noBareUrls);
+ expect(toHtml(actualHast)).toEqual(expected);
+ });
+
+ it('should not trim whitespace', () => {
+ const noBareUrls = u('text', ' \n Just some words. ');
+ const expected = toHtml(h('', ' \n Just some words. '));
+ const actualHast = h('');
+ actualHast.children = wrapBareUrls(noBareUrls);
+ expect(toHtml(actualHast)).toEqual(expected);
+ });
+
+ it('should handle !', () => {
+ const exclamation = u('text', 'Just < : > near https://example.com!?');
+ const childrenExclamation = wrapBareUrls(exclamation);
+ const actualHast = h('');
+ actualHast.children = childrenExclamation;
+ const expected = toHtml(
+ h('', ['Just < : > near ', h('code', 'https://example.com'), '!?'])
+ );
+ expect(toHtml(actualHast)).toEqual(expected);
+ });
+
+ it('should not parse any markdown', () => {
+ const noBareUrls = u('text', 'Just *some* words.');
+ const childrenNoBare = wrapBareUrls(noBareUrls);
+ const actualHast = h('');
+ actualHast.children = childrenNoBare;
+ const expected = toHtml(h('', 'Just *some* words.'));
+ expect(toHtml(actualHast)).toEqual(expected);
+ });
+
+ it('should replace bare urls with code elements', () => {
+ const urlBare = u('text', 'a https://example.com b');
+ const childrenBare = wrapBareUrls(urlBare);
+ const actualHast = h('');
+ actualHast.children = childrenBare;
+ const expected = toHtml(
+ h('', ['a ', h('code', 'https://example.com'), ' b'])
+ );
+ expect(toHtml(actualHast)).toEqual(expected);
+ });
+
+ it('should replace url strings with code elements', () => {
+ const urlBare = u('text', 'https://example.com');
+ const childrenBare = wrapBareUrls(urlBare);
+ const actualHast = h('');
+ actualHast.children = childrenBare;
+ const expected = toHtml(h('', [h('code', 'https://example.com')]));
+ expect(toHtml(actualHast)).toEqual(expected);
+ });
+
+ it('should replace two bare urls with two code elements', () => {
+ const urlBare = u(
+ 'text',
+ 'a https://example.com text https://sample-site.com b'
+ );
+ const childrenBare = wrapBareUrls(urlBare);
+ const actualHast = h('');
+ actualHast.children = childrenBare;
+ const expected = toHtml(
+ h('', [
+ 'a ',
+ h('code', 'https://example.com'),
+ ' text ',
+ h('code', 'https://sample-site.com'),
+ ' b'
+ ])
+ );
+ expect(toHtml(actualHast)).toEqual(expected);
+ });
+
+ it('should replace two identical urls with two code elements', () => {
+ const urlBare = u(
+ 'text',
+ 'a https://example.com text https://example.com b'
+ );
+ const childrenBare = wrapBareUrls(urlBare);
+ const actualHast = h('');
+ actualHast.children = childrenBare;
+ const expected = toHtml(
+ h('', [
+ 'a ',
+ h('code', 'https://example.com'),
+ ' text ',
+ h('code', 'https://example.com'),
+ ' b'
+ ])
+ );
+ expect(toHtml(actualHast)).toEqual(expected);
+ });
+
+ it('should replace quoted bare urls with code elements', () => {
+ const urlQuoted = {
+ type: 'text',
+ value: 'a "https://example.com" b'
+ };
+ const childrenQuoted = wrapBareUrls(urlQuoted);
+ const actualQuoted = h('');
+ actualQuoted.children = childrenQuoted;
+ const expectedQuoted = toHtml(
+ h('', ['a "', h('code', 'https://example.com'), '" b'])
+ );
+ expect(toHtml(actualQuoted)).toEqual(expectedQuoted);
+ });
+
+ it('should replace single quoted bare urls with code elements', () => {
+ const urlQuoted = {
+ type: 'text',
+ value: `a 'https://example.com' b`
+ };
+ const childrenQuoted = wrapBareUrls(urlQuoted);
+ const actualQuoted = h('');
+ actualQuoted.children = childrenQuoted;
+ const expectedQuoted = toHtml(
+ h('', [`a '`, h('code', 'https://example.com'), `' b`])
+ );
+ expect(toHtml(actualQuoted)).toEqual(expectedQuoted);
+ });
+
+ // NOTE: this is a remark-parse bug that the formatter works around
+ it(`should replace quoted bare urls before '.' with code elements`, () => {
+ const urlQuoted = {
+ type: 'text',
+ value: '"http://example.com".'
+ };
+ const childrenQuoted = wrapBareUrls(urlQuoted);
+ const actualQuoted = h('');
+ actualQuoted.children = childrenQuoted;
+ const expectedQuoted = toHtml(
+ h('', ['"', h('code', 'http://example.com'), '".'])
+ );
+ expect(toHtml(actualQuoted)).toEqual(expectedQuoted);
+ });
+ // NOTE: this is a remark-parse bug that the formatter works around
+ it(`should replace single-quoted bare urls before '.' with code elements`, () => {
+ const urlQuoted = {
+ type: 'text',
+ value: "'http://example.com'."
+ };
+ const childrenQuoted = wrapBareUrls(urlQuoted);
+ const actualQuoted = h('');
+ actualQuoted.children = childrenQuoted;
+ const expectedQuoted = toHtml(
+ h('', ["'", h('code', 'http://example.com'), "'."])
+ );
+ expect(toHtml(actualQuoted)).toEqual(expectedQuoted);
+ });
+ // NOTE: this is a remark-parse bug that the formatter works around
+ it(`should replace quoted bare urls before '>' with code elements`, () => {
+ const urlQuoted = {
+ type: 'text',
+ value: '"http://example.com">this '
+ };
+ const childrenQuoted = wrapBareUrls(urlQuoted);
+ const actualQuoted = h('');
+ actualQuoted.children = childrenQuoted;
+ const expectedQuoted = toHtml(
+ h('', ['"', h('code', 'http://example.com'), '">this '])
+ );
+ expect(toHtml(actualQuoted)).toEqual(expectedQuoted);
+ });
+
+ // NOTE: this is a remark-parse bug that the formatter works around
+ it(`really should replace quoted bare urls before '>' with code elements`, () => {
+ const urlQuoted = {
+ type: 'text',
+ value: '"http://example.com">'
+ };
+ const childrenQuoted = wrapBareUrls(urlQuoted);
+ const actualQuoted = h('');
+ actualQuoted.children = childrenQuoted;
+ const expectedQuoted = toHtml(
+ h('', ['"', h('code', 'http://example.com'), '">'])
+ );
+ expect(toHtml(actualQuoted)).toEqual(expectedQuoted);
+ });
+
+ // NOTE: this is a remark-parse bug that the formatter works around
+ it(`should replace single-quoted bare urls before '>' with code elements`, () => {
+ const urlQuoted = {
+ type: 'text',
+ value: `'http://example.com'>this `
+ };
+ const childrenQuoted = wrapBareUrls(urlQuoted);
+ const actualQuoted = h('');
+ actualQuoted.children = childrenQuoted;
+ const expectedQuoted = toHtml(
+ h('', ["'", h('code', 'http://example.com'), "'>this "])
+ );
+ expect(toHtml(actualQuoted)).toEqual(expectedQuoted);
+ });
+ });
+});
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/package-lock.json b/tools/scripts/formatter/fcc-md-to-gfm/package-lock.json
new file mode 100644
index 0000000000..f72cc47501
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/package-lock.json
@@ -0,0 +1,2087 @@
+{
+ "name": "fcc-md-to-gfm",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@types/hast": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.1.tgz",
+ "integrity": "sha512-viwwrB+6xGzw+G1eWpF9geV3fnsDgXqHG+cqgiHrvQfDUW5hzhCyV7Sy3UJxhfRFBsgky2SSW33qi/YrIkjX5Q==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "*"
+ }
+ },
+ "@types/mdast": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.3.tgz",
+ "integrity": "sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "*"
+ }
+ },
+ "@types/parse5": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz",
+ "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==",
+ "dev": true
+ },
+ "@types/unist": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz",
+ "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==",
+ "dev": true
+ },
+ "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-iterate": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-1.1.4.tgz",
+ "integrity": "sha512-sNRaPGh9nnmdC8Zf+pT3UqP8rnWj5Hf9wiFGsX3wUQ2yVSIhO2ShFwCoceIPpB41QF6i2OEmrHmCo36xronCVA==",
+ "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
+ },
+ "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
+ },
+ "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
+ },
+ "bail": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
+ "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==",
+ "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"
+ }
+ }
+ }
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "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"
+ }
+ },
+ "ccount": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.5.tgz",
+ "integrity": "sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw==",
+ "dev": true
+ },
+ "character-entities": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
+ "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
+ "dev": true
+ },
+ "character-entities-html4": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz",
+ "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==",
+ "dev": true
+ },
+ "character-entities-legacy": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
+ "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
+ "dev": true
+ },
+ "character-reference-invalid": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
+ "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
+ "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"
+ }
+ }
+ }
+ },
+ "collapse-white-space": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz",
+ "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==",
+ "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"
+ }
+ },
+ "comma-separated-tokens": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz",
+ "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==",
+ "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
+ },
+ "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-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "dbly-linked-list": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/dbly-linked-list/-/dbly-linked-list-0.2.0.tgz",
+ "integrity": "sha512-Ool7y15f6JRDs0YKx7Dh9uiTb1jS1SZLNdT3Y2q16DlaEghXbMsmODS/XittjR2xztt1gJUpz7jVxpqAPF8VGg==",
+ "dev": true,
+ "requires": {
+ "lodash.isequal": "^4.5.0"
+ }
+ },
+ "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"
+ }
+ },
+ "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=",
+ "dev": true
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "eventemitter3": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
+ "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==",
+ "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"
+ }
+ }
+ }
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "fault": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz",
+ "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==",
+ "dev": true,
+ "requires": {
+ "format": "^0.2.0"
+ }
+ },
+ "fifo": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/fifo/-/fifo-2.3.0.tgz",
+ "integrity": "sha1-GC3o3QYyqkfPaBbZvEMjMX1SWdw=",
+ "dev": true
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "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"
+ }
+ }
+ }
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true
+ },
+ "format": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz",
+ "integrity": "sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+ "dev": true
+ },
+ "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==",
+ "dev": true
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "dev": true,
+ "requires": {
+ "get-value": "^2.0.6",
+ "has-values": "^1.0.0",
+ "isobject": "^3.0.0"
+ }
+ },
+ "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": {
+ "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
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "hast-to-hyperscript": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.0.tgz",
+ "integrity": "sha512-NJvMYU3GlMLs7hN3CRbsNlMzusVNkYBogVWDGybsuuVQ336gFLiD+q9qtFZT2meSHzln3pNISZWTASWothMSMg==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.3",
+ "comma-separated-tokens": "^1.0.0",
+ "property-information": "^5.3.0",
+ "space-separated-tokens": "^1.0.0",
+ "style-to-object": "^0.3.0",
+ "unist-util-is": "^4.0.0",
+ "web-namespaces": "^1.0.0"
+ }
+ },
+ "hast-util-embedded": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/hast-util-embedded/-/hast-util-embedded-1.0.5.tgz",
+ "integrity": "sha512-0FfLHmfArWOizbdwjL+Rc9QIBzqP80juicNl4S4NEPq5OYWBCgYrtYDPUDoSyQQ9IQlBn9W7++fpYQNzZSq/wQ==",
+ "dev": true,
+ "requires": {
+ "hast-util-is-element": "^1.0.0"
+ }
+ },
+ "hast-util-from-parse5": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-6.0.0.tgz",
+ "integrity": "sha512-3ZYnfKenbbkhhNdmOQqgH10vnvPivTdsOJCri+APn0Kty+nRkDHArnaX9Hiaf8H+Ig+vkNptL+SRY/6RwWJk1Q==",
+ "dev": true,
+ "requires": {
+ "@types/parse5": "^5.0.0",
+ "ccount": "^1.0.0",
+ "hastscript": "^5.0.0",
+ "property-information": "^5.0.0",
+ "vfile": "^4.0.0",
+ "web-namespaces": "^1.0.0"
+ },
+ "dependencies": {
+ "hastscript": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-5.1.2.tgz",
+ "integrity": "sha512-WlztFuK+Lrvi3EggsqOkQ52rKbxkXL3RwB6t5lwoa8QLMemoWfBuL43eDrwOamJyR7uKQKdmKYaBH1NZBiIRrQ==",
+ "dev": true,
+ "requires": {
+ "comma-separated-tokens": "^1.0.0",
+ "hast-util-parse-selector": "^2.0.0",
+ "property-information": "^5.0.0",
+ "space-separated-tokens": "^1.0.0"
+ }
+ }
+ }
+ },
+ "hast-util-has-property": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-1.0.4.tgz",
+ "integrity": "sha512-ghHup2voGfgFoHMGnaLHOjbYFACKrRh9KFttdCzMCbFoBMJXiNi2+XTrPP8+q6cDJM/RSqlCfVWrjp1H201rZg==",
+ "dev": true
+ },
+ "hast-util-is-body-ok-link": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/hast-util-is-body-ok-link/-/hast-util-is-body-ok-link-1.0.4.tgz",
+ "integrity": "sha512-mFblNpLvFbD8dG2Nw5dJBYZkxIHeph1JAh5yr4huI7T5m8cV0zaXNiqzKPX/JdjA+tIDF7c33u9cxK132KRjyQ==",
+ "dev": true,
+ "requires": {
+ "hast-util-has-property": "^1.0.0",
+ "hast-util-is-element": "^1.0.0"
+ }
+ },
+ "hast-util-is-element": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.1.0.tgz",
+ "integrity": "sha512-oUmNua0bFbdrD/ELDSSEadRVtWZOf3iF6Lbv81naqsIV99RnSCieTbWuWCY8BAeEfKJTKl0gRdokv+dELutHGQ==",
+ "dev": true
+ },
+ "hast-util-parse-selector": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.4.tgz",
+ "integrity": "sha512-gW3sxfynIvZApL4L07wryYF4+C9VvH3AUi7LAnVXV4MneGEgwOByXvFo18BgmTWnm7oHAe874jKbIB1YhHSIzA==",
+ "dev": true
+ },
+ "hast-util-phrasing": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/hast-util-phrasing/-/hast-util-phrasing-1.0.5.tgz",
+ "integrity": "sha512-P3uxm+8bnwcfAS/XpGie9wMmQXAQqsYhgQQKRwmWH/V6chiq0lmTy8KjQRJmYjusdMtNKGCUksdILSZy1suSpQ==",
+ "dev": true,
+ "requires": {
+ "hast-util-embedded": "^1.0.0",
+ "hast-util-has-property": "^1.0.0",
+ "hast-util-is-body-ok-link": "^1.0.0",
+ "hast-util-is-element": "^1.0.0"
+ }
+ },
+ "hast-util-raw": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-6.0.1.tgz",
+ "integrity": "sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==",
+ "dev": true,
+ "requires": {
+ "@types/hast": "^2.0.0",
+ "hast-util-from-parse5": "^6.0.0",
+ "hast-util-to-parse5": "^6.0.0",
+ "html-void-elements": "^1.0.0",
+ "parse5": "^6.0.0",
+ "unist-util-position": "^3.0.0",
+ "vfile": "^4.0.0",
+ "web-namespaces": "^1.0.0",
+ "xtend": "^4.0.0",
+ "zwitch": "^1.0.0"
+ }
+ },
+ "hast-util-to-html": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-7.1.1.tgz",
+ "integrity": "sha512-Ujqj0hGuo3dIQKilkbauAv5teOqPvhaSLEgs1lgApFT0812e114KiffV8XfE4ttR8dRPqxNOIJOMu6SKOVOGlg==",
+ "dev": true,
+ "requires": {
+ "ccount": "^1.0.0",
+ "comma-separated-tokens": "^1.0.0",
+ "hast-util-is-element": "^1.0.0",
+ "hast-util-whitespace": "^1.0.0",
+ "html-void-elements": "^1.0.0",
+ "property-information": "^5.0.0",
+ "space-separated-tokens": "^1.0.0",
+ "stringify-entities": "^3.0.1",
+ "unist-util-is": "^4.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "hast-util-to-mdast": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/hast-util-to-mdast/-/hast-util-to-mdast-6.0.0.tgz",
+ "integrity": "sha512-DqG5A0QCi/VACAa9W35aiR0bA1fwYpLgo5IYG6KOQ6v0moT0YhM/JoX25JTmsoyGVy+NC37082shcLefFCL5qA==",
+ "dev": true,
+ "requires": {
+ "extend": "^3.0.2",
+ "hast-util-has-property": "^1.0.0",
+ "hast-util-is-element": "^1.0.0",
+ "hast-util-to-text": "^1.0.0",
+ "mdast-util-phrasing": "^1.0.0",
+ "mdast-util-to-string": "^1.0.4",
+ "rehype-minify-whitespace": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "trim-trailing-lines": "^1.1.0",
+ "unist-util-visit": "^2.0.0",
+ "xtend": "^4.0.1"
+ }
+ },
+ "hast-util-to-parse5": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz",
+ "integrity": "sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==",
+ "dev": true,
+ "requires": {
+ "hast-to-hyperscript": "^9.0.0",
+ "property-information": "^5.0.0",
+ "web-namespaces": "^1.0.0",
+ "xtend": "^4.0.0",
+ "zwitch": "^1.0.0"
+ }
+ },
+ "hast-util-to-text": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-1.0.1.tgz",
+ "integrity": "sha512-Xvp9fWiWVb4WaHc1E1g6dtyYlcVwyjRT0CC9oXtVUNhbmIB1gqRVBuBIFJgrFkYxdo+T3UIl5i5ipPGaPRnUOw==",
+ "dev": true,
+ "requires": {
+ "hast-util-is-element": "^1.0.2",
+ "repeat-string": "^1.6.1",
+ "unist-util-find-after": "^2.0.3"
+ }
+ },
+ "hast-util-whitespace": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz",
+ "integrity": "sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A==",
+ "dev": true
+ },
+ "hastscript": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz",
+ "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==",
+ "dev": true,
+ "requires": {
+ "@types/hast": "^2.0.0",
+ "comma-separated-tokens": "^1.0.0",
+ "hast-util-parse-selector": "^2.0.0",
+ "property-information": "^5.0.0",
+ "space-separated-tokens": "^1.0.0"
+ }
+ },
+ "html-void-elements": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz",
+ "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==",
+ "dev": true
+ },
+ "html-whitespace-sensitive-tag-names": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/html-whitespace-sensitive-tag-names/-/html-whitespace-sensitive-tag-names-1.0.3.tgz",
+ "integrity": "sha512-GX1UguduCBEAEo1hjFxc2Bz04/sDq0ACNyT7LsuoDcPfXYI3nS0NRPp3dyazLJyVUMp3GPBB56i/0Zr6CqD2PQ==",
+ "dev": true
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "inline-style-parser": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz",
+ "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==",
+ "dev": true
+ },
+ "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": {
+ "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
+ },
+ "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-alphabetical": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
+ "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
+ "dev": true
+ },
+ "is-alphanumeric": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz",
+ "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=",
+ "dev": true
+ },
+ "is-alphanumerical": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
+ "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
+ "dev": true,
+ "requires": {
+ "is-alphabetical": "^1.0.0",
+ "is-decimal": "^1.0.0"
+ }
+ },
+ "is-buffer": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
+ "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==",
+ "dev": true
+ },
+ "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": {
+ "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
+ },
+ "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-decimal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
+ "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
+ "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-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+ "dev": true
+ },
+ "is-hexadecimal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
+ "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
+ "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": {
+ "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
+ },
+ "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-plain-obj": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "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-whitespace-character": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz",
+ "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==",
+ "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-word-character": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz",
+ "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==",
+ "dev": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "isflattenable": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/isflattenable/-/isflattenable-1.1.0.tgz",
+ "integrity": "sha512-qr/kk8a8KmevVz0Sp899TdSAHg9ybc1HnFlFq/3ZW9G4a5IQsHz5fVnmq0poFMpCqI9wLPHSH9cCT2R1ctXoIQ==",
+ "dev": true,
+ "requires": {
+ "lodash.isarguments": "^3.1.0",
+ "lodash.isarray": "^3.0.4"
+ }
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "join-deep": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/join-deep/-/join-deep-1.2.1.tgz",
+ "integrity": "sha512-z1rVo21SUcDXtgWvToo8O2RfuMy6/ScnEWzyvVRRGYdWMrLqT0iGw/jkHxZ4BaBJGzTQxYhi0ZonsHlU+oJ8iw==",
+ "dev": true,
+ "requires": {
+ "reduce-deep": "^1.3.1"
+ }
+ },
+ "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
+ },
+ "lodash": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+ "dev": true
+ },
+ "lodash.isarguments": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
+ "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=",
+ "dev": true
+ },
+ "lodash.isarray": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
+ "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=",
+ "dev": true
+ },
+ "lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=",
+ "dev": true
+ },
+ "lodash.iteratee": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.iteratee/-/lodash.iteratee-4.7.0.tgz",
+ "integrity": "sha1-vkF32yiajMw8CZDx2ya1si/BVUw=",
+ "dev": true
+ },
+ "longest-streak": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz",
+ "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "markdown-escapes": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz",
+ "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==",
+ "dev": true
+ },
+ "markdown-table": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz",
+ "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==",
+ "dev": true,
+ "requires": {
+ "repeat-string": "^1.0.0"
+ }
+ },
+ "mdast-builder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/mdast-builder/-/mdast-builder-1.1.1.tgz",
+ "integrity": "sha512-a3KBk/LmYD6wKsWi8WJrGU/rXR4yuF4Men0JO0z6dSZCm5FrXXWTRDjqK0vGSqa+1M6p9edeuypZAZAzSehTUw==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.3"
+ }
+ },
+ "mdast-util-compact": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-2.0.1.tgz",
+ "integrity": "sha512-7GlnT24gEwDrdAwEHrU4Vv5lLWrEer4KOkAiKT9nYstsTad7Oc1TwqT2zIMKRdZF7cTuaf+GA1E4Kv7jJh8mPA==",
+ "dev": true,
+ "requires": {
+ "unist-util-visit": "^2.0.0"
+ }
+ },
+ "mdast-util-definitions": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz",
+ "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==",
+ "dev": true,
+ "requires": {
+ "unist-util-visit": "^2.0.0"
+ }
+ },
+ "mdast-util-phrasing": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-1.0.3.tgz",
+ "integrity": "sha512-b1Ar28MjmPMMnTDUApnL1AUJY1L/KmBg5+iBLMd8/+0JqXh1sENow9+wj8Mp/SZBYtMlGRUQ1PkBWinPEDVeNQ==",
+ "dev": true,
+ "requires": {
+ "unist-util-is": "^3.0.0"
+ },
+ "dependencies": {
+ "unist-util-is": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz",
+ "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==",
+ "dev": true
+ }
+ }
+ },
+ "mdast-util-to-hast": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-10.0.0.tgz",
+ "integrity": "sha512-dRyAC5S4eDcIOdkz4jg0wXbUdlf+5YFu7KppJNHOsMaD7ql5bKIqVcvXYYkcrKjzUkfX8JsKFVMthsU8OWxQ+w==",
+ "dev": true,
+ "requires": {
+ "@types/mdast": "^3.0.0",
+ "@types/unist": "^2.0.0",
+ "mdast-util-definitions": "^4.0.0",
+ "mdurl": "^1.0.0",
+ "unist-builder": "^2.0.0",
+ "unist-util-generated": "^1.0.0",
+ "unist-util-position": "^3.0.0",
+ "unist-util-visit": "^2.0.0"
+ }
+ },
+ "mdast-util-to-string": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz",
+ "integrity": "sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==",
+ "dev": true
+ },
+ "mdurl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+ "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
+ "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"
+ }
+ },
+ "mixin-deep": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+ "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+ "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"
+ }
+ }
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "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"
+ }
+ },
+ "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"
+ }
+ },
+ "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
+ },
+ "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-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.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "parse-entities": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
+ "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
+ "dev": true,
+ "requires": {
+ "character-entities": "^1.0.0",
+ "character-entities-legacy": "^1.0.0",
+ "character-reference-invalid": "^1.0.0",
+ "is-alphanumerical": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-hexadecimal": "^1.0.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
+ },
+ "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
+ },
+ "process-nextick-args": {
+ "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
+ },
+ "property-information": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz",
+ "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==",
+ "dev": true,
+ "requires": {
+ "xtend": "^4.0.0"
+ }
+ },
+ "queue-cb": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/queue-cb/-/queue-cb-1.1.5.tgz",
+ "integrity": "sha512-PKsogFZgSyIYn9hFD401ul8RWJnTtdUw+owgvWwhcevsYwY/UvJIeIziibB61CLp7/wry5EWLHmXzjeXr441Nw==",
+ "dev": true,
+ "requires": {
+ "fifo": "^2.3.0"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "readdirp-walk": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/readdirp-walk/-/readdirp-walk-1.7.0.tgz",
+ "integrity": "sha512-tGAXcAlxTM2I8SfOUniI/43eienxkywW5NuN3Ov1Qpngjnw8l1LcjSTBc6QwOpv9D0MTdPHb/wmPVKExbuYa0g==",
+ "dev": true,
+ "requires": {
+ "eventemitter3": "^3.1.0",
+ "graceful-fs": "^4.1.11",
+ "micromatch": "^3.1.10",
+ "readable-stream": "^2.0.2",
+ "walk-filtered": "^1.13.0"
+ }
+ },
+ "reduce-deep": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/reduce-deep/-/reduce-deep-1.3.1.tgz",
+ "integrity": "sha512-UJuIfS1er7MwsTQ5fkjgGo2gwM3WynmCg7VJLv/RqIU8xtCqrkFC922tWyD1dxeA+lC5pyUZi6JdIUKI6UubsA==",
+ "dev": true,
+ "requires": {
+ "isflattenable": "^1.1.0"
+ }
+ },
+ "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"
+ }
+ },
+ "rehype-minify-whitespace": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/rehype-minify-whitespace/-/rehype-minify-whitespace-3.0.0.tgz",
+ "integrity": "sha512-Z5NIG9FxTeK2Ta+eTWCnTVPXu1qC58eCXZA3m/Z7PPinKw82KSR+12c2l1sLLSg27QZOmZrrd9piS8dsAVfliQ==",
+ "dev": true,
+ "requires": {
+ "collapse-white-space": "^1.0.0",
+ "hast-util-embedded": "^1.0.0",
+ "hast-util-has-property": "^1.0.0",
+ "hast-util-is-body-ok-link": "^1.0.0",
+ "hast-util-is-element": "^1.0.0",
+ "html-whitespace-sensitive-tag-names": "^1.0.0",
+ "unist-util-is": "^4.0.0",
+ "unist-util-modify-children": "^1.0.0"
+ }
+ },
+ "remark-frontmatter": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-2.0.0.tgz",
+ "integrity": "sha512-uNOQt4tO14qBFWXenF0MLC4cqo3dv8qiHPGyjCl1rwOT0LomSHpcElbjjVh5CwzElInB38HD8aSRVugKQjeyHA==",
+ "dev": true,
+ "requires": {
+ "fault": "^1.0.1"
+ }
+ },
+ "remark-parse": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz",
+ "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==",
+ "dev": true,
+ "requires": {
+ "ccount": "^1.0.0",
+ "collapse-white-space": "^1.0.2",
+ "is-alphabetical": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-whitespace-character": "^1.0.0",
+ "is-word-character": "^1.0.0",
+ "markdown-escapes": "^1.0.0",
+ "parse-entities": "^2.0.0",
+ "repeat-string": "^1.5.4",
+ "state-toggle": "^1.0.0",
+ "trim": "0.0.1",
+ "trim-trailing-lines": "^1.0.0",
+ "unherit": "^1.0.4",
+ "unist-util-remove-position": "^2.0.0",
+ "vfile-location": "^3.0.0",
+ "xtend": "^4.0.1"
+ }
+ },
+ "remark-stringify": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-8.1.1.tgz",
+ "integrity": "sha512-q4EyPZT3PcA3Eq7vPpT6bIdokXzFGp9i85igjmhRyXWmPs0Y6/d2FYwUNotKAWyLch7g0ASZJn/KHHcHZQ163A==",
+ "dev": true,
+ "requires": {
+ "ccount": "^1.0.0",
+ "is-alphanumeric": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-whitespace-character": "^1.0.0",
+ "longest-streak": "^2.0.1",
+ "markdown-escapes": "^1.0.0",
+ "markdown-table": "^2.0.0",
+ "mdast-util-compact": "^2.0.0",
+ "parse-entities": "^2.0.0",
+ "repeat-string": "^1.5.4",
+ "state-toggle": "^1.0.0",
+ "stringify-entities": "^3.0.0",
+ "unherit": "^1.0.4",
+ "xtend": "^4.0.1"
+ }
+ },
+ "repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+ "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
+ },
+ "replace-ext": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
+ "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
+ "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==",
+ "dev": true
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "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"
+ }
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "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": {
+ "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
+ },
+ "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"
+ }
+ },
+ "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=",
+ "dev": true
+ },
+ "space-separated-tokens": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz",
+ "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==",
+ "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"
+ }
+ },
+ "stack-lifo": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/stack-lifo/-/stack-lifo-0.1.6.tgz",
+ "integrity": "sha512-fNXXK6AHbOIExOtJYPb1RlP8OXQr8tlpDNP5I78ZId9uK+MDCcDAkwGWTDACYLXAwOhaKLTYwkoSOihAt+/cLg==",
+ "dev": true,
+ "requires": {
+ "dbly-linked-list": "0.2.0"
+ }
+ },
+ "state-toggle": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz",
+ "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==",
+ "dev": true
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "stringify-entities": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-3.1.0.tgz",
+ "integrity": "sha512-3FP+jGMmMV/ffZs86MoghGqAoqXAdxLrJP4GUdrDN1aIScYih5tuIO3eF4To5AJZ79KDZ8Fpdy7QJnK8SsL1Vg==",
+ "dev": true,
+ "requires": {
+ "character-entities-html4": "^1.0.0",
+ "character-entities-legacy": "^1.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "style-to-object": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz",
+ "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==",
+ "dev": true,
+ "requires": {
+ "inline-style-parser": "0.1.1"
+ }
+ },
+ "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": {
+ "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
+ },
+ "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=",
+ "dev": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ }
+ },
+ "to-vfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-6.1.0.tgz",
+ "integrity": "sha512-BxX8EkCxOAZe+D/ToHdDsJcVI4HqQfmw0tCkp31zf3dNP/XWIAjU4CmeuSwsSoOzOTqHPOL0KUzyZqJplkD0Qw==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^2.0.0",
+ "vfile": "^4.0.0"
+ }
+ },
+ "trim": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
+ "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=",
+ "dev": true
+ },
+ "trim-trailing-lines": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz",
+ "integrity": "sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA==",
+ "dev": true
+ },
+ "trough": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
+ "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==",
+ "dev": true
+ },
+ "unherit": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz",
+ "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "unified": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz",
+ "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==",
+ "dev": true,
+ "requires": {
+ "bail": "^1.0.0",
+ "extend": "^3.0.0",
+ "is-buffer": "^2.0.0",
+ "is-plain-obj": "^2.0.0",
+ "trough": "^1.0.0",
+ "vfile": "^4.0.0"
+ }
+ },
+ "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"
+ }
+ },
+ "unist-builder": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz",
+ "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==",
+ "dev": true
+ },
+ "unist-util-find": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/unist-util-find/-/unist-util-find-1.0.2.tgz",
+ "integrity": "sha512-ft06UDYzqi9o9RmGP0sZWI/zvLLQiBW2/MD+rW6mDqbOWDcmknGX9orQPspfuGRYWr8eSJAmfsBcvOpfGRJseA==",
+ "dev": true,
+ "requires": {
+ "lodash.iteratee": "^4.5.0",
+ "unist-util-visit": "^1.1.0"
+ },
+ "dependencies": {
+ "unist-util-is": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz",
+ "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==",
+ "dev": true
+ },
+ "unist-util-visit": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz",
+ "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==",
+ "dev": true,
+ "requires": {
+ "unist-util-visit-parents": "^2.0.0"
+ }
+ },
+ "unist-util-visit-parents": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz",
+ "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==",
+ "dev": true,
+ "requires": {
+ "unist-util-is": "^3.0.0"
+ }
+ }
+ }
+ },
+ "unist-util-find-after": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-2.0.4.tgz",
+ "integrity": "sha512-zo0ShIr+E/aU9xSK7JC9Kb+WP9seTFCuqVYdo5+HJSjN009XMfhiA1FIExEKzdDP1UsgvKGleGlB/pSdTSqZww==",
+ "dev": true,
+ "requires": {
+ "unist-util-is": "^3.0.0"
+ },
+ "dependencies": {
+ "unist-util-is": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz",
+ "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==",
+ "dev": true
+ }
+ }
+ },
+ "unist-util-generated": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.5.tgz",
+ "integrity": "sha512-1TC+NxQa4N9pNdayCYA1EGUOCAO0Le3fVp7Jzns6lnua/mYgwHo0tz5WUAfrdpNch1RZLHc61VZ1SDgrtNXLSw==",
+ "dev": true
+ },
+ "unist-util-is": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.0.2.tgz",
+ "integrity": "sha512-Ofx8uf6haexJwI1gxWMGg6I/dLnF2yE+KibhD3/diOqY2TinLcqHXCV6OI5gFVn3xQqDH+u0M625pfKwIwgBKQ==",
+ "dev": true
+ },
+ "unist-util-modify-children": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-1.1.6.tgz",
+ "integrity": "sha512-TOA6W9QLil+BrHqIZNR4o6IA5QwGOveMbnQxnWYq+7EFORx9vz/CHrtzF36zWrW61E2UKw7sM1KPtIgeceVwXw==",
+ "dev": true,
+ "requires": {
+ "array-iterate": "^1.0.0"
+ }
+ },
+ "unist-util-position": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.1.0.tgz",
+ "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==",
+ "dev": true
+ },
+ "unist-util-remove-position": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz",
+ "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==",
+ "dev": true,
+ "requires": {
+ "unist-util-visit": "^2.0.0"
+ }
+ },
+ "unist-util-stringify-position": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
+ "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.2"
+ }
+ },
+ "unist-util-visit": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz",
+ "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "unist-util-is": "^4.0.0",
+ "unist-util-visit-parents": "^3.0.0"
+ }
+ },
+ "unist-util-visit-parents": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz",
+ "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "unist-util-is": "^4.0.0"
+ }
+ },
+ "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
+ }
+ }
+ },
+ "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
+ },
+ "vfile": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.0.tgz",
+ "integrity": "sha512-a/alcwCvtuc8OX92rqqo7PflxiCgXRFjdyoGVuYV+qbgCb0GgZJRvIgCD4+U/Kl1yhaRsaTwksF88xbPyGsgpw==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "is-buffer": "^2.0.0",
+ "replace-ext": "1.0.0",
+ "unist-util-stringify-position": "^2.0.0",
+ "vfile-message": "^2.0.0"
+ }
+ },
+ "vfile-location": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.1.0.tgz",
+ "integrity": "sha512-FCZ4AN9xMcjFIG1oGmZKo61PjwJHRVA+0/tPUP2ul4uIwjGGndIxavEMRpWn5p4xwm/ZsdXp9YNygf1ZyE4x8g==",
+ "dev": true
+ },
+ "vfile-message": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
+ "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "unist-util-stringify-position": "^2.0.0"
+ }
+ },
+ "walk-filtered": {
+ "version": "1.24.0",
+ "resolved": "https://registry.npmjs.org/walk-filtered/-/walk-filtered-1.24.0.tgz",
+ "integrity": "sha512-z4dwZ5IpNEfWVYEso60fsgrXpym65M+a03vumbnonJCrMll3H8JVy9xrU2RHpVGMr8rwlr5y+9qpr71h0RWdsA==",
+ "dev": true,
+ "requires": {
+ "join-deep": "^1.2.0",
+ "queue-cb": "^1.1.0",
+ "stack-lifo": "^0.1.6"
+ }
+ },
+ "web-namespaces": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz",
+ "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==",
+ "dev": true
+ },
+ "xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "dev": true
+ },
+ "zwitch": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz",
+ "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==",
+ "dev": true
+ }
+ }
+}
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/package.json b/tools/scripts/formatter/fcc-md-to-gfm/package.json
new file mode 100644
index 0000000000..63600d3479
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/package.json
@@ -0,0 +1,31 @@
+{
+ "name": "fcc-md-to-gfm",
+ "version": "1.0.0",
+ "description": "",
+ "main": "formatCurriculum.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "BSD-3-Clause",
+ "devDependencies": {
+ "hast-util-phrasing": "^1.0.5",
+ "hast-util-raw": "^6.0.1",
+ "hast-util-to-html": "^7.1.1",
+ "hast-util-to-mdast": "^6.0.0",
+ "hastscript": "^6.0.0",
+ "lodash": "^4.17.20",
+ "mdast-builder": "^1.1.1",
+ "mdast-util-to-hast": "^10.0.0",
+ "parse-entities": "^2.0.0",
+ "readdirp-walk": "^1.7.0",
+ "remark-frontmatter": "^2.0.0",
+ "remark-parse": "^8.0.3",
+ "remark-stringify": "^8.1.1",
+ "to-vfile": "^6.1.0",
+ "unified": "^9.2.0",
+ "unist-builder": "^2.0.3",
+ "unist-util-find": "^1.0.2",
+ "unist-util-visit": "^2.0.3"
+ }
+}
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/transformChallenges.js b/tools/scripts/formatter/fcc-md-to-gfm/transformChallenges.js
new file mode 100644
index 0000000000..f0f02a2460
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/transformChallenges.js
@@ -0,0 +1,57 @@
+const unified = require('unified');
+const vfile = require('to-vfile');
+const markdown = require('remark-parse');
+const frontmatter = require('remark-frontmatter');
+const stringify = require('remark-stringify');
+
+const { insertSpaces } = require('./insert-spaces');
+const codeToBackticks = require('./code-to-backticks');
+
+const insertSpacesProcessor = unified()
+ .use(markdown)
+ .use(insertSpaces)
+ .use(stringify, { fences: true, emphasis: '*' })
+ .use(frontmatter, ['yaml']);
+// ^ Prevents the frontmatter being modified
+
+const getCodeToBackticksProcessor = (shouldThrow, pre) =>
+ unified()
+ .use(markdown)
+ .use(codeToBackticks, { shouldThrow, pre })
+ .use(stringify, { fences: true, emphasis: '*' })
+ .use(frontmatter, ['yaml']);
+
+// Despite entities defaulting to false, some will still remain, including
+// <
+const prettifyProcessor = unified()
+ .use(markdown)
+ .use(stringify, { fences: true, emphasis: '*' })
+ .use(frontmatter, ['yaml']);
+
+exports.insertSpaces = createProcessor(insertSpacesProcessor);
+
+exports.codeToBackticks = createProcessor(getCodeToBackticksProcessor());
+exports.checkCodeToBackticks = createProcessor(
+ getCodeToBackticksProcessor(true)
+);
+
+exports.getCodeToBackticksSync = shouldThrow => text =>
+ getCodeToBackticksProcessor(shouldThrow, true).processSync(text);
+
+exports.prettify = createProcessor(prettifyProcessor);
+exports.prettifySync = prettifyProcessor.processSync;
+
+function createProcessor(processor) {
+ return (msg, isFile = false) => {
+ const fileOrText = isFile ? vfile.readSync(msg) : msg;
+ return new Promise((resolve, reject) =>
+ processor.process(fileOrText, function(err, file) {
+ if (err) {
+ err.message += ' in file ' + msg;
+ reject(err);
+ }
+ return resolve(file.contents);
+ })
+ );
+ };
+}
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/transformChallenges.test.js b/tools/scripts/formatter/fcc-md-to-gfm/transformChallenges.test.js
new file mode 100644
index 0000000000..e8158a5b3d
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/transformChallenges.test.js
@@ -0,0 +1,30 @@
+const { codeToBackticks } = require('./transformChallenges');
+
+/* global expect */
+
+describe('transformChallenges', () => {
+ describe('codeToBackticks', () => {
+ it('should convert to *', () => {
+ const expected = 'Some *emphasis* here\n';
+ return codeToBackticks('Some emphasis here').then(actual => {
+ expect(actual).toEqual(expected);
+ });
+ });
+ it('should convert to `', () => {
+ const expected = 'Code `code` test\n';
+ return codeToBackticks('Code code
test').then(actual => {
+ expect(actual).toEqual(expected);
+ });
+ });
+ it('should convert html entities', () => {
+ const expected =
+ 'a ` ` test\n';
+ return codeToBackticks(
+ // eslint-disable-next-line max-len
+ 'a <input type="text" placeholder="this is placeholder text">
test\n'
+ ).then(actual => {
+ expect(actual).toEqual(expected);
+ });
+ });
+ });
+});
diff --git a/tools/scripts/formatter/fcc-md-to-gfm/validate-text.js b/tools/scripts/formatter/fcc-md-to-gfm/validate-text.js
new file mode 100644
index 0000000000..b3208f4275
--- /dev/null
+++ b/tools/scripts/formatter/fcc-md-to-gfm/validate-text.js
@@ -0,0 +1,14 @@
+const { insertSpaces, checkCodeToBackticks } = require('./transformChallenges');
+const readDirP = require('readdirp-walk');
+
+const challengeDir = '../../../../curriculum/challenges/english';
+
+readDirP({ root: challengeDir, fileFilter: ['*.md'] }).on('data', file => {
+ if (file.stat.isFile()) {
+ insertSpaces(file.fullPath, true)
+ .then(checkCodeToBackticks)
+ .catch(() => {
+ console.log(file.path);
+ });
+ }
+});
diff --git a/tools/scripts/formatter/md-to-mdx/create-mdx.js b/tools/scripts/formatter/md-to-mdx/create-mdx.js
new file mode 100644
index 0000000000..9d33ba64ba
--- /dev/null
+++ b/tools/scripts/formatter/md-to-mdx/create-mdx.js
@@ -0,0 +1,440 @@
+const { isEmpty, pick } = require('lodash');
+const yaml = require('js-yaml');
+const he = require('he');
+const prettier = require('prettier');
+
+const prettierOptions = prettier.resolveConfig.sync();
+
+const {
+ getCodeToBackticksSync,
+ prettifySync
+} = require('../../formatter/fcc-md-to-gfm/transformChallenges');
+const { correctUrl } = require('../../formatter/fcc-md-to-gfm/insert-spaces');
+
+const codeToBackticksSync = getCodeToBackticksSync(true);
+const unified = require('unified');
+
+const remarkParse = require('remark-parse');
+const find = require('unist-util-find');
+const remark2rehype = require('remark-rehype');
+const html = require('rehype-stringify');
+const raw = require('rehype-raw');
+
+var parser = unified().use(remarkParse);
+var mdToHTML = unified()
+ .use(remarkParse)
+ .use(remark2rehype, { allowDangerousHtml: true })
+ .use(raw)
+ .use(html, { allowDangerousCharacters: true, allowDangerousHtml: true })
+ .processSync;
+
+function parseMd(text) {
+ return parser.parse(text);
+}
+
+// inspired by wrapRecursive, but takes in text and outputs text.
+function wrapUrls(rawText) {
+ const mdNode = parseMd(rawText);
+
+ const link = find(mdNode, { type: 'link' });
+
+ if (link) {
+ const url = correctUrl(link.url);
+ const pos = rawText.indexOf(url);
+ const head = rawText.slice(0, pos);
+ const tail = rawText.slice(pos + url.length);
+ const newText = head + '`' + url + '`' + wrapUrls(tail);
+ return newText;
+ } else {
+ return rawText;
+ }
+}
+
+const frontmatterProperties = [
+ 'id',
+ 'title',
+ 'challengeType',
+ 'videoId',
+ 'videoUrl',
+ 'forumTopicId',
+ 'isPrivate',
+ 'required',
+ 'helpCategory'
+];
+
+const otherProperties = [
+ 'description',
+ 'instructions',
+ 'tests',
+ 'solutions',
+ 'files',
+ 'question'
+];
+
+function createFrontmatter(data) {
+ Object.keys(data).forEach(key => {
+ if (!frontmatterProperties.includes(key) && !otherProperties.includes(key))
+ throw Error(`Unknown property '${key}'`);
+ });
+
+ // TODO: sort the keys? It doesn't matter from a machine perspective, but
+ // it does from human-readability one. We could get lucky and have the order
+ // be preserved accidentally.
+ const frontData = pick(data, frontmatterProperties);
+ const frontYAML = yaml.dump(frontData);
+
+ return `---
+${frontYAML}---
+
+`;
+}
+
+// TODO: handle certs elsewhere (ideally don't try to create mdx versions)
+function createHints({ tests, title }) {
+ if (!tests) return '';
+ const strTests = tests
+ .map(
+ ({ text, testString }) => `${hintToMd(text, title)}
+
+${'```js'}
+${
+ typeof testString === 'string'
+ ? prettier
+ .format(testString, { ...prettierOptions, parser: 'babel' })
+ .trim()
+ : ''
+}
+${'```'}
+`
+ )
+ .join('\n');
+ return `# --hints--
+
+${strTests}
+`;
+}
+
+function validateHints({ tests, question, title }) {
+ if (tests) {
+ tests.forEach(({ text }) => {
+ validateAndLog(text, title, false);
+ });
+ }
+ if (question && question.text) {
+ validateAndLog(question.text, title, false);
+ }
+ if (question && question.answers) {
+ question.answers.forEach(text => {
+ validateAndLog(text, title, false);
+ });
+ }
+}
+
+function validateAndLog(text, title, log = true) {
+ const { valid, parsed, parsedSimplified, finalHint } = validateText(text);
+ if (!valid) {
+ if (log) {
+ console.log('original'.padEnd(8, ' '), text);
+ console.log('parsed'.padEnd(8, ' '), parsed);
+ console.log('finalP'.padEnd(8, ' '), parsedSimplified);
+ console.log('finalT'.padEnd(8, ' '), finalHint);
+ }
+ throw Error(title);
+ }
+}
+
+function validateText(text) {
+ // hints can be empty; empty hints don't need validating.
+ if (!text) {
+ return { valid: true };
+ }
+
+ // the trailing \n will not affect the final html, so we can trim. At worst
+ // there will be difference between the two.
+ text = text.trim();
+
+ let parsed = mdToHTML(text).contents;
+
+ // parsed text is expected to get wrapped in p tags, so we remove them.
+ // NOTE: this is a bit zealous, but allowing any p tags generates a ton of
+ // false positives.
+ if (parsed.match(/^.*<\/p>$/s)) {
+ parsed = parsed.replace(/
/g, '').replace(/<\/p>/g, '');
+ } else if (parsed.match(/^
.*<\/p>\n
/)) {
+ parsed = parsed.match(/^(.*)<\/p>/s)[1];
+ text = text.match(/^(.*?)```/s)[1];
+ } else if (
+ parsed.match(/^
/) ||
+ parsed.match(/^stuff
+ // blah and we should be okay.
+
+ // throw Error(`Unexpected parse result ${parsed}`);
+ return { valid: true, parsed };
+ } else {
+ throw Error(`Unexpected parse result ${parsed}`);
+ }
+
+ if (text === parsed) {
+ return { valid: true, parsed };
+ }
+
+ // it's possible the hint contained ` not code tags, so we replace in both
+ // also trimming because we know whitespace is actually preserved by the mdx
+ // parser
+
+ let finalParsed = parsed.replace(//g, '`').replace(/<\/code>/g, '`');
+ let finalHint = text.replace(//g, '`').replace(/<\/code>/g, '`');
+
+ // I've verified that whitespace is preserved by formatting and that the mdx
+ // parser also preserves it when it should (i.e. inside ``). So, for
+ // simplicity, I'm collapsing it here.
+ finalParsed = finalParsed.replace(/\s+/g, '');
+ finalHint = finalHint.replace(/\s+/g, '');
+ // TODO: is this too lax? Just forcing them both to use the decoded
+ // characters.
+ finalParsed = he.decode(finalParsed);
+ finalHint = he.decode(finalHint);
+
+ return {
+ valid: finalHint === finalParsed,
+ parsed,
+ parsedSimplified: finalParsed,
+ finalHint
+ };
+}
+
+function hintToMd(hint, title) {
+ // we're only interested in `code` and want to avoid catching ```code```
+ const codeRE = /(? {
+ // prettify discards whitespace, which we generally want to keep.
+ if (text.match(/^\s*$/)) {
+ return text;
+ } else {
+ // bit of hack: we need to keep trailing newlines because they might be
+ // meaningful. prettifySync should respect them, but it's clearly being
+ // overzealous.
+ const leadingBreaks = text.match(/^\n*/)[0];
+ const rest = text.slice(leadingBreaks.length);
+ // prettify *also* adds a trailing \n which we generally don't want to
+ // keep
+ return leadingBreaks + prettifySync(rest).contents.slice(0, -1);
+ }
+ });
+
+ const code = [...wrappedUrls.matchAll(codeRE)].map(match => match[0]);
+ let newHint = [];
+ pretty.forEach((text, idx) => {
+ newHint.push(text);
+ if (typeof code[idx] !== 'undefined') {
+ newHint.push(code[idx]);
+ }
+ });
+ // depending on how the hint is represented in yaml, it can have extra \n
+ // chars at the end, so we should trim.
+ newHint = newHint.join('').trim();
+
+ return newHint;
+}
+
+function wrapCode(hint) {
+ if (typeof hint !== 'string') {
+ return '';
+ }
+ let mdHint;
+ function replacer(match, p1) {
+ // transform then remove the trailing \n
+ // Using pre is a dirty hack to make sure the whitespace is preserved
+ return codeToBackticksSync(`${p1} `).contents.slice(0, -1);
+ }
+ const codeRE = /(.*?)<\/code>/g;
+ // to avoid parsing the rest of the markdown we use codeToBackticksSync on the
+ // code inside the re. If it fails, the code could be complicated enough to
+ // fool the regex, so we log it for human validation.
+ try {
+ mdHint = hint.replace(codeRE, replacer);
+ } catch (err) {
+ // console.log('err', err);
+ // console.log(`${title} failed
+ // hint:
+ // ${hint}`);
+ mdHint = hint.replace(codeRE, '`$1`');
+ // console.log('produced:');
+ // console.log(mdHint);
+ // console.log();
+ }
+ return mdHint;
+}
+
+function createSolutions({ solutions }) {
+ if (!solutions) return '';
+ const solutionsStr = solutions.map(soln => solutionToText(soln)).join(`
+---
+
+`);
+ return `# --solutions--
+
+${solutionsStr}`;
+}
+
+function createQuestion({ question, title }) {
+ if (!question) return '';
+ const { text, answers, solution } = question;
+ return `# --question--
+
+## --text--
+
+${hintToMd(text, title)}
+
+## --answers--
+
+${answers.map(answer => hintToMd(answer, title)).join(`
+
+---
+
+`)}
+
+## --video-solution--
+
+${solution}
+
+`;
+}
+
+// files: {
+// indexhtml: {
+// key: 'indexhtml',
+// ext: 'html',
+// name: 'index',
+// contents: 'Hello \n',
+// head: '',
+// tail: '',
+// editableRegionBoundaries: []
+// }
+// }
+
+function createSeed({ files }) {
+ if (!files) return '';
+ const supportedLanguages = ['html', 'css', 'js', 'jsx'];
+ const supportedIndexes = supportedLanguages.map(lang => 'index' + lang);
+ Object.values(files).forEach(({ ext }) => {
+ if (!supportedLanguages.includes(ext)) throw `Unsupported language: ${ext}`;
+ });
+ Object.keys(files).forEach(index => {
+ if (!supportedIndexes.includes(index)) throw `Unsupported index: ${index}`;
+ });
+
+ const head = Object.values(files)
+ .filter(({ head }) => !isEmpty(head))
+ .map(({ ext, head }) => fenceCode(ext, head))
+ .join('\n');
+
+ const tail = Object.values(files)
+ .filter(({ tail }) => !isEmpty(tail))
+ .map(({ ext, tail }) => fenceCode(ext, tail))
+ .join('\n');
+
+ const contents = Object.values(files)
+ .map(({ ext, contents, editableRegionBoundaries }) =>
+ fenceCode(ext, insertMarkers(contents, editableRegionBoundaries))
+ )
+ .join('\n');
+
+ return (
+ `# --seed--
+
+` +
+ createSection('before-user-code', head, 2) +
+ createSection('after-user-code', tail, 2) +
+ createSection('seed-contents', contents, 2)
+ );
+}
+
+function insertMarkers(code, markers) {
+ const lines = code.split('\n');
+ return markers
+ .reduce((acc, idx) => {
+ return insert(acc, '--fcc-editable-region--', idx);
+ }, lines)
+ .join('\n');
+}
+
+function insert(xs, x, idx) {
+ return [...xs.slice(0, idx), x, ...xs.slice(idx)];
+}
+
+function solutionToText(solution) {
+ const supportedLanguages = ['html', 'css', 'js', 'jsx', 'py'];
+ const supportedIndexes = supportedLanguages.map(lang => 'index' + lang);
+ Object.values(solution).forEach(({ ext }) => {
+ if (!supportedLanguages.includes(ext)) throw `Unsupported language: ${ext}`;
+ });
+ Object.keys(solution).forEach(index => {
+ if (!supportedIndexes.includes(index)) throw `Unsupported index: ${index}`;
+ });
+
+ return Object.values(solution)
+ .map(({ ext, contents }) => fenceCode(ext, contents))
+ .join('\n');
+}
+
+// Even if there is no code, we should fence it in case the extension is used
+function fenceCode(ext, code) {
+ return `${'```' + ext}
+${code + '```'}
+`;
+}
+
+function createInstructions({ instructions }) {
+ return createSection('instructions', instructions);
+}
+
+function createDescription({ description }) {
+ return createSection('description', description);
+}
+
+function createSection(heading, contents, depth = 1) {
+ return contents && contents.trim()
+ ? `${''.padEnd(depth, '#')} --${heading}--
+
+${contents}
+`
+ : '';
+}
+
+function challengeToString(data) {
+ return (
+ createFrontmatter(data) +
+ createDescription(data) +
+ createInstructions(data) +
+ createQuestion(data) +
+ createHints(data) +
+ createSeed(data) +
+ createSolutions(data)
+ );
+}
+
+exports.challengeToString = challengeToString;
+exports.validateHints = validateHints;
+
+// console.log(exports.challengeToString(challengeData));
+// // exports.challengeToString(challengeData);
+
+// console.log(
+// hintToMd('ZigZagMatrix(2) should return [[0, 1], [2, 3]].', 'title')
+// );
+
+// console.log(hintToMd('lar@freecodecamp.org', 'title'));
diff --git a/tools/scripts/formatter/md-to-mdx/md-to-mdx.js b/tools/scripts/formatter/md-to-mdx/md-to-mdx.js
new file mode 100644
index 0000000000..c0b37dbda4
--- /dev/null
+++ b/tools/scripts/formatter/md-to-mdx/md-to-mdx.js
@@ -0,0 +1,28 @@
+const readDirP = require('readdirp-walk');
+const { getText } = require('./transform-to-mdx');
+const { challengeToString } = require('./create-mdx');
+const { parseMD } = require('../../../challenge-md-parser/mdx/index');
+const fs = require('fs');
+
+const challengeDir = '../../../../curriculum/challenges/chinese';
+
+readDirP({ root: challengeDir, fileFilter: ['*.md'] }).on('data', file => {
+ if (file.stat.isFile()) {
+ generateTranscribableChallenge(file.fullPath)
+ .then(challengeToString)
+ .then(text => fs.writeFileSync(file.fullPath + 'x', text))
+ .catch(err => {
+ console.log('Error transforming');
+ console.log(file.path);
+ console.log('mdx version not created.');
+ console.log(err);
+ });
+ }
+});
+
+function generateTranscribableChallenge(fullPath) {
+ return Promise.all([parseMD(fullPath), getText(fullPath)]).then(results => ({
+ ...results[0],
+ ...results[1]
+ }));
+}
diff --git a/tools/scripts/formatter/md-to-mdx/plugins/section-to-heading.js b/tools/scripts/formatter/md-to-mdx/plugins/section-to-heading.js
new file mode 100644
index 0000000000..22e49957fa
--- /dev/null
+++ b/tools/scripts/formatter/md-to-mdx/plugins/section-to-heading.js
@@ -0,0 +1,22 @@
+const visit = require('unist-util-visit');
+const is = require('unist-util-is');
+
+function plugin() {
+ return transformer;
+
+ function transformer(tree) {
+ visit(tree, 'heading', visitor);
+
+ // eslint-disable-next-line consistent-return
+ function visitor(node) {
+ if (node.children.length !== 1) throw 'Heading has too many children';
+ if (is(node.children[0], { type: 'text', value: 'Description' }))
+ return true;
+
+ if (is(node.children[0], { type: 'text', value: 'Instructions' }))
+ return true;
+ }
+ }
+}
+
+module.exports = plugin;
diff --git a/tools/scripts/formatter/md-to-mdx/plugins/tests-to-data.js b/tools/scripts/formatter/md-to-mdx/plugins/tests-to-data.js
new file mode 100644
index 0000000000..88f4d380a6
--- /dev/null
+++ b/tools/scripts/formatter/md-to-mdx/plugins/tests-to-data.js
@@ -0,0 +1,24 @@
+const visit = require('unist-util-visit');
+const YAML = require('js-yaml');
+
+function plugin() {
+ return transformer;
+
+ function transformer(tree, file) {
+ visit(tree, 'code', visitor);
+
+ function visitor(node) {
+ const { lang, value } = node;
+ if (lang === 'yml') {
+ const tests = YAML.load(value);
+
+ file.data = {
+ ...file.data,
+ ...tests
+ };
+ }
+ }
+ }
+}
+
+module.exports = plugin;
diff --git a/tools/scripts/formatter/md-to-mdx/plugins/text-to-data.js b/tools/scripts/formatter/md-to-mdx/plugins/text-to-data.js
new file mode 100644
index 0000000000..fa6b0b862e
--- /dev/null
+++ b/tools/scripts/formatter/md-to-mdx/plugins/text-to-data.js
@@ -0,0 +1,30 @@
+const stringify = require('remark-stringify');
+const { root } = require('mdast-builder');
+const unified = require('unified');
+const getAllBetween = require('../utils/get-all-between');
+
+const stringifyMd = nodes =>
+ unified()
+ .use(stringify, { fences: true, emphasis: '*' })
+ .stringify(root(nodes));
+
+function plugin() {
+ return transformer;
+
+ function transformer(tree, file) {
+ const descriptionNodes = getAllBetween(
+ tree,
+ { type: 'html', value: "" },
+ { type: 'html', value: ' ' }
+ );
+ file.data.description = stringifyMd(descriptionNodes);
+ const instructionsNodes = getAllBetween(
+ tree,
+ { type: 'html', value: "" },
+ { type: 'html', value: ' ' }
+ );
+ file.data.instructions = stringifyMd(instructionsNodes);
+ }
+}
+
+module.exports = plugin;
diff --git a/tools/scripts/formatter/md-to-mdx/transform-to-mdx.js b/tools/scripts/formatter/md-to-mdx/transform-to-mdx.js
new file mode 100644
index 0000000000..2ab8c62963
--- /dev/null
+++ b/tools/scripts/formatter/md-to-mdx/transform-to-mdx.js
@@ -0,0 +1,24 @@
+const unified = require('unified');
+const vfile = require('to-vfile');
+const markdown = require('remark-parse');
+const frontmatter = require('remark-frontmatter');
+
+const textToData = require('./plugins/text-to-data');
+const testsToData = require('./plugins/tests-to-data');
+
+const textProcessor = unified()
+ .use(markdown)
+ .use(textToData)
+ .use(testsToData)
+ .use(frontmatter, ['yaml']);
+
+exports.getText = createProcessor(textProcessor);
+
+function createProcessor(processor) {
+ return async msg => {
+ const file = typeof msg === 'string' ? vfile.readSync(msg) : msg;
+ const tree = processor.parse(file);
+ await processor.run(tree, file);
+ return file.data;
+ };
+}
diff --git a/tools/scripts/formatter/md-to-mdx/utils/get-all-between.js b/tools/scripts/formatter/md-to-mdx/utils/get-all-between.js
new file mode 100644
index 0000000000..1311a447c0
--- /dev/null
+++ b/tools/scripts/formatter/md-to-mdx/utils/get-all-between.js
@@ -0,0 +1,19 @@
+const between = require('unist-util-find-all-between');
+const find = require('unist-util-find');
+const findAfter = require('unist-util-find-after');
+const findAllAfter = require('unist-util-find-all-after');
+
+function getAllBetween(tree, testStart, testEnd) {
+ const start = find(tree, testStart);
+
+ if (!start) return [];
+
+ const end = findAfter(tree, start, testEnd);
+
+ const targetNodes = end
+ ? between(tree, start, end)
+ : findAllAfter(tree, start);
+ return targetNodes;
+}
+
+module.exports = getAllBetween;
diff --git a/tools/scripts/formatter/md-to-mdx/validate-hints.js b/tools/scripts/formatter/md-to-mdx/validate-hints.js
new file mode 100644
index 0000000000..8f30e77506
--- /dev/null
+++ b/tools/scripts/formatter/md-to-mdx/validate-hints.js
@@ -0,0 +1,19 @@
+const readDirP = require('readdirp-walk');
+const { getText } = require('./transform-to-mdx');
+const { validateHints } = require('./create-mdx');
+
+const challengeDir = '../../../../curriculum/challenges/english';
+
+readDirP({
+ root: challengeDir,
+ fileFilter: ['*.md']
+}).on('data', file => {
+ if (file.stat.isFile()) {
+ getText(file.fullPath)
+ .then(validateHints)
+ .catch(() => {
+ console.log('invalid hint in');
+ console.log(file.path);
+ });
+ }
+});
diff --git a/tools/scripts/formatter/package-lock.json b/tools/scripts/formatter/package-lock.json
new file mode 100644
index 0000000000..282ffad0a5
--- /dev/null
+++ b/tools/scripts/formatter/package-lock.json
@@ -0,0 +1,2185 @@
+{
+ "name": "fcc-formatter",
+ "version": "1.0.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@types/hast": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.1.tgz",
+ "integrity": "sha512-viwwrB+6xGzw+G1eWpF9geV3fnsDgXqHG+cqgiHrvQfDUW5hzhCyV7Sy3UJxhfRFBsgky2SSW33qi/YrIkjX5Q==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "*"
+ }
+ },
+ "@types/mdast": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.3.tgz",
+ "integrity": "sha512-SXPBMnFVQg1s00dlMCc/jCdvPqdE4mXaMMCeRlxLDmTAEoegHT53xKtkDnzDTOcmMHUfcjyf36/YYZ6SxRdnsw==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "*"
+ }
+ },
+ "@types/parse5": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-5.0.3.tgz",
+ "integrity": "sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==",
+ "dev": true
+ },
+ "@types/unist": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.3.tgz",
+ "integrity": "sha512-FvUupuM3rlRsRtCN+fDudtmytGO6iHJuuRKS1Ss0pG5z8oX0diNEw94UEL7hgDbpN94rgaK5R7sWm6RrSkZuAQ==",
+ "dev": true
+ },
+ "argparse": {
+ "version": "1.0.10",
+ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+ "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+ "dev": true,
+ "requires": {
+ "sprintf-js": "~1.0.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-iterate": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/array-iterate/-/array-iterate-1.1.4.tgz",
+ "integrity": "sha512-sNRaPGh9nnmdC8Zf+pT3UqP8rnWj5Hf9wiFGsX3wUQ2yVSIhO2ShFwCoceIPpB41QF6i2OEmrHmCo36xronCVA==",
+ "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
+ },
+ "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
+ },
+ "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
+ },
+ "bail": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/bail/-/bail-1.0.5.tgz",
+ "integrity": "sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ==",
+ "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"
+ }
+ }
+ }
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "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"
+ }
+ },
+ "ccount": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/ccount/-/ccount-1.0.5.tgz",
+ "integrity": "sha512-MOli1W+nfbPLlKEhInaxhRdp7KVLFxLN5ykwzHgLsLI3H3gs5jjFAK4Eoj3OzzcxCtumDaI8onoVDeQyWaNTkw==",
+ "dev": true
+ },
+ "character-entities": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
+ "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
+ "dev": true
+ },
+ "character-entities-html4": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz",
+ "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g==",
+ "dev": true
+ },
+ "character-entities-legacy": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
+ "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
+ "dev": true
+ },
+ "character-reference-invalid": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
+ "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
+ "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"
+ }
+ }
+ }
+ },
+ "collapse-white-space": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz",
+ "integrity": "sha512-jEovNnrhMuqyCcjfEJA56v0Xq8SkIoPKDyaHahwo3POf4qcSXqMYuwNcOTzp74vTsR9Tn08z4MxWqAhcekogkQ==",
+ "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"
+ }
+ },
+ "comma-separated-tokens": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz",
+ "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==",
+ "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
+ },
+ "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-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+ "dev": true
+ },
+ "dbly-linked-list": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/dbly-linked-list/-/dbly-linked-list-0.2.0.tgz",
+ "integrity": "sha512-Ool7y15f6JRDs0YKx7Dh9uiTb1jS1SZLNdT3Y2q16DlaEghXbMsmODS/XittjR2xztt1gJUpz7jVxpqAPF8VGg==",
+ "dev": true,
+ "requires": {
+ "lodash.isequal": "^4.5.0"
+ }
+ },
+ "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"
+ }
+ },
+ "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=",
+ "dev": true
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "esprima": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+ "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+ "dev": true
+ },
+ "eventemitter3": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
+ "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==",
+ "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"
+ }
+ }
+ }
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "fault": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz",
+ "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==",
+ "dev": true,
+ "requires": {
+ "format": "^0.2.0"
+ }
+ },
+ "fifo": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/fifo/-/fifo-2.3.0.tgz",
+ "integrity": "sha1-GC3o3QYyqkfPaBbZvEMjMX1SWdw=",
+ "dev": true
+ },
+ "fill-range": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
+ "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
+ "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"
+ }
+ }
+ }
+ },
+ "for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+ "dev": true
+ },
+ "format": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz",
+ "integrity": "sha1-1hcBB+nv3E7TDJ3DkBbflCtctYs=",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "get-value": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
+ "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+ "dev": true
+ },
+ "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==",
+ "dev": true
+ },
+ "has-value": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
+ "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
+ "dev": true,
+ "requires": {
+ "get-value": "^2.0.6",
+ "has-values": "^1.0.0",
+ "isobject": "^3.0.0"
+ }
+ },
+ "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": {
+ "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
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "hast-to-hyperscript": {
+ "version": "9.0.0",
+ "resolved": "https://registry.npmjs.org/hast-to-hyperscript/-/hast-to-hyperscript-9.0.0.tgz",
+ "integrity": "sha512-NJvMYU3GlMLs7hN3CRbsNlMzusVNkYBogVWDGybsuuVQ336gFLiD+q9qtFZT2meSHzln3pNISZWTASWothMSMg==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.3",
+ "comma-separated-tokens": "^1.0.0",
+ "property-information": "^5.3.0",
+ "space-separated-tokens": "^1.0.0",
+ "style-to-object": "^0.3.0",
+ "unist-util-is": "^4.0.0",
+ "web-namespaces": "^1.0.0"
+ }
+ },
+ "hast-util-embedded": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/hast-util-embedded/-/hast-util-embedded-1.0.5.tgz",
+ "integrity": "sha512-0FfLHmfArWOizbdwjL+Rc9QIBzqP80juicNl4S4NEPq5OYWBCgYrtYDPUDoSyQQ9IQlBn9W7++fpYQNzZSq/wQ==",
+ "dev": true,
+ "requires": {
+ "hast-util-is-element": "^1.0.0"
+ }
+ },
+ "hast-util-from-parse5": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-6.0.0.tgz",
+ "integrity": "sha512-3ZYnfKenbbkhhNdmOQqgH10vnvPivTdsOJCri+APn0Kty+nRkDHArnaX9Hiaf8H+Ig+vkNptL+SRY/6RwWJk1Q==",
+ "dev": true,
+ "requires": {
+ "@types/parse5": "^5.0.0",
+ "ccount": "^1.0.0",
+ "hastscript": "^5.0.0",
+ "property-information": "^5.0.0",
+ "vfile": "^4.0.0",
+ "web-namespaces": "^1.0.0"
+ },
+ "dependencies": {
+ "hastscript": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-5.1.2.tgz",
+ "integrity": "sha512-WlztFuK+Lrvi3EggsqOkQ52rKbxkXL3RwB6t5lwoa8QLMemoWfBuL43eDrwOamJyR7uKQKdmKYaBH1NZBiIRrQ==",
+ "dev": true,
+ "requires": {
+ "comma-separated-tokens": "^1.0.0",
+ "hast-util-parse-selector": "^2.0.0",
+ "property-information": "^5.0.0",
+ "space-separated-tokens": "^1.0.0"
+ }
+ }
+ }
+ },
+ "hast-util-has-property": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/hast-util-has-property/-/hast-util-has-property-1.0.4.tgz",
+ "integrity": "sha512-ghHup2voGfgFoHMGnaLHOjbYFACKrRh9KFttdCzMCbFoBMJXiNi2+XTrPP8+q6cDJM/RSqlCfVWrjp1H201rZg==",
+ "dev": true
+ },
+ "hast-util-is-body-ok-link": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/hast-util-is-body-ok-link/-/hast-util-is-body-ok-link-1.0.4.tgz",
+ "integrity": "sha512-mFblNpLvFbD8dG2Nw5dJBYZkxIHeph1JAh5yr4huI7T5m8cV0zaXNiqzKPX/JdjA+tIDF7c33u9cxK132KRjyQ==",
+ "dev": true,
+ "requires": {
+ "hast-util-has-property": "^1.0.0",
+ "hast-util-is-element": "^1.0.0"
+ }
+ },
+ "hast-util-is-element": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-1.1.0.tgz",
+ "integrity": "sha512-oUmNua0bFbdrD/ELDSSEadRVtWZOf3iF6Lbv81naqsIV99RnSCieTbWuWCY8BAeEfKJTKl0gRdokv+dELutHGQ==",
+ "dev": true
+ },
+ "hast-util-parse-selector": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.4.tgz",
+ "integrity": "sha512-gW3sxfynIvZApL4L07wryYF4+C9VvH3AUi7LAnVXV4MneGEgwOByXvFo18BgmTWnm7oHAe874jKbIB1YhHSIzA==",
+ "dev": true
+ },
+ "hast-util-phrasing": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/hast-util-phrasing/-/hast-util-phrasing-1.0.5.tgz",
+ "integrity": "sha512-P3uxm+8bnwcfAS/XpGie9wMmQXAQqsYhgQQKRwmWH/V6chiq0lmTy8KjQRJmYjusdMtNKGCUksdILSZy1suSpQ==",
+ "dev": true,
+ "requires": {
+ "hast-util-embedded": "^1.0.0",
+ "hast-util-has-property": "^1.0.0",
+ "hast-util-is-body-ok-link": "^1.0.0",
+ "hast-util-is-element": "^1.0.0"
+ }
+ },
+ "hast-util-raw": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-6.0.1.tgz",
+ "integrity": "sha512-ZMuiYA+UF7BXBtsTBNcLBF5HzXzkyE6MLzJnL605LKE8GJylNjGc4jjxazAHUtcwT5/CEt6afRKViYB4X66dig==",
+ "dev": true,
+ "requires": {
+ "@types/hast": "^2.0.0",
+ "hast-util-from-parse5": "^6.0.0",
+ "hast-util-to-parse5": "^6.0.0",
+ "html-void-elements": "^1.0.0",
+ "parse5": "^6.0.0",
+ "unist-util-position": "^3.0.0",
+ "vfile": "^4.0.0",
+ "web-namespaces": "^1.0.0",
+ "xtend": "^4.0.0",
+ "zwitch": "^1.0.0"
+ }
+ },
+ "hast-util-to-html": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-7.1.1.tgz",
+ "integrity": "sha512-Ujqj0hGuo3dIQKilkbauAv5teOqPvhaSLEgs1lgApFT0812e114KiffV8XfE4ttR8dRPqxNOIJOMu6SKOVOGlg==",
+ "dev": true,
+ "requires": {
+ "ccount": "^1.0.0",
+ "comma-separated-tokens": "^1.0.0",
+ "hast-util-is-element": "^1.0.0",
+ "hast-util-whitespace": "^1.0.0",
+ "html-void-elements": "^1.0.0",
+ "property-information": "^5.0.0",
+ "space-separated-tokens": "^1.0.0",
+ "stringify-entities": "^3.0.1",
+ "unist-util-is": "^4.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "hast-util-to-mdast": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/hast-util-to-mdast/-/hast-util-to-mdast-6.0.0.tgz",
+ "integrity": "sha512-DqG5A0QCi/VACAa9W35aiR0bA1fwYpLgo5IYG6KOQ6v0moT0YhM/JoX25JTmsoyGVy+NC37082shcLefFCL5qA==",
+ "dev": true,
+ "requires": {
+ "extend": "^3.0.2",
+ "hast-util-has-property": "^1.0.0",
+ "hast-util-is-element": "^1.0.0",
+ "hast-util-to-text": "^1.0.0",
+ "mdast-util-phrasing": "^1.0.0",
+ "mdast-util-to-string": "^1.0.4",
+ "rehype-minify-whitespace": "^3.0.0",
+ "repeat-string": "^1.6.1",
+ "trim-trailing-lines": "^1.1.0",
+ "unist-util-visit": "^2.0.0",
+ "xtend": "^4.0.1"
+ }
+ },
+ "hast-util-to-parse5": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-6.0.0.tgz",
+ "integrity": "sha512-Lu5m6Lgm/fWuz8eWnrKezHtVY83JeRGaNQ2kn9aJgqaxvVkFCZQBEhgodZUDUvoodgyROHDb3r5IxAEdl6suJQ==",
+ "dev": true,
+ "requires": {
+ "hast-to-hyperscript": "^9.0.0",
+ "property-information": "^5.0.0",
+ "web-namespaces": "^1.0.0",
+ "xtend": "^4.0.0",
+ "zwitch": "^1.0.0"
+ }
+ },
+ "hast-util-to-text": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-1.0.1.tgz",
+ "integrity": "sha512-Xvp9fWiWVb4WaHc1E1g6dtyYlcVwyjRT0CC9oXtVUNhbmIB1gqRVBuBIFJgrFkYxdo+T3UIl5i5ipPGaPRnUOw==",
+ "dev": true,
+ "requires": {
+ "hast-util-is-element": "^1.0.2",
+ "repeat-string": "^1.6.1",
+ "unist-util-find-after": "^2.0.3"
+ },
+ "dependencies": {
+ "unist-util-find-after": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-2.0.4.tgz",
+ "integrity": "sha512-zo0ShIr+E/aU9xSK7JC9Kb+WP9seTFCuqVYdo5+HJSjN009XMfhiA1FIExEKzdDP1UsgvKGleGlB/pSdTSqZww==",
+ "dev": true,
+ "requires": {
+ "unist-util-is": "^3.0.0"
+ }
+ },
+ "unist-util-is": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz",
+ "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==",
+ "dev": true
+ }
+ }
+ },
+ "hast-util-whitespace": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz",
+ "integrity": "sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A==",
+ "dev": true
+ },
+ "hastscript": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz",
+ "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==",
+ "dev": true,
+ "requires": {
+ "@types/hast": "^2.0.0",
+ "comma-separated-tokens": "^1.0.0",
+ "hast-util-parse-selector": "^2.0.0",
+ "property-information": "^5.0.0",
+ "space-separated-tokens": "^1.0.0"
+ }
+ },
+ "he": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
+ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
+ "dev": true
+ },
+ "html-void-elements": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-1.0.5.tgz",
+ "integrity": "sha512-uE/TxKuyNIcx44cIWnjr/rfIATDH7ZaOMmstu0CwhFG1Dunhlp4OC6/NMbhiwoq5BpW0ubi303qnEk/PZj614w==",
+ "dev": true
+ },
+ "html-whitespace-sensitive-tag-names": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/html-whitespace-sensitive-tag-names/-/html-whitespace-sensitive-tag-names-1.0.3.tgz",
+ "integrity": "sha512-GX1UguduCBEAEo1hjFxc2Bz04/sDq0ACNyT7LsuoDcPfXYI3nS0NRPp3dyazLJyVUMp3GPBB56i/0Zr6CqD2PQ==",
+ "dev": true
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "inline-style-parser": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz",
+ "integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q==",
+ "dev": true
+ },
+ "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": {
+ "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
+ },
+ "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-alphabetical": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
+ "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
+ "dev": true
+ },
+ "is-alphanumeric": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-alphanumeric/-/is-alphanumeric-1.0.0.tgz",
+ "integrity": "sha1-Spzvcdr0wAHB2B1j0UDPU/1oifQ=",
+ "dev": true
+ },
+ "is-alphanumerical": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
+ "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
+ "dev": true,
+ "requires": {
+ "is-alphabetical": "^1.0.0",
+ "is-decimal": "^1.0.0"
+ }
+ },
+ "is-buffer": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
+ "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==",
+ "dev": true
+ },
+ "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": {
+ "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
+ },
+ "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-decimal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
+ "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
+ "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-extendable": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+ "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+ "dev": true
+ },
+ "is-hexadecimal": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
+ "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
+ "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": {
+ "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
+ },
+ "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-plain-obj": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz",
+ "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==",
+ "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-whitespace-character": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-whitespace-character/-/is-whitespace-character-1.0.4.tgz",
+ "integrity": "sha512-SDweEzfIZM0SJV0EUga669UTKlmL0Pq8Lno0QDQsPnvECB3IM2aP0gdx5TrU0A01MAPfViaZiI2V1QMZLaKK5w==",
+ "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-word-character": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-word-character/-/is-word-character-1.0.4.tgz",
+ "integrity": "sha512-5SMO8RVennx3nZrqtKwCGyyetPE9VDba5ugvKLaD4KopPG5kR4mQ7tNt/r7feL5yt5h3lpuBbIUmCOG2eSzXHA==",
+ "dev": true
+ },
+ "isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+ "dev": true
+ },
+ "isflattenable": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/isflattenable/-/isflattenable-1.1.0.tgz",
+ "integrity": "sha512-qr/kk8a8KmevVz0Sp899TdSAHg9ybc1HnFlFq/3ZW9G4a5IQsHz5fVnmq0poFMpCqI9wLPHSH9cCT2R1ctXoIQ==",
+ "dev": true,
+ "requires": {
+ "lodash.isarguments": "^3.1.0",
+ "lodash.isarray": "^3.0.4"
+ }
+ },
+ "isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+ "dev": true
+ },
+ "join-deep": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/join-deep/-/join-deep-1.2.1.tgz",
+ "integrity": "sha512-z1rVo21SUcDXtgWvToo8O2RfuMy6/ScnEWzyvVRRGYdWMrLqT0iGw/jkHxZ4BaBJGzTQxYhi0ZonsHlU+oJ8iw==",
+ "dev": true,
+ "requires": {
+ "reduce-deep": "^1.3.1"
+ }
+ },
+ "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"
+ }
+ },
+ "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
+ },
+ "lodash": {
+ "version": "4.17.20",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
+ "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
+ "dev": true
+ },
+ "lodash.isarguments": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
+ "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=",
+ "dev": true
+ },
+ "lodash.isarray": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
+ "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=",
+ "dev": true
+ },
+ "lodash.isequal": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+ "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA=",
+ "dev": true
+ },
+ "lodash.iteratee": {
+ "version": "4.7.0",
+ "resolved": "https://registry.npmjs.org/lodash.iteratee/-/lodash.iteratee-4.7.0.tgz",
+ "integrity": "sha1-vkF32yiajMw8CZDx2ya1si/BVUw=",
+ "dev": true
+ },
+ "longest-streak": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-2.0.4.tgz",
+ "integrity": "sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg==",
+ "dev": true
+ },
+ "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"
+ }
+ },
+ "markdown-escapes": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/markdown-escapes/-/markdown-escapes-1.0.4.tgz",
+ "integrity": "sha512-8z4efJYk43E0upd0NbVXwgSTQs6cT3T06etieCMEg7dRbzCbxUCK/GHlX8mhHRDcp+OLlHkPKsvqQTCvsRl2cg==",
+ "dev": true
+ },
+ "markdown-table": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-2.0.0.tgz",
+ "integrity": "sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==",
+ "dev": true,
+ "requires": {
+ "repeat-string": "^1.0.0"
+ }
+ },
+ "mdast-builder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/mdast-builder/-/mdast-builder-1.1.1.tgz",
+ "integrity": "sha512-a3KBk/LmYD6wKsWi8WJrGU/rXR4yuF4Men0JO0z6dSZCm5FrXXWTRDjqK0vGSqa+1M6p9edeuypZAZAzSehTUw==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.3"
+ }
+ },
+ "mdast-util-compact": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/mdast-util-compact/-/mdast-util-compact-2.0.1.tgz",
+ "integrity": "sha512-7GlnT24gEwDrdAwEHrU4Vv5lLWrEer4KOkAiKT9nYstsTad7Oc1TwqT2zIMKRdZF7cTuaf+GA1E4Kv7jJh8mPA==",
+ "dev": true,
+ "requires": {
+ "unist-util-visit": "^2.0.0"
+ }
+ },
+ "mdast-util-definitions": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-4.0.0.tgz",
+ "integrity": "sha512-k8AJ6aNnUkB7IE+5azR9h81O5EQ/cTDXtWdMq9Kk5KcEW/8ritU5CeLg/9HhOC++nALHBlaogJ5jz0Ybk3kPMQ==",
+ "dev": true,
+ "requires": {
+ "unist-util-visit": "^2.0.0"
+ }
+ },
+ "mdast-util-phrasing": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-1.0.3.tgz",
+ "integrity": "sha512-b1Ar28MjmPMMnTDUApnL1AUJY1L/KmBg5+iBLMd8/+0JqXh1sENow9+wj8Mp/SZBYtMlGRUQ1PkBWinPEDVeNQ==",
+ "dev": true,
+ "requires": {
+ "unist-util-is": "^3.0.0"
+ },
+ "dependencies": {
+ "unist-util-is": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz",
+ "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==",
+ "dev": true
+ }
+ }
+ },
+ "mdast-util-to-hast": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-10.0.0.tgz",
+ "integrity": "sha512-dRyAC5S4eDcIOdkz4jg0wXbUdlf+5YFu7KppJNHOsMaD7ql5bKIqVcvXYYkcrKjzUkfX8JsKFVMthsU8OWxQ+w==",
+ "dev": true,
+ "requires": {
+ "@types/mdast": "^3.0.0",
+ "@types/unist": "^2.0.0",
+ "mdast-util-definitions": "^4.0.0",
+ "mdurl": "^1.0.0",
+ "unist-builder": "^2.0.0",
+ "unist-util-generated": "^1.0.0",
+ "unist-util-position": "^3.0.0",
+ "unist-util-visit": "^2.0.0"
+ }
+ },
+ "mdast-util-to-string": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz",
+ "integrity": "sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==",
+ "dev": true
+ },
+ "mdurl": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+ "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
+ "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"
+ }
+ },
+ "mixin-deep": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
+ "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
+ "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"
+ }
+ }
+ }
+ },
+ "ms": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+ "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"
+ }
+ },
+ "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"
+ }
+ },
+ "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
+ },
+ "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-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.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
+ "dev": true,
+ "requires": {
+ "isobject": "^3.0.1"
+ }
+ },
+ "parse-entities": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
+ "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
+ "dev": true,
+ "requires": {
+ "character-entities": "^1.0.0",
+ "character-entities-legacy": "^1.0.0",
+ "character-reference-invalid": "^1.0.0",
+ "is-alphanumerical": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-hexadecimal": "^1.0.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
+ },
+ "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
+ },
+ "prettier": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz",
+ "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==",
+ "dev": true
+ },
+ "process-nextick-args": {
+ "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
+ },
+ "property-information": {
+ "version": "5.6.0",
+ "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz",
+ "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==",
+ "dev": true,
+ "requires": {
+ "xtend": "^4.0.0"
+ }
+ },
+ "queue-cb": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/queue-cb/-/queue-cb-1.1.5.tgz",
+ "integrity": "sha512-PKsogFZgSyIYn9hFD401ul8RWJnTtdUw+owgvWwhcevsYwY/UvJIeIziibB61CLp7/wry5EWLHmXzjeXr441Nw==",
+ "dev": true,
+ "requires": {
+ "fifo": "^2.3.0"
+ }
+ },
+ "readable-stream": {
+ "version": "2.3.7",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+ "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+ "dev": true,
+ "requires": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "readdirp-walk": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/readdirp-walk/-/readdirp-walk-1.7.0.tgz",
+ "integrity": "sha512-tGAXcAlxTM2I8SfOUniI/43eienxkywW5NuN3Ov1Qpngjnw8l1LcjSTBc6QwOpv9D0MTdPHb/wmPVKExbuYa0g==",
+ "dev": true,
+ "requires": {
+ "eventemitter3": "^3.1.0",
+ "graceful-fs": "^4.1.11",
+ "micromatch": "^3.1.10",
+ "readable-stream": "^2.0.2",
+ "walk-filtered": "^1.13.0"
+ }
+ },
+ "reduce-deep": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/reduce-deep/-/reduce-deep-1.3.1.tgz",
+ "integrity": "sha512-UJuIfS1er7MwsTQ5fkjgGo2gwM3WynmCg7VJLv/RqIU8xtCqrkFC922tWyD1dxeA+lC5pyUZi6JdIUKI6UubsA==",
+ "dev": true,
+ "requires": {
+ "isflattenable": "^1.1.0"
+ }
+ },
+ "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"
+ }
+ },
+ "rehype-minify-whitespace": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/rehype-minify-whitespace/-/rehype-minify-whitespace-3.0.0.tgz",
+ "integrity": "sha512-Z5NIG9FxTeK2Ta+eTWCnTVPXu1qC58eCXZA3m/Z7PPinKw82KSR+12c2l1sLLSg27QZOmZrrd9piS8dsAVfliQ==",
+ "dev": true,
+ "requires": {
+ "collapse-white-space": "^1.0.0",
+ "hast-util-embedded": "^1.0.0",
+ "hast-util-has-property": "^1.0.0",
+ "hast-util-is-body-ok-link": "^1.0.0",
+ "hast-util-is-element": "^1.0.0",
+ "html-whitespace-sensitive-tag-names": "^1.0.0",
+ "unist-util-is": "^4.0.0",
+ "unist-util-modify-children": "^1.0.0"
+ }
+ },
+ "rehype-raw": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/rehype-raw/-/rehype-raw-5.0.0.tgz",
+ "integrity": "sha512-q/MOBj4fs1WF/LSCh5uOtNhnm5OESuDcSvq1mDQP4/2t6Q52E9MHeVoLeMy9vOn93BEcgVBm4FCokcK2iXRDvA==",
+ "dev": true,
+ "requires": {
+ "hast-util-raw": "^6.0.0"
+ }
+ },
+ "rehype-stringify": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-8.0.0.tgz",
+ "integrity": "sha512-VkIs18G0pj2xklyllrPSvdShAV36Ff3yE5PUO9u36f6+2qJFnn22Z5gKwBOwgXviux4UC7K+/j13AnZfPICi/g==",
+ "dev": true,
+ "requires": {
+ "hast-util-to-html": "^7.1.1"
+ }
+ },
+ "remark-frontmatter": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/remark-frontmatter/-/remark-frontmatter-2.0.0.tgz",
+ "integrity": "sha512-uNOQt4tO14qBFWXenF0MLC4cqo3dv8qiHPGyjCl1rwOT0LomSHpcElbjjVh5CwzElInB38HD8aSRVugKQjeyHA==",
+ "dev": true,
+ "requires": {
+ "fault": "^1.0.1"
+ }
+ },
+ "remark-parse": {
+ "version": "8.0.3",
+ "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-8.0.3.tgz",
+ "integrity": "sha512-E1K9+QLGgggHxCQtLt++uXltxEprmWzNfg+MxpfHsZlrddKzZ/hZyWHDbK3/Ap8HJQqYJRXP+jHczdL6q6i85Q==",
+ "dev": true,
+ "requires": {
+ "ccount": "^1.0.0",
+ "collapse-white-space": "^1.0.2",
+ "is-alphabetical": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-whitespace-character": "^1.0.0",
+ "is-word-character": "^1.0.0",
+ "markdown-escapes": "^1.0.0",
+ "parse-entities": "^2.0.0",
+ "repeat-string": "^1.5.4",
+ "state-toggle": "^1.0.0",
+ "trim": "0.0.1",
+ "trim-trailing-lines": "^1.0.0",
+ "unherit": "^1.0.4",
+ "unist-util-remove-position": "^2.0.0",
+ "vfile-location": "^3.0.0",
+ "xtend": "^4.0.1"
+ }
+ },
+ "remark-rehype": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/remark-rehype/-/remark-rehype-8.0.0.tgz",
+ "integrity": "sha512-gVvOH02TMFqXOWoL6iXU7NXMsDJguNkNuMrzfkQeA4V6WCyHQnOKptn+IQBVVPuIH2sMJBwo8hlrmtn1MLTh9w==",
+ "dev": true,
+ "requires": {
+ "mdast-util-to-hast": "^10.0.0"
+ }
+ },
+ "remark-stringify": {
+ "version": "8.1.1",
+ "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-8.1.1.tgz",
+ "integrity": "sha512-q4EyPZT3PcA3Eq7vPpT6bIdokXzFGp9i85igjmhRyXWmPs0Y6/d2FYwUNotKAWyLch7g0ASZJn/KHHcHZQ163A==",
+ "dev": true,
+ "requires": {
+ "ccount": "^1.0.0",
+ "is-alphanumeric": "^1.0.0",
+ "is-decimal": "^1.0.0",
+ "is-whitespace-character": "^1.0.0",
+ "longest-streak": "^2.0.1",
+ "markdown-escapes": "^1.0.0",
+ "markdown-table": "^2.0.0",
+ "mdast-util-compact": "^2.0.0",
+ "parse-entities": "^2.0.0",
+ "repeat-string": "^1.5.4",
+ "state-toggle": "^1.0.0",
+ "stringify-entities": "^3.0.0",
+ "unherit": "^1.0.4",
+ "xtend": "^4.0.1"
+ }
+ },
+ "repeat-element": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
+ "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
+ "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
+ },
+ "replace-ext": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz",
+ "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=",
+ "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==",
+ "dev": true
+ },
+ "safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "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"
+ }
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "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": {
+ "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
+ },
+ "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"
+ }
+ },
+ "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=",
+ "dev": true
+ },
+ "space-separated-tokens": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz",
+ "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==",
+ "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
+ },
+ "stack-lifo": {
+ "version": "0.1.6",
+ "resolved": "https://registry.npmjs.org/stack-lifo/-/stack-lifo-0.1.6.tgz",
+ "integrity": "sha512-fNXXK6AHbOIExOtJYPb1RlP8OXQr8tlpDNP5I78ZId9uK+MDCcDAkwGWTDACYLXAwOhaKLTYwkoSOihAt+/cLg==",
+ "dev": true,
+ "requires": {
+ "dbly-linked-list": "0.2.0"
+ }
+ },
+ "state-toggle": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/state-toggle/-/state-toggle-1.0.3.tgz",
+ "integrity": "sha512-d/5Z4/2iiCnHw6Xzghyhb+GcmF89bxwgXG60wjIiZaxnymbyOmI8Hk4VqHXiVVp6u2ysaskFfXg3ekCj4WNftQ==",
+ "dev": true
+ },
+ "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"
+ }
+ }
+ }
+ },
+ "string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "requires": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "stringify-entities": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-3.1.0.tgz",
+ "integrity": "sha512-3FP+jGMmMV/ffZs86MoghGqAoqXAdxLrJP4GUdrDN1aIScYih5tuIO3eF4To5AJZ79KDZ8Fpdy7QJnK8SsL1Vg==",
+ "dev": true,
+ "requires": {
+ "character-entities-html4": "^1.0.0",
+ "character-entities-legacy": "^1.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "style-to-object": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.3.0.tgz",
+ "integrity": "sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA==",
+ "dev": true,
+ "requires": {
+ "inline-style-parser": "0.1.1"
+ }
+ },
+ "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": {
+ "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
+ },
+ "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=",
+ "dev": true,
+ "requires": {
+ "is-number": "^3.0.0",
+ "repeat-string": "^1.6.1"
+ }
+ },
+ "to-vfile": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-6.1.0.tgz",
+ "integrity": "sha512-BxX8EkCxOAZe+D/ToHdDsJcVI4HqQfmw0tCkp31zf3dNP/XWIAjU4CmeuSwsSoOzOTqHPOL0KUzyZqJplkD0Qw==",
+ "dev": true,
+ "requires": {
+ "is-buffer": "^2.0.0",
+ "vfile": "^4.0.0"
+ }
+ },
+ "trim": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/trim/-/trim-0.0.1.tgz",
+ "integrity": "sha1-WFhUf2spB1fulczMZm+1AITEYN0=",
+ "dev": true
+ },
+ "trim-trailing-lines": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/trim-trailing-lines/-/trim-trailing-lines-1.1.3.tgz",
+ "integrity": "sha512-4ku0mmjXifQcTVfYDfR5lpgV7zVqPg6zV9rdZmwOPqq0+Zq19xDqEgagqVbc4pOOShbncuAOIs59R3+3gcF3ZA==",
+ "dev": true
+ },
+ "trough": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/trough/-/trough-1.0.5.tgz",
+ "integrity": "sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA==",
+ "dev": true
+ },
+ "unherit": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/unherit/-/unherit-1.1.3.tgz",
+ "integrity": "sha512-Ft16BJcnapDKp0+J/rqFC3Rrk6Y/Ng4nzsC028k2jdDII/rdZ7Wd3pPT/6+vIIxRagwRc9K0IUX0Ra4fKvw+WQ==",
+ "dev": true,
+ "requires": {
+ "inherits": "^2.0.0",
+ "xtend": "^4.0.0"
+ }
+ },
+ "unified": {
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/unified/-/unified-9.2.0.tgz",
+ "integrity": "sha512-vx2Z0vY+a3YoTj8+pttM3tiJHCwY5UFbYdiWrwBEbHmK8pvsPj2rtAX2BFfgXen8T39CJWblWRDT4L5WGXtDdg==",
+ "dev": true,
+ "requires": {
+ "bail": "^1.0.0",
+ "extend": "^3.0.0",
+ "is-buffer": "^2.0.0",
+ "is-plain-obj": "^2.0.0",
+ "trough": "^1.0.0",
+ "vfile": "^4.0.0"
+ }
+ },
+ "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"
+ }
+ },
+ "unist-builder": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/unist-builder/-/unist-builder-2.0.3.tgz",
+ "integrity": "sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==",
+ "dev": true
+ },
+ "unist-util-find": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/unist-util-find/-/unist-util-find-1.0.2.tgz",
+ "integrity": "sha512-ft06UDYzqi9o9RmGP0sZWI/zvLLQiBW2/MD+rW6mDqbOWDcmknGX9orQPspfuGRYWr8eSJAmfsBcvOpfGRJseA==",
+ "dev": true,
+ "requires": {
+ "lodash.iteratee": "^4.5.0",
+ "unist-util-visit": "^1.1.0"
+ },
+ "dependencies": {
+ "unist-util-is": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-3.0.0.tgz",
+ "integrity": "sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==",
+ "dev": true
+ },
+ "unist-util-visit": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-1.4.1.tgz",
+ "integrity": "sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==",
+ "dev": true,
+ "requires": {
+ "unist-util-visit-parents": "^2.0.0"
+ }
+ },
+ "unist-util-visit-parents": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz",
+ "integrity": "sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==",
+ "dev": true,
+ "requires": {
+ "unist-util-is": "^3.0.0"
+ }
+ }
+ }
+ },
+ "unist-util-find-after": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/unist-util-find-after/-/unist-util-find-after-3.0.0.tgz",
+ "integrity": "sha512-ojlBqfsBftYXExNu3+hHLfJQ/X1jYY/9vdm4yZWjIbf0VuWF6CRufci1ZyoD/wV2TYMKxXUoNuoqwy+CkgzAiQ==",
+ "dev": true,
+ "requires": {
+ "unist-util-is": "^4.0.0"
+ }
+ },
+ "unist-util-find-all-after": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/unist-util-find-all-after/-/unist-util-find-all-after-3.0.2.tgz",
+ "integrity": "sha512-xaTC/AGZ0rIM2gM28YVRAFPIZpzbpDtU3dRmp7EXlNVA8ziQc4hY3H7BHXM1J49nEmiqc3svnqMReW+PGqbZKQ==",
+ "dev": true,
+ "requires": {
+ "unist-util-is": "^4.0.0"
+ }
+ },
+ "unist-util-find-all-between": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/unist-util-find-all-between/-/unist-util-find-all-between-2.1.0.tgz",
+ "integrity": "sha512-OCCUtDD8UHKeODw3TPXyFDxPCbpgBzbGTTaDpR68nvxkwiVcawBqMVrokfBMvUi7ij2F5q7S4s4Jq5dvkcBt+w==",
+ "dev": true,
+ "requires": {
+ "unist-util-find": "^1.0.1",
+ "unist-util-is": "^4.0.2"
+ }
+ },
+ "unist-util-generated": {
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/unist-util-generated/-/unist-util-generated-1.1.5.tgz",
+ "integrity": "sha512-1TC+NxQa4N9pNdayCYA1EGUOCAO0Le3fVp7Jzns6lnua/mYgwHo0tz5WUAfrdpNch1RZLHc61VZ1SDgrtNXLSw==",
+ "dev": true
+ },
+ "unist-util-is": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-4.0.4.tgz",
+ "integrity": "sha512-3dF39j/u423v4BBQrk1AQ2Ve1FxY5W3JKwXxVFzBODQ6WEvccguhgp802qQLKSnxPODE6WuRZtV+ohlUg4meBA==",
+ "dev": true
+ },
+ "unist-util-modify-children": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/unist-util-modify-children/-/unist-util-modify-children-1.1.6.tgz",
+ "integrity": "sha512-TOA6W9QLil+BrHqIZNR4o6IA5QwGOveMbnQxnWYq+7EFORx9vz/CHrtzF36zWrW61E2UKw7sM1KPtIgeceVwXw==",
+ "dev": true,
+ "requires": {
+ "array-iterate": "^1.0.0"
+ }
+ },
+ "unist-util-position": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-3.1.0.tgz",
+ "integrity": "sha512-w+PkwCbYSFw8vpgWD0v7zRCl1FpY3fjDSQ3/N/wNd9Ffa4gPi8+4keqt99N3XW6F99t/mUzp2xAhNmfKWp95QA==",
+ "dev": true
+ },
+ "unist-util-remove-position": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-2.0.1.tgz",
+ "integrity": "sha512-fDZsLYIe2uT+oGFnuZmy73K6ZxOPG/Qcm+w7jbEjaFcJgbQ6cqjs/eSPzXhsmGpAsWPkqZM9pYjww5QTn3LHMA==",
+ "dev": true,
+ "requires": {
+ "unist-util-visit": "^2.0.0"
+ }
+ },
+ "unist-util-stringify-position": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz",
+ "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.2"
+ }
+ },
+ "unist-util-visit": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-2.0.3.tgz",
+ "integrity": "sha512-iJ4/RczbJMkD0712mGktuGpm/U4By4FfDonL7N/9tATGIF4imikjOuagyMY53tnZq3NP6BcmlrHhEKAfGWjh7Q==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "unist-util-is": "^4.0.0",
+ "unist-util-visit-parents": "^3.0.0"
+ }
+ },
+ "unist-util-visit-parents": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz",
+ "integrity": "sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "unist-util-is": "^4.0.0"
+ }
+ },
+ "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
+ }
+ }
+ },
+ "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
+ },
+ "vfile": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/vfile/-/vfile-4.2.0.tgz",
+ "integrity": "sha512-a/alcwCvtuc8OX92rqqo7PflxiCgXRFjdyoGVuYV+qbgCb0GgZJRvIgCD4+U/Kl1yhaRsaTwksF88xbPyGsgpw==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "is-buffer": "^2.0.0",
+ "replace-ext": "1.0.0",
+ "unist-util-stringify-position": "^2.0.0",
+ "vfile-message": "^2.0.0"
+ }
+ },
+ "vfile-location": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-3.1.0.tgz",
+ "integrity": "sha512-FCZ4AN9xMcjFIG1oGmZKo61PjwJHRVA+0/tPUP2ul4uIwjGGndIxavEMRpWn5p4xwm/ZsdXp9YNygf1ZyE4x8g==",
+ "dev": true
+ },
+ "vfile-message": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz",
+ "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==",
+ "dev": true,
+ "requires": {
+ "@types/unist": "^2.0.0",
+ "unist-util-stringify-position": "^2.0.0"
+ }
+ },
+ "walk-filtered": {
+ "version": "1.24.0",
+ "resolved": "https://registry.npmjs.org/walk-filtered/-/walk-filtered-1.24.0.tgz",
+ "integrity": "sha512-z4dwZ5IpNEfWVYEso60fsgrXpym65M+a03vumbnonJCrMll3H8JVy9xrU2RHpVGMr8rwlr5y+9qpr71h0RWdsA==",
+ "dev": true,
+ "requires": {
+ "join-deep": "^1.2.0",
+ "queue-cb": "^1.1.0",
+ "stack-lifo": "^0.1.6"
+ }
+ },
+ "web-namespaces": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz",
+ "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==",
+ "dev": true
+ },
+ "xtend": {
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+ "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+ "dev": true
+ },
+ "zwitch": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-1.0.5.tgz",
+ "integrity": "sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==",
+ "dev": true
+ }
+ }
+}
diff --git a/tools/scripts/formatter/package.json b/tools/scripts/formatter/package.json
new file mode 100644
index 0000000000..8fc38d8895
--- /dev/null
+++ b/tools/scripts/formatter/package.json
@@ -0,0 +1,41 @@
+{
+ "name": "fcc-formatter",
+ "version": "1.0.0",
+ "description": "",
+ "main": "formatCurriculum.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "author": "",
+ "license": "BSD-3-Clause",
+ "devDependencies": {
+ "hast-util-phrasing": "^1.0.5",
+ "hast-util-raw": "^6.0.1",
+ "hast-util-to-html": "^7.1.1",
+ "hast-util-to-mdast": "^6.0.0",
+ "hastscript": "^6.0.0",
+ "he": "^1.2.0",
+ "js-yaml": "^3.14.1",
+ "lodash": "^4.17.20",
+ "mdast-builder": "^1.1.1",
+ "mdast-util-to-hast": "^10.0.0",
+ "parse-entities": "^2.0.0",
+ "prettier": "^2.2.1",
+ "readdirp-walk": "^1.7.0",
+ "rehype-raw": "^5.0.0",
+ "rehype-stringify": "^8.0.0",
+ "remark-frontmatter": "^2.0.0",
+ "remark-parse": "^8.0.3",
+ "remark-rehype": "^8.0.0",
+ "remark-stringify": "^8.1.1",
+ "to-vfile": "^6.1.0",
+ "unified": "^9.2.0",
+ "unist-util-find": "^1.0.2",
+ "unist-util-find-after": "^3.0.0",
+ "unist-util-find-all-after": "^3.0.2",
+ "unist-util-find-all-between": "^2.1.0",
+ "unist-util-is": "^4.0.4",
+ "unist-util-visit": "^2.0.3"
+ },
+ "dependencies": {}
+}