From cd86fba7def8bc2d55314eec6ce291ed341cbea7 Mon Sep 17 00:00:00 2001
From: lzear <antoine.clausse@gmail.com>
Date: Tue, 12 Jan 2021 23:10:42 +0100
Subject: [PATCH] feat: add Nanson method and Baldwin method

---
 README.md                    |  10 +-
 package.json                 |  25 ++---
 src/methods/baldwin/index.ts |  27 +++++
 src/methods/coombs/index.ts  |   2 +-
 src/methods/index.ts         |  22 ++++
 src/methods/nanson/index.ts  |  33 ++++++
 src/types.ts                 |   2 +
 src/votes.test.ts            |  68 +++++++++++--
 src/votes.ts                 |  42 +++++++-
 typedoc.js                   |   2 -
 yarn.lock                    | 191 +++++++++++++++++++----------------
 11 files changed, 304 insertions(+), 120 deletions(-)
 create mode 100644 src/methods/baldwin/index.ts
 create mode 100644 src/methods/nanson/index.ts

diff --git a/README.md b/README.md
index ba47a9e..16fd9db 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@ for more information.
 **⚠️Maximal lotteries & Randomized Condorcet⚠️** (Errors included): Returns
 probabilities for each candidate that should be used for a lottery between the
 Candidates. If a candidate is the Condorcet winner, its probability will be 1.
-Despite being non-deterministic, those methods are the most fair.
+Despite being non-deterministic, those methods are the fairest.
 
 **Ranked pairs**: Using the duel results as edges, build an acyclic graph
 starting by the strongest score differences. The roots of the graph are the
@@ -79,9 +79,15 @@ candidates.
 **Approval voting**: Each voter can select (“approve”) any number of candidates.
 The winner is the most-approved candidate.
 
-**Borda's count**: For each voter, every candidate is given a number of points
+**Borda count**: For each voter, every candidate is given a number of points
 which equals the number of candidates ranked lower in the voter's preference.
 
+**Nanson method**: Iterative Borda count in which, each round, candidates scoring
+the average score or less are eliminated.
+
+**Baldwin method**: Iterative Borda count in which, each round, candidates scoring
+the lowest score are eliminated.
+
 **Instant-runoff**: Considering only the top choice of each voter, the candidate
 with the fewest votes is eliminated. The election repeats until there is a
 winner. This voting system is very similar to single transferable vote method.
diff --git a/package.json b/package.json
index 990a256..118aeaf 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,8 @@
   "module": "dist/votes.es5.js",
   "types": "dist/votes.d.ts",
   "files": [
-    "dist"
+    "dist",
+    "src"
   ],
   "author": "lzear",
   "repository": {
@@ -20,7 +21,7 @@
     "eslint": "eslint --ext .js --ext .ts .",
     "fix:prettier": "prettier --write \"**/*.*\"",
     "prebuild": "rimraf dist",
-    "build": "rollup -c rollup.config.js && typedoc",
+    "build": "rollup -c rollup.config.js && npx typedoc src/votes.ts",
     "build:watch": "tsc --module commonjs && rollup -c rollup.config.js -w",
     "test": "jest --coverage",
     "test:watch": "jest --coverage --watch",
@@ -53,26 +54,26 @@
     "@rollup/plugin-commonjs": "^17.0.0",
     "@rollup/plugin-json": "^4.1.0",
     "@rollup/plugin-node-resolve": "^11.0.1",
-    "@types/jest": "^26.0.19",
-    "@types/lodash": "^4.14.165",
-    "@types/node": "^14.14.14",
-    "@typescript-eslint/eslint-plugin": "^4.11.0",
-    "@typescript-eslint/parser": "^4.11.0",
+    "@types/jest": "^26.0.20",
+    "@types/lodash": "^4.14.167",
+    "@types/node": "^14.14.20",
+    "@typescript-eslint/eslint-plugin": "^4.13.0",
+    "@typescript-eslint/parser": "^4.13.0",
     "commitizen": "^4.2.2",
     "dotenv": "^8.2.0",
-    "eslint": "^7.16.0",
+    "eslint": "^7.17.0",
     "eslint-config-prettier": "^7.1.0",
-    "eslint-plugin-prettier": "^3.3.0",
-    "husky": "^4.3.6",
+    "eslint-plugin-prettier": "^3.3.1",
+    "husky": "^4.3.7",
     "jest": "^26.6.3",
     "lint-staged": "^10.5.3",
     "prettier": "^2.2.1",
     "rimraf": "^3.0.2",
-    "rollup": "^2.35.1",
+    "rollup": "^2.36.1",
     "rollup-plugin-sizes": "^1.0.3",
     "rollup-plugin-sourcemaps": "^0.6.3",
     "rollup-plugin-typescript2": "^0.29.0",
-    "semantic-release": "^17.3.0",
+    "semantic-release": "^17.3.1",
     "shelljs": "^0.8.4",
     "travis-deploy-once": "^5.0.11",
     "ts-jest": "^26.4.4",
diff --git a/src/methods/baldwin/index.ts b/src/methods/baldwin/index.ts
new file mode 100644
index 0000000..3f89ebf
--- /dev/null
+++ b/src/methods/baldwin/index.ts
@@ -0,0 +1,27 @@
+import difference from 'lodash/difference'
+import {
+  SystemUsingRankings,
+  ScoreObject,
+  VotingSystem,
+  Ballot,
+} from '../../types'
+import { borda } from '../borda'
+import { scoresToRanking } from '../../utils'
+
+export const baldwin: SystemUsingRankings = {
+  type: VotingSystem.Baldwin,
+  computeFromBallots(ballots: Ballot[], candidates: string[]): ScoreObject {
+    const score: ScoreObject = {}
+    let remainingCandidates = candidates
+    let points = 0
+    while (remainingCandidates.length > 0) {
+      const bordaScores = borda.computeFromBallots(ballots, remainingCandidates)
+      const ranking = scoresToRanking(bordaScores)
+      const losers = ranking[ranking.length - 1]
+      for (const loser of losers) score[loser] = points
+      remainingCandidates = difference(remainingCandidates, losers)
+      points++
+    }
+    return score
+  },
+}
diff --git a/src/methods/coombs/index.ts b/src/methods/coombs/index.ts
index 96a3900..7218de8 100644
--- a/src/methods/coombs/index.ts
+++ b/src/methods/coombs/index.ts
@@ -16,7 +16,7 @@ export const coombs: SystemUsingRankings = {
       ranking: [...ballot.ranking].reverse(),
       weight: ballot.weight,
     }))
-    let remainingCandidates = [...candidates]
+    let remainingCandidates = candidates
     let points = 0
     while (remainingCandidates.length > 0) {
       const fptpScore = firstPastThePost.computeFromBallots(
diff --git a/src/methods/index.ts b/src/methods/index.ts
index 8ead42d..0b31afb 100644
--- a/src/methods/index.ts
+++ b/src/methods/index.ts
@@ -1,5 +1,6 @@
 import { VotingSystem } from '../types'
 import { approbation } from './approbation'
+import { baldwin } from './baldwin'
 import { borda } from './borda'
 import { coombs } from './coombs'
 import { copeland } from './copeland'
@@ -8,6 +9,7 @@ import { instantRunoff } from './instant-runoff'
 import { kemeny } from './kemeny'
 import { maximalLotteries } from './maximal-lotteries'
 import { minimax } from './minimax'
+import { nanson } from './nanson'
 import { rankedPairs } from './ranked-pairs'
 import { randomizedCondorcet } from './randomized-condorcet'
 import { schulze } from './schulze'
@@ -15,6 +17,7 @@ import { twoRoundRunoff } from './two-round-runoff'
 
 export const methods = {
   [VotingSystem.Approbation]: approbation,
+  [VotingSystem.Baldwin]: baldwin,
   [VotingSystem.Borda]: borda,
   [VotingSystem.Coombs]: coombs,
   [VotingSystem.Copeland]: copeland,
@@ -23,8 +26,27 @@ export const methods = {
   [VotingSystem.Kemeny]: kemeny,
   [VotingSystem.MaximalLotteries]: maximalLotteries,
   [VotingSystem.Minimax]: minimax,
+  [VotingSystem.NANSON]: nanson,
   [VotingSystem.RankedPairs]: rankedPairs,
   [VotingSystem.RandomizedCondorcet]: randomizedCondorcet,
   [VotingSystem.Schulze]: schulze,
   [VotingSystem.TwoRoundRunoff]: twoRoundRunoff,
 }
+
+export {
+  approbation,
+  baldwin,
+  borda,
+  coombs,
+  copeland,
+  firstPastThePost,
+  instantRunoff,
+  kemeny,
+  maximalLotteries,
+  minimax,
+  nanson,
+  rankedPairs,
+  randomizedCondorcet,
+  schulze,
+  twoRoundRunoff,
+}
diff --git a/src/methods/nanson/index.ts b/src/methods/nanson/index.ts
new file mode 100644
index 0000000..30d8ee5
--- /dev/null
+++ b/src/methods/nanson/index.ts
@@ -0,0 +1,33 @@
+import sum from 'lodash/sum'
+import difference from 'lodash/difference'
+import {
+  SystemUsingRankings,
+  ScoreObject,
+  VotingSystem,
+  Ballot,
+} from '../../types'
+import { borda } from '../borda'
+
+export const nanson: SystemUsingRankings = {
+  type: VotingSystem.NANSON,
+  computeFromBallots(ballots: Ballot[], candidates: string[]): ScoreObject {
+    const score: ScoreObject = {}
+    let remainingCandidates = candidates
+    let points = 0
+    while (remainingCandidates.length > 0) {
+      const bordaScores = borda.computeFromBallots(ballots, remainingCandidates)
+      const scores = Object.values(bordaScores)
+      const avg = sum(scores) / scores.length
+      const losers = remainingCandidates.filter((c) => bordaScores[c] <= avg)
+      let maxPoints = points + 1
+      for (const loser of losers) {
+        const p = points + bordaScores[loser] + 1
+        score[loser] = p
+        if (p > maxPoints) maxPoints = p
+      }
+      remainingCandidates = difference(remainingCandidates, losers)
+      points = maxPoints
+    }
+    return score
+  },
+}
diff --git a/src/types.ts b/src/types.ts
index ae5739b..5361cfb 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -8,6 +8,7 @@ export type ScoreObject = { [candidate: string]: number }
 
 export enum VotingSystem {
   Approbation = 'APPROBATION',
+  Baldwin = 'BALDWIN',
   Borda = 'BORDA',
   Coombs = 'COOMBS',
   Copeland = 'COPELAND',
@@ -16,6 +17,7 @@ export enum VotingSystem {
   InstantRunoff = 'INSTANT_RUNOFF',
   MaximalLotteries = 'MAXIMAL_LOTTERIES',
   Minimax = 'MINIMAX',
+  NANSON = 'NANSON',
   RandomizedCondorcet = 'RANDOMIZED_CONDORCET',
   RankedPairs = 'RANKED_PAIRS',
   Schulze = 'SCHULZE',
diff --git a/src/votes.test.ts b/src/votes.test.ts
index 0cdf297..56c15a6 100644
--- a/src/votes.test.ts
+++ b/src/votes.test.ts
@@ -1,17 +1,23 @@
 import { methods, SystemUsingMatrix, SystemUsingRankings, utils } from './votes'
 import { VotingSystem } from './types'
 import { matrixFromBallots } from './utils'
-import { approbation } from './methods/approbation'
-import { borda } from './methods/borda'
-import { copeland } from './methods/copeland'
-import { firstPastThePost } from './methods/first-past-the-post'
-import { instantRunoff } from './methods/instant-runoff'
-import { kemeny } from './methods/kemeny'
-import { maximalLotteries } from './methods/maximal-lotteries'
-import { minimax } from './methods/minimax'
-import { rankedPairs } from './methods/ranked-pairs'
-import { schulze } from './methods/schulze'
-import { twoRoundRunoff } from './methods/two-round-runoff'
+import {
+  approbation,
+  baldwin,
+  borda,
+  coombs,
+  copeland,
+  firstPastThePost,
+  instantRunoff,
+  kemeny,
+  maximalLotteries,
+  minimax,
+  nanson,
+  randomizedCondorcet,
+  rankedPairs,
+  schulze,
+  twoRoundRunoff,
+} from './votes'
 import { abcde, balinski, dummyProfile, sW } from './test/testUtils'
 
 describe('Test all methods', () => {
@@ -39,10 +45,12 @@ describe('Test all methods', () => {
     }, {})
     expect(allResults).toStrictEqual({
       APPROBATION: ['a'],
+      BALDWIN: ['a'],
       BORDA: ['a'],
       COOMBS: ['a'],
       FIRST_PAST_THE_POST: ['a'],
       INSTANT_RUNOFF: ['a'],
+      NANSON: ['a'],
       TWO_ROUND_RUNOFF: ['a'],
     })
     Object.values(allResults).forEach((v) => expect(v).toStrictEqual(['a']))
@@ -82,6 +90,15 @@ describe('Test all methods', () => {
       e: 22,
     })
   })
+  it('votes with baldwin', () => {
+    expect(baldwin.computeFromBallots(balinski, abcde)).toStrictEqual({
+      a: 0,
+      b: 3,
+      c: 4,
+      d: 2,
+      e: 1,
+    })
+  })
   it('votes with borda', () => {
     expect(borda.computeFromBallots(balinski, abcde)).toStrictEqual({
       a: 135,
@@ -91,6 +108,15 @@ describe('Test all methods', () => {
       e: 182,
     })
   })
+  it('votes with coombs', () => {
+    expect(coombs.computeFromBallots(balinski, abcde)).toStrictEqual({
+      a: 0,
+      b: 3,
+      c: 4,
+      d: 2,
+      e: 1,
+    })
+  })
   it('votes with FPTP', () => {
     expect(firstPastThePost.computeFromBallots(balinski, abcde)).toStrictEqual({
       a: 33,
@@ -109,6 +135,15 @@ describe('Test all methods', () => {
       e: 30,
     })
   })
+  it('votes with instant nanson', () => {
+    expect(nanson.computeFromBallots(balinski, abcde)).toStrictEqual({
+      a: 136,
+      b: 243,
+      c: 244,
+      d: 193,
+      e: 183,
+    })
+  })
   it('votes with two-round runoff', () => {
     expect(twoRoundRunoff.computeFromBallots(balinski, abcde)).toStrictEqual({
       a: 36,
@@ -140,6 +175,17 @@ describe('Test all methods', () => {
       e: 1,
     })
   })
+  it('votes with randomizedCondorcet', () => {
+    expect(
+      randomizedCondorcet.computeFromMatrix(matrixFromBallots(sW, abcde)),
+    ).toStrictEqual({
+      a: 0.3333333333333333,
+      b: 0,
+      c: 0.3333333333333333,
+      d: 0,
+      e: 0.3333333333333333,
+    })
+  })
   it('votes with schulze', () => {
     expect(
       schulze.computeFromMatrix(matrixFromBallots(sW, abcde)),
diff --git a/src/votes.ts b/src/votes.ts
index 7d35a1f..5ee3792 100644
--- a/src/votes.ts
+++ b/src/votes.ts
@@ -1,4 +1,21 @@
-import { methods } from './methods'
+import {
+  approbation,
+  baldwin,
+  borda,
+  coombs,
+  copeland,
+  firstPastThePost,
+  instantRunoff,
+  kemeny,
+  maximalLotteries,
+  minimax,
+  nanson,
+  rankedPairs,
+  randomizedCondorcet,
+  schulze,
+  twoRoundRunoff,
+  methods,
+} from './methods'
 import {
   System,
   VotingSystem,
@@ -11,13 +28,32 @@ import {
 import * as utils from './utils'
 
 export {
-  methods,
+  // enum
   VotingSystem,
+  // All methods:
+  methods,
+  approbation,
+  baldwin,
+  borda,
+  coombs,
+  copeland,
+  firstPastThePost,
+  instantRunoff,
+  kemeny,
+  maximalLotteries,
+  minimax,
+  nanson,
+  rankedPairs,
+  randomizedCondorcet,
+  schulze,
+  twoRoundRunoff,
+  // utils
+  utils,
+  // types
   System,
   SystemUsingRankings,
   SystemUsingMatrix,
   Matrix,
   ScoreObject,
   Ballot,
-  utils,
 }
diff --git a/typedoc.js b/typedoc.js
index 9996f13..b0b5078 100644
--- a/typedoc.js
+++ b/typedoc.js
@@ -2,8 +2,6 @@ module.exports = {
   out: './docs',
   includes: './src',
   exclude: ['**/*.test.ts', '**/test/**/*'],
-  mode: 'file',
   excludeExternals: true,
-  excludeNotExported: true,
   excludePrivate: true,
 }
diff --git a/yarn.lock b/yarn.lock
index 91d75f3..d8beb08 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1560,10 +1560,10 @@
     jest-diff "^26.0.0"
     pretty-format "^26.0.0"
 
-"@types/jest@^26.0.19":
-  version "26.0.19"
-  resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.19.tgz#e6fa1e3def5842ec85045bd5210e9bb8289de790"
-  integrity sha512-jqHoirTG61fee6v6rwbnEuKhpSKih0tuhqeFbCmMmErhtu3BYlOZaXWjffgOstMM4S/3iQD31lI5bGLTrs97yQ==
+"@types/jest@^26.0.20":
+  version "26.0.20"
+  resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.20.tgz#cd2f2702ecf69e86b586e1f5223a60e454056307"
+  integrity sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA==
   dependencies:
     jest-diff "^26.0.0"
     pretty-format "^26.0.0"
@@ -1573,10 +1573,10 @@
   resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.6.tgz#f4c7ec43e81b319a9815115031709f26987891f0"
   integrity sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==
 
-"@types/lodash@^4.14.165":
-  version "4.14.165"
-  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.165.tgz#74d55d947452e2de0742bad65270433b63a8c30f"
-  integrity sha512-tjSSOTHhI5mCHTy/OOXYIhi2Wt1qcbHmuXD1Ha7q70CgI/I71afO4XtLb/cVexki1oVYchpul/TOuu3Arcdxrg==
+"@types/lodash@^4.14.167":
+  version "4.14.167"
+  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.167.tgz#ce7d78553e3c886d4ea643c37ec7edc20f16765e"
+  integrity sha512-w7tQPjARrvdeBkX/Rwg95S592JwxqOjmms3zWQ0XZgSyxSLdzWaYH3vErBhdVS/lRBX7F8aBYcYJYTr5TMGOzw==
 
 "@types/minimist@^1.2.0":
   version "1.2.0"
@@ -1588,10 +1588,10 @@
   resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.6.tgz#146d3da57b3c636cc0d1769396ce1cfa8991147f"
   integrity sha512-6QlRuqsQ/Ox/aJEQWBEJG7A9+u7oSYl3mem/K8IzxXG/kAGbV1YPD9Bg9Zw3vyxC/YP+zONKwy8hGkSt1jxFMw==
 
-"@types/node@^14.14.14":
-  version "14.14.14"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.14.tgz#f7fd5f3cc8521301119f63910f0fb965c7d761ae"
-  integrity sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ==
+"@types/node@^14.14.20":
+  version "14.14.20"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.20.tgz#f7974863edd21d1f8a494a73e8e2b3658615c340"
+  integrity sha512-Y93R97Ouif9JEOWPIUyU+eyIdyRqQR0I8Ez1dzku4hDx34NWh4HbtIc3WNzwB1Y9ULvNGeu5B8h8bVL5cAk4/A==
 
 "@types/normalize-package-data@^2.4.0":
   version "2.4.0"
@@ -1637,61 +1637,62 @@
   dependencies:
     "@types/yargs-parser" "*"
 
-"@typescript-eslint/eslint-plugin@^4.11.0":
-  version "4.11.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.11.0.tgz#bc6c1e4175c0cf42083da4314f7931ad12f731cc"
-  integrity sha512-x4arJMXBxyD6aBXLm3W7mSDZRiABzy+2PCLJbL7OPqlp53VXhaA1HKK7R2rTee5OlRhnUgnp8lZyVIqjnyPT6g==
+"@typescript-eslint/eslint-plugin@^4.13.0":
+  version "4.13.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.13.0.tgz#5f580ea520fa46442deb82c038460c3dd3524bb6"
+  integrity sha512-ygqDUm+BUPvrr0jrXqoteMqmIaZ/bixYOc3A4BRwzEPTZPi6E+n44rzNZWaB0YvtukgP+aoj0i/fyx7FkM2p1w==
   dependencies:
-    "@typescript-eslint/experimental-utils" "4.11.0"
-    "@typescript-eslint/scope-manager" "4.11.0"
+    "@typescript-eslint/experimental-utils" "4.13.0"
+    "@typescript-eslint/scope-manager" "4.13.0"
     debug "^4.1.1"
     functional-red-black-tree "^1.0.1"
+    lodash "^4.17.15"
     regexpp "^3.0.0"
     semver "^7.3.2"
     tsutils "^3.17.1"
 
-"@typescript-eslint/experimental-utils@4.11.0":
-  version "4.11.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.11.0.tgz#d1a47cc6cfe1c080ce4ead79267574b9881a1565"
-  integrity sha512-1VC6mSbYwl1FguKt8OgPs8xxaJgtqFpjY/UzUYDBKq4pfQ5lBvN2WVeqYkzf7evW42axUHYl2jm9tNyFsb8oLg==
+"@typescript-eslint/experimental-utils@4.13.0":
+  version "4.13.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.13.0.tgz#9dc9ab375d65603b43d938a0786190a0c72be44e"
+  integrity sha512-/ZsuWmqagOzNkx30VWYV3MNB/Re/CGv/7EzlqZo5RegBN8tMuPaBgNK6vPBCQA8tcYrbsrTdbx3ixMRRKEEGVw==
   dependencies:
     "@types/json-schema" "^7.0.3"
-    "@typescript-eslint/scope-manager" "4.11.0"
-    "@typescript-eslint/types" "4.11.0"
-    "@typescript-eslint/typescript-estree" "4.11.0"
+    "@typescript-eslint/scope-manager" "4.13.0"
+    "@typescript-eslint/types" "4.13.0"
+    "@typescript-eslint/typescript-estree" "4.13.0"
     eslint-scope "^5.0.0"
     eslint-utils "^2.0.0"
 
-"@typescript-eslint/parser@^4.11.0":
-  version "4.11.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.11.0.tgz#1dd3d7e42708c10ce9f3aa64c63c0ab99868b4e2"
-  integrity sha512-NBTtKCC7ZtuxEV5CrHUO4Pg2s784pvavc3cnz6V+oJvVbK4tH9135f/RBP6eUA2KHiFKAollSrgSctQGmHbqJQ==
+"@typescript-eslint/parser@^4.13.0":
+  version "4.13.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.13.0.tgz#c413d640ea66120cfcc37f891e8cb3fd1c9d247d"
+  integrity sha512-KO0J5SRF08pMXzq9+abyHnaGQgUJZ3Z3ax+pmqz9vl81JxmTTOUfQmq7/4awVfq09b6C4owNlOgOwp61pYRBSg==
   dependencies:
-    "@typescript-eslint/scope-manager" "4.11.0"
-    "@typescript-eslint/types" "4.11.0"
-    "@typescript-eslint/typescript-estree" "4.11.0"
+    "@typescript-eslint/scope-manager" "4.13.0"
+    "@typescript-eslint/types" "4.13.0"
+    "@typescript-eslint/typescript-estree" "4.13.0"
     debug "^4.1.1"
 
-"@typescript-eslint/scope-manager@4.11.0":
-  version "4.11.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.11.0.tgz#2d906537db8a3a946721699e4fc0833810490254"
-  integrity sha512-6VSTm/4vC2dHM3ySDW9Kl48en+yLNfVV6LECU8jodBHQOhO8adAVizaZ1fV0QGZnLQjQ/y0aBj5/KXPp2hBTjA==
+"@typescript-eslint/scope-manager@4.13.0":
+  version "4.13.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.13.0.tgz#5b45912a9aa26b29603d8fa28f5e09088b947141"
+  integrity sha512-UpK7YLG2JlTp/9G4CHe7GxOwd93RBf3aHO5L+pfjIrhtBvZjHKbMhBXTIQNkbz7HZ9XOe++yKrXutYm5KmjWgQ==
   dependencies:
-    "@typescript-eslint/types" "4.11.0"
-    "@typescript-eslint/visitor-keys" "4.11.0"
+    "@typescript-eslint/types" "4.13.0"
+    "@typescript-eslint/visitor-keys" "4.13.0"
 
-"@typescript-eslint/types@4.11.0":
-  version "4.11.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.11.0.tgz#86cf95e7eac4ccfd183f9fcf1480cece7caf4ca4"
-  integrity sha512-XXOdt/NPX++txOQHM1kUMgJUS43KSlXGdR/aDyEwuAEETwuPt02Nc7v+s57PzuSqMbNLclblQdv3YcWOdXhQ7g==
+"@typescript-eslint/types@4.13.0":
+  version "4.13.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.13.0.tgz#6a7c6015a59a08fbd70daa8c83dfff86250502f8"
+  integrity sha512-/+aPaq163oX+ObOG00M0t9tKkOgdv9lq0IQv/y4SqGkAXmhFmCfgsELV7kOCTb2vVU5VOmVwXBXJTDr353C1rQ==
 
-"@typescript-eslint/typescript-estree@4.11.0":
-  version "4.11.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.11.0.tgz#1144d145841e5987d61c4c845442a24b24165a4b"
-  integrity sha512-eA6sT5dE5RHAFhtcC+b5WDlUIGwnO9b0yrfGa1mIOIAjqwSQCpXbLiFmKTdRbQN/xH2EZkGqqLDrKUuYOZ0+Hg==
+"@typescript-eslint/typescript-estree@4.13.0":
+  version "4.13.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.13.0.tgz#cf6e2207c7d760f5dfd8d18051428fadfc37b45e"
+  integrity sha512-9A0/DFZZLlGXn5XA349dWQFwPZxcyYyCFX5X88nWs2uachRDwGeyPz46oTsm9ZJE66EALvEns1lvBwa4d9QxMg==
   dependencies:
-    "@typescript-eslint/types" "4.11.0"
-    "@typescript-eslint/visitor-keys" "4.11.0"
+    "@typescript-eslint/types" "4.13.0"
+    "@typescript-eslint/visitor-keys" "4.13.0"
     debug "^4.1.1"
     globby "^11.0.1"
     is-glob "^4.0.1"
@@ -1699,12 +1700,12 @@
     semver "^7.3.2"
     tsutils "^3.17.1"
 
-"@typescript-eslint/visitor-keys@4.11.0":
-  version "4.11.0"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.11.0.tgz#906669a50f06aa744378bb84c7d5c4fdbc5b7d51"
-  integrity sha512-tRYKyY0i7cMk6v4UIOCjl1LhuepC/pc6adQqJk4Is3YcC6k46HvsV9Wl7vQoLbm9qADgeujiT7KdLrylvFIQ+A==
+"@typescript-eslint/visitor-keys@4.13.0":
+  version "4.13.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.13.0.tgz#9acb1772d3b3183182b6540d3734143dce9476fe"
+  integrity sha512-6RoxWK05PAibukE7jElqAtNMq+RWZyqJ6Q/GdIxaiUj2Ept8jh8+FUVlbq9WxMYxkmEOPvCE5cRSyupMpwW31g==
   dependencies:
-    "@typescript-eslint/types" "4.11.0"
+    "@typescript-eslint/types" "4.13.0"
     eslint-visitor-keys "^2.0.0"
 
 JSONStream@^1.0.4, JSONStream@^1.3.4, JSONStream@^1.3.5:
@@ -3346,10 +3347,10 @@ eslint-config-prettier@^7.1.0:
   resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-7.1.0.tgz#5402eb559aa94b894effd6bddfa0b1ca051c858f"
   integrity sha512-9sm5/PxaFG7qNJvJzTROMM1Bk1ozXVTKI0buKOyb0Bsr1hrwi0H/TzxF/COtf1uxikIK8SwhX7K6zg78jAzbeA==
 
-eslint-plugin-prettier@^3.3.0:
-  version "3.3.0"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.0.tgz#61e295349a65688ffac0b7808ef0a8244bdd8d40"
-  integrity sha512-tMTwO8iUWlSRZIwS9k7/E4vrTsfvsrcM5p1eftyuqWH25nKsz/o6/54I7jwQ/3zobISyC7wMy9ZsFwgTxOcOpQ==
+eslint-plugin-prettier@^3.3.1:
+  version "3.3.1"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz#7079cfa2497078905011e6f82e8dd8453d1371b7"
+  integrity sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==
   dependencies:
     prettier-linter-helpers "^1.0.0"
 
@@ -3378,10 +3379,10 @@ eslint-visitor-keys@^2.0.0:
   resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
   integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
 
-eslint@^7.16.0:
-  version "7.16.0"
-  resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.16.0.tgz#a761605bf9a7b32d24bb7cde59aeb0fd76f06092"
-  integrity sha512-iVWPS785RuDA4dWuhhgXTNrGxHHK3a8HLSMBgbbU59ruJDubUraXN8N5rn7kb8tG6sjg74eE0RA3YWT51eusEw==
+eslint@^7.17.0:
+  version "7.17.0"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.17.0.tgz#4ccda5bf12572ad3bf760e6f195886f50569adb0"
+  integrity sha512-zJk08MiBgwuGoxes5sSQhOtibZ75pz0J35XTRlZOk9xMffhpA9BTbQZxoXZzOl5zMbleShbGwtw+1kGferfFwQ==
   dependencies:
     "@babel/code-frame" "^7.0.0"
     "@eslint/eslintrc" "^0.2.2"
@@ -3779,12 +3780,12 @@ find-up@^5.0.0:
     locate-path "^6.0.0"
     path-exists "^4.0.0"
 
-find-versions@^3.0.0, find-versions@^3.2.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-3.2.0.tgz#10297f98030a786829681690545ef659ed1d254e"
-  integrity sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==
+find-versions@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-4.0.0.tgz#3c57e573bf97769b8cb8df16934b627915da4965"
+  integrity sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==
   dependencies:
-    semver-regex "^2.0.0"
+    semver-regex "^3.1.2"
 
 findup-sync@^3.0.0:
   version "3.0.0"
@@ -4268,9 +4269,9 @@ has@^1.0.3:
     function-bind "^1.1.1"
 
 highlight.js@^10.2.0:
-  version "10.4.1"
-  resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.4.1.tgz#d48fbcf4a9971c4361b3f95f302747afe19dbad0"
-  integrity sha512-yR5lWvNz7c85OhVAEAeFhVCc/GV4C30Fjzc/rCP0aCWzc1UUOPUk55dK/qdwTZHBvMZo+eZ2jpk62ndX/xMFlg==
+  version "10.5.0"
+  resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.5.0.tgz#3f09fede6a865757378f2d9ebdcbc15ba268f98f"
+  integrity sha512-xTmvd9HiIHR6L53TMC7TKolEj65zG1XU+Onr8oi86mYa+nLcIbxTTWkpW7CsEwv/vK7u1zb8alZIMLDqqN6KTw==
 
 homedir-polyfill@^1.0.1:
   version "1.0.3"
@@ -4372,18 +4373,18 @@ humanize-ms@^1.2.1:
   dependencies:
     ms "^2.0.0"
 
-husky@^4.3.6:
-  version "4.3.6"
-  resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.6.tgz#ebd9dd8b9324aa851f1587318db4cccb7665a13c"
-  integrity sha512-o6UjVI8xtlWRL5395iWq9LKDyp/9TE7XMOTvIpEVzW638UcGxTmV5cfel6fsk/jbZSTlvfGVJf2svFtybcIZag==
+husky@^4.3.7:
+  version "4.3.7"
+  resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.7.tgz#ca47bbe6213c1aa8b16bbd504530d9600de91e88"
+  integrity sha512-0fQlcCDq/xypoyYSJvEuzbDPHFf8ZF9IXKJxlrnvxABTSzK1VPT2RKYQKrcgJ+YD39swgoB6sbzywUqFxUiqjw==
   dependencies:
     chalk "^4.0.0"
     ci-info "^2.0.0"
     compare-versions "^3.6.0"
     cosmiconfig "^7.0.0"
-    find-versions "^3.2.0"
+    find-versions "^4.0.0"
     opencollective-postinstall "^2.0.2"
-    pkg-dir "^4.2.0"
+    pkg-dir "^5.0.0"
     please-upgrade-node "^3.2.0"
     slash "^3.0.0"
     which-pm-runs "^1.0.0"
@@ -6051,11 +6052,16 @@ marked-terminal@^4.0.0:
     node-emoji "^1.10.0"
     supports-hyperlinks "^2.1.0"
 
-marked@^1.0.0, marked@^1.1.1:
+marked@^1.0.0:
   version "1.2.2"
   resolved "https://registry.yarnpkg.com/marked/-/marked-1.2.2.tgz#5d77ffb789c4cb0ae828bfe76250f7140b123f70"
   integrity sha512-5jjKHVl/FPo0Z6ocP3zYhKiJLzkwJAw4CZoLjv57FkvbUuwOX4LIBBGGcXjAY6ATcd1q9B8UTj5T9Umauj0QYQ==
 
+marked@^1.1.1:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/marked/-/marked-1.2.7.tgz#6e14b595581d2319cdcf033a24caaf41455a01fb"
+  integrity sha512-No11hFYcXr/zkBvL6qFmAp1z6BKY3zqLMHny/JN/ey+al7qwCM2+CMBL9BOgqMxZU36fz4cCWfn2poWIf7QRXA==
+
 meant@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/meant/-/meant-1.0.2.tgz#5d0c78310a3d8ae1408a16be0fe0bd42a969f560"
@@ -7181,6 +7187,13 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0:
   dependencies:
     find-up "^4.0.0"
 
+pkg-dir@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760"
+  integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==
+  dependencies:
+    find-up "^5.0.0"
+
 please-upgrade-node@^3.2.0:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942"
@@ -7825,10 +7838,10 @@ rollup-plugin-typescript2@^0.29.0:
     resolve "1.17.0"
     tslib "2.0.1"
 
-rollup@^2.35.1:
-  version "2.35.1"
-  resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.35.1.tgz#e6bc8d10893556a638066f89e8c97f422d03968c"
-  integrity sha512-q5KxEyWpprAIcainhVy6HfRttD9kutQpHbeqDTWnqAFNJotiojetK6uqmcydNMymBEtC4I8bCYR+J3mTMqeaUA==
+rollup@^2.36.1:
+  version "2.36.1"
+  resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.36.1.tgz#2174f0c25c7b400d57b05628d0e732c7ae8d2178"
+  integrity sha512-eAfqho8dyzuVvrGqpR0ITgEdq0zG2QJeWYh+HeuTbpcaXk8vNFc48B7bJa1xYosTCKx0CuW+447oQOW8HgBIZQ==
   optionalDependencies:
     fsevents "~2.1.2"
 
@@ -7905,10 +7918,10 @@ saxes@^5.0.0:
   dependencies:
     xmlchars "^2.2.0"
 
-semantic-release@^17.3.0:
-  version "17.3.0"
-  resolved "https://registry.yarnpkg.com/semantic-release/-/semantic-release-17.3.0.tgz#121252b5bb6acc1048d7657111173b03d47502c5"
-  integrity sha512-enhDayMZRP4nWcWAMBFHHB7THRaIcRdUAZv3lxd65pXs2ttzay7IeCvRRrGayRWExtnY0ulwRz5Ycp88Dv/UeQ==
+semantic-release@^17.3.1:
+  version "17.3.1"
+  resolved "https://registry.yarnpkg.com/semantic-release/-/semantic-release-17.3.1.tgz#8904ef1ca8e704394de0e204b284f6c252284da4"
+  integrity sha512-NSdxvnBTklrRBYRexVUx44Hri9sTu9b8x+1HfWDGIWemDTFQfWOTbT1N3oy5l8WcZHodhRvtyI7gm50SfAa3Fg==
   dependencies:
     "@semantic-release/commit-analyzer" "^8.0.0"
     "@semantic-release/error" "^2.2.0"
@@ -7921,7 +7934,7 @@ semantic-release@^17.3.0:
     env-ci "^5.0.0"
     execa "^4.0.0"
     figures "^3.0.0"
-    find-versions "^3.0.0"
+    find-versions "^4.0.0"
     get-stream "^5.0.0"
     git-log-parser "^1.2.0"
     hook-std "^2.0.0"
@@ -7958,10 +7971,10 @@ semver-diff@^3.1.1:
   dependencies:
     semver "^6.3.0"
 
-semver-regex@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-2.0.0.tgz#a93c2c5844539a770233379107b38c7b4ac9d338"
-  integrity sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==
+semver-regex@^3.1.2:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-3.1.2.tgz#34b4c0d361eef262e07199dbef316d0f2ab11807"
+  integrity sha512-bXWyL6EAKOJa81XG1OZ/Yyuq+oT0b2YLlxx7c+mrdYPaPbnj6WgVULXhinMIeZGufuUBu/eVRqXEhiv4imfwxA==
 
 "semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", "semver@^2.3.0 || 3.x || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.1:
   version "5.7.1"