Browse Source

code of osm2pdf v1 rewritten in typescript and refactored

mrkvon 3 years ago
parent
commit
414481f37c
14 changed files with 763 additions and 17 deletions
  1. 5
    0
      .gitignore
  2. 23
    2
      package.json
  3. 35
    0
      src/help.ts
  4. 0
    1
      src/index.ts
  5. 5
    0
      src/log.ts
  6. 45
    0
      src/map.ts
  7. 1
    0
      src/minimist.d.ts
  8. 39
    0
      src/osm.ts
  9. 80
    0
      src/pdf.ts
  10. 88
    0
      src/route.ts
  11. 58
    0
      src/run.ts
  12. 3
    0
      src/utils.ts
  13. 5
    1
      tsconfig.json
  14. 376
    13
      yarn.lock

+ 5
- 0
.gitignore View File

@@ -1,2 +1,7 @@
1 1
 node_modules
2 2
 /lib
3
+*.pdf
4
+*.xml
5
+*.gpx
6
+yarn-error.log
7
+/tmp*

+ 23
- 2
package.json View File

@@ -9,6 +9,7 @@
9 9
   },
10 10
   "homepage": "https://git.mrkvon.org/mrkvon/osm2pdf",
11 11
   "main": "lib/index.js",
12
+  "bin": "lib/run.js",
12 13
   "types": "lib/index.d.ts",
13 14
   "license": "MIT",
14 15
   "private": false,
@@ -30,13 +31,33 @@
30 31
     "prepublishOnly": "yarn test && yarn lint",
31 32
     "preversion": "yarn lint",
32 33
     "version": "yarn format && git add -A src",
33
-    "postversion" : "git push && git push --tags"
34
+    "postversion": "git push && git push --tags",
35
+    "prestart": "yarn build",
36
+    "start": "node lib/run.js"
34 37
   },
35
-  "files": ["lib/**/*"],
38
+  "files": [
39
+    "lib/**/*"
40
+  ],
36 41
   "devDependencies": {
42
+    "@types/axios": "^0.14.0",
43
+    "@types/fs-extra": "^8.0.1",
44
+    "@types/gm": "^1.18.7",
45
+    "@types/jest": "^24.9.1",
46
+    "@types/minimist": "^1.2.0",
47
+    "@types/node": "^13.1.8",
48
+    "@types/xml2js": "^0.4.5",
49
+    "jest": "^25.1.0",
37 50
     "prettier": "^1.19.1",
51
+    "ts-jest": "^25.0.0",
38 52
     "tslint": "^6.0.0",
39 53
     "tslint-config-prettier": "^1.18.0",
40 54
     "typescript": "^3.7.5"
55
+  },
56
+  "dependencies": {
57
+    "axios": "^0.19.2",
58
+    "fs-extra": "^8.1.0",
59
+    "gm": "^1.23.1",
60
+    "merge-img": "^2.1.3",
61
+    "minimist": "^1.2.0"
41 62
   }
42 63
 }

+ 35
- 0
src/help.ts View File

@@ -0,0 +1,35 @@
1
+const HELP = `
2
+Export OpenStreetMap to pdf
3
+
4
+Usage:
5
+osm2pdf [options]
6
+
7
+Options:
8
+-h, --help                print this page
9
+--route                   (optional) download the route
10
+                          you can download the GPX route file from https://graphhopper.com/maps/
11
+                          find the desired route and click "GPX export" (gpx button)
12
+--input <path/to/gpx>     (with --route option) path to GPX route file
13
+-n, --north <latitude>
14
+-w, --west <longitude>
15
+-s, --south <latitude>
16
+-e, --east <longitude>    latitude or longitude of the desired map boundary (only when --route is not specified)
17
+                          downloads a map within a defined square
18
+--zoom <level>            (optional) map zoom (number); defaults to 12; must be < 17
19
+--sx <integer>            (optional) amount of tiles per page horizontally; defaults to 4
20
+--sy <integer>            (optional) amount of tiles per page vertically; defaults to 5
21
+--output <path/to/output> (optional) the desired name of the exported pdf file
22
+
23
+Examples:
24
+1. Provide map boundaries
25
+
26
+  osm2pdf --zoom=10 --north=15.1 --south=14.9 --east=13.9 --west=13.7
27
+
28
+2. Provide a route in GPX format (can be exported at https://graphhopper.com/maps/)
29
+  
30
+  osm2pdf --route --zoom=15 --input=path/to/some_route.gpx --output=my-route
31
+`;
32
+
33
+export default function help(): void {
34
+  console.log(HELP); // tslint:disable-line:no-console
35
+}

+ 0
- 1
src/index.ts View File

@@ -1 +0,0 @@
1
-export const Greeter = (name: string) => `Hello ${name}`;

+ 5
- 0
src/log.ts View File

@@ -0,0 +1,5 @@
1
+export default function log(...props: string[]): void {
2
+  process.stdout.clearLine(0);
3
+  process.stdout.cursorTo(0);
4
+  process.stdout.write(props.join(' '));
5
+}

+ 45
- 0
src/map.ts View File

@@ -0,0 +1,45 @@
1
+import { lat2tile, lon2tile, getTileSize } from './osm';
2
+import { pages2pdf, Page, PageSize } from './pdf';
3
+
4
+interface Boundaries {
5
+  north: number;
6
+  south: number;
7
+  east: number;
8
+  west: number;
9
+  zoom: number;
10
+}
11
+
12
+// main executable function
13
+export default async function map(boundaries: Boundaries, pageSize: PageSize, output: string) {
14
+  const pages: Page[] = boundaries2pages(boundaries, pageSize);
15
+
16
+  await pages2pdf(pages, output);
17
+}
18
+
19
+function boundaries2pages({ north, west, south, east, zoom }: Boundaries, { sx, sy }: PageSize) {
20
+  const x = lon2tile(west, zoom);
21
+  const y = lat2tile(north, zoom);
22
+
23
+  const { width, height } = getTileSize({ north, west, south, east, zoom });
24
+
25
+  const pagesX = Math.ceil(width / sx);
26
+  const pagesY = Math.ceil(height / sy);
27
+
28
+  console.log('size', pagesX, 'x', pagesY, 'pages'); // tslint:disable-line:no-console
29
+
30
+  const pages: Page[] = [];
31
+
32
+  for (let py = 0; py < pagesY; py++) {
33
+    for (let px = 0; px < pagesX; px++) {
34
+      pages.push({
35
+        x: x + px * sx,
36
+        y: y + py * sy,
37
+        sx,
38
+        sy,
39
+        zoom,
40
+      });
41
+    }
42
+  }
43
+
44
+  return pages;
45
+}

+ 1
- 0
src/minimist.d.ts View File

@@ -0,0 +1 @@
1
+declare module 'merge-img';

+ 39
- 0
src/osm.ts View File

@@ -0,0 +1,39 @@
1
+/**
2
+ * copied from https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#ECMAScript_.28JavaScript.2FActionScript.2C_etc..29
3
+ */
4
+
5
+export function lon2tile(lon: number, zoom: number): number {
6
+  return Math.floor(((lon + 180) / 360) * Math.pow(2, zoom));
7
+}
8
+
9
+export function lat2tile(lat: number, zoom: number) {
10
+  return Math.floor(
11
+    ((1 - Math.log(Math.tan((lat * Math.PI) / 180) + 1 / Math.cos((lat * Math.PI) / 180)) / Math.PI) / 2) *
12
+      Math.pow(2, zoom),
13
+  );
14
+}
15
+
16
+/**
17
+ * Given map edges, count how many tiles does the map consist of
18
+ */
19
+export function getTileSize({
20
+  north,
21
+  west,
22
+  south,
23
+  east,
24
+  zoom,
25
+}: {
26
+  north: number;
27
+  west: number;
28
+  south: number;
29
+  east: number;
30
+  zoom: number;
31
+}): { width: number; height: number } {
32
+  const topTile: number = lat2tile(north, zoom); // eg.lat2tile(34.422, 9);
33
+  const bottomTile: number = lat2tile(south, zoom);
34
+  const leftTile: number = lon2tile(west, zoom);
35
+  const rightTile: number = lon2tile(east, zoom);
36
+  const width: number = Math.abs(leftTile - rightTile) + 1;
37
+  const height: number = Math.abs(topTile - bottomTile) + 1;
38
+  return { width, height };
39
+}

+ 80
- 0
src/pdf.ts View File

@@ -0,0 +1,80 @@
1
+import axios from 'axios';
2
+import mergeImg from 'merge-img';
3
+import gm from 'gm';
4
+import fs from 'fs-extra';
5
+import { pad } from './utils';
6
+import log from './log';
7
+
8
+export interface Tile {
9
+  x: number;
10
+  y: number;
11
+  zoom: number;
12
+}
13
+
14
+export interface PageSize {
15
+  sx: number;
16
+  sy: number;
17
+}
18
+
19
+export interface Page extends Tile, PageSize {}
20
+
21
+async function getTile({ x, y, zoom }: Tile): Promise<Buffer> {
22
+  return Buffer.from(
23
+    (
24
+      await axios.get(`https://tile.openstreetmap.org/${zoom}/${x}/${y}.png`, {
25
+        responseType: 'arraybuffer',
26
+      })
27
+    ).data,
28
+    'binary',
29
+  );
30
+}
31
+
32
+export async function getPage({ x, y, sx, sy, zoom }: Page): Promise<Buffer[][]> {
33
+  const rows: Promise<Buffer[]>[] = [];
34
+  for (let i = 0; i < sx; i++) {
35
+    const row: Promise<Buffer>[] = [];
36
+    for (let j = 0; j < sy; j++) {
37
+      row.push(getTile({ x: x + i, y: y + j, zoom }));
38
+    }
39
+    rows.push(Promise.all(row));
40
+  }
41
+  return await Promise.all(rows);
42
+}
43
+
44
+async function mergeTiles(tiles: Buffer[][]): Promise<any> {
45
+  const row = await Promise.all(tiles.map(column => mergeImg(column, { direction: true })));
46
+  return await mergeImg(row);
47
+}
48
+
49
+async function createPdf(name: string, tmp: string) {
50
+  await new Promise((resolve, reject) => {
51
+    gm(`${tmp}/*.png`).write(`${name}.pdf`, err => {
52
+      if (!err) return resolve();
53
+      if (err) return reject(err);
54
+    });
55
+  });
56
+}
57
+
58
+async function clearTemporary(tmp: string) {
59
+  await fs.remove(tmp);
60
+}
61
+
62
+export async function pages2pdf(pages: Page[], name: string): Promise<void> {
63
+  const tmp = `tmp${Date.now()}`;
64
+  await fs.ensureDir(tmp);
65
+
66
+  for (let i = 0, len = pages.length; i < len; i++) {
67
+    const page = pages[i];
68
+    log('page', `${i + 1}/${pages.length}`);
69
+    const pageTiles = await getPage(page);
70
+    const image = await mergeTiles(pageTiles);
71
+
72
+    await new Promise(resolve => image.write(`${tmp}/${pad(i)}.png`, resolve));
73
+  }
74
+
75
+  await createPdf(name, tmp);
76
+  await clearTemporary(tmp);
77
+
78
+  log();
79
+  console.log(`Finished! Your map was saved to ${name}.pdf`); // tslint:disable-line:no-console
80
+}

+ 88
- 0
src/route.ts View File

@@ -0,0 +1,88 @@
1
+import xml2js from 'xml2js';
2
+import fs from 'fs-extra';
3
+import { promisify } from 'util';
4
+import { lat2tile, lon2tile } from './osm';
5
+import { pages2pdf, Tile, Page, PageSize } from './pdf';
6
+
7
+const parseString = promisify(xml2js.parseString);
8
+
9
+export default async function route(
10
+  { zoom, input }: { zoom: number; input: string },
11
+  pageSize: PageSize,
12
+  output: string,
13
+) {
14
+  // get route
15
+  // tslint:disable-next-line:no-shadowed-variable
16
+  const route = await parseRoute(input);
17
+  // get tile for each route point
18
+  const tiles = route2tiles(route, zoom);
19
+  const pages = tiles2pages(tiles, pageSize);
20
+  await pages2pdf(pages, output);
21
+}
22
+
23
+interface Coordinate {
24
+  lat: number;
25
+  lon: number;
26
+}
27
+
28
+interface StringCoordinate {
29
+  lat: string;
30
+  lon: string;
31
+}
32
+
33
+interface Route {
34
+  gpx: {
35
+    trk: {
36
+      trkseg: {
37
+        trkpt: {
38
+          $: StringCoordinate;
39
+        }[];
40
+      }[];
41
+    }[];
42
+  };
43
+}
44
+
45
+async function parseRoute(file: string): Promise<Coordinate[]> {
46
+  const xml = (await fs.readFile(file)).toString();
47
+  const raw = (await parseString(xml)) as Route;
48
+  return raw.gpx.trk[0].trkseg[0].trkpt.map(({ $: { lat, lon } }) => ({ lat: +lat, lon: +lon }));
49
+}
50
+
51
+// tslint:disable-next-line:no-shadowed-variable
52
+function route2tiles(route: Coordinate[], zoom: number): Tile[] {
53
+  const tiles: Tile[] = [];
54
+  // add tile for each route point
55
+  route.forEach(({ lat, lon }) => {
56
+    const tile: Tile = {
57
+      x: lon2tile(+lon, zoom),
58
+      y: lat2tile(+lat, zoom),
59
+      zoom,
60
+    };
61
+
62
+    const found = tiles.findIndex(({ x, y }) => x === tile.x && y === tile.y);
63
+    if (found === -1) tiles.push(tile);
64
+  });
65
+
66
+  return tiles;
67
+}
68
+
69
+function tiles2pages(tiles: Tile[], { sx, sy }: PageSize): Page[] {
70
+  const pages: Page[] = [];
71
+  tiles.forEach(({ x, y, zoom }) => {
72
+    const page: Page = {
73
+      x: Math.floor(x / sx) * sx,
74
+      y: Math.floor(y / sy) * sy,
75
+      sx,
76
+      sy,
77
+      zoom,
78
+    };
79
+
80
+    // tslint:disable-next-line:no-shadowed-variable
81
+    const found = pages.findIndex(({ x, y }) => x === page.x && y === page.y);
82
+    if (found === -1) {
83
+      pages.push(page);
84
+    }
85
+  });
86
+
87
+  return pages;
88
+}

+ 58
- 0
src/run.ts View File

@@ -0,0 +1,58 @@
1
+#!/bin/sh
2
+':'; // # comment; exec /usr/bin/env node --experimental-modules "$0" "$@"
3
+
4
+// executable for routes
5
+//
6
+// if option route is specified, download a route
7
+// e.g. --route --zoom=15 --input=route.xml --output=route --sx=4 --sy=5
8
+//
9
+// otherwise download a map (default)
10
+// e.g. --zoom=15 --north= --south= --east= --west= --output=map --sx=4 --sy=5
11
+//
12
+
13
+import minimist from 'minimist';
14
+import map from './map';
15
+import route from './route';
16
+import help from './help';
17
+
18
+(async () => {
19
+  const argv = minimist(process.argv.slice(2));
20
+
21
+  if (argv.h || argv.help) {
22
+    help();
23
+    return;
24
+  }
25
+
26
+  const zoom = Number(argv.zoom || 12);
27
+
28
+  if (zoom >= 17) {
29
+    const SORRY = 'Sorry, OSM Tile Usage Policy (https://operations.osmfoundation.org/policies/tiles/) forbids downloading tiles with zoom 17 and higher.';
30
+    console.log(SORRY); // tslint:disable-line:no-console
31
+    return;
32
+  }
33
+
34
+  const sx = Number(argv.sx || 4);
35
+  const sy = Number(argv.sy || 5);
36
+  const output = argv.output;
37
+
38
+  if (argv.route) {
39
+    const input = argv.input;
40
+
41
+    if (!input) return help();
42
+
43
+    await route({ zoom, input }, { sx, sy }, output || 'route');
44
+  } else {
45
+    if (!argv.n || !argv.s || !argv.w || !argv.e) return help();
46
+
47
+    const north = Number(argv.n || argv.north);
48
+    const west = Number(argv.w || argv.west);
49
+    const south = Number(argv.s || argv.south);
50
+    const east = Number(argv.e || argv.east);
51
+
52
+    await map(
53
+      { zoom, north, west, south, east },
54
+      { sx, sy },
55
+      output || `map_${north}_${west}_${south}_${east}_${zoom}`,
56
+    );
57
+  }
58
+})();

+ 3
- 0
src/utils.ts View File

@@ -0,0 +1,3 @@
1
+export function pad(num: number, decimals = 5): string {
2
+  return ('0'.repeat(decimals) + num).slice(-decimals);
3
+}

+ 5
- 1
tsconfig.json View File

@@ -4,7 +4,11 @@
4 4
     "module": "commonjs",
5 5
     "declaration": true,
6 6
     "outDir": "./lib",
7
-    "strict": true
7
+    "strict": true,
8
+    "lib": ["dom", "es2020"],
9
+    "esModuleInterop": true,
10
+    "noUnusedParameters": true,
11
+    "noUnusedLocals": true
8 12
   },
9 13
   "include": ["src"],
10 14
   "exclude": ["node_modules", "**/__tests__/*"]

+ 376
- 13
yarn.lock View File

@@ -341,6 +341,13 @@
341 341
   dependencies:
342 342
     type-detect "4.0.8"
343 343
 
344
+"@types/axios@^0.14.0":
345
+  version "0.14.0"
346
+  resolved "https://registry.yarnpkg.com/@types/axios/-/axios-0.14.0.tgz#ec2300fbe7d7dddd7eb9d3abf87999964cafce46"
347
+  integrity sha1-7CMA++fX3d1+udOr+HmZlkyvzkY=
348
+  dependencies:
349
+    axios "*"
350
+
344 351
 "@types/babel__core@^7.1.0":
345 352
   version "7.1.3"
346 353
   resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.3.tgz#e441ea7df63cd080dfcd02ab199e6d16a735fc30"
@@ -379,6 +386,20 @@
379 386
   resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
380 387
   integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
381 388
 
389
+"@types/fs-extra@^8.0.1":
390
+  version "8.0.1"
391
+  resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.0.1.tgz#a2378d6e7e8afea1564e44aafa2e207dadf77686"
392
+  integrity sha512-J00cVDALmi/hJOYsunyT52Hva5TnJeKP5yd1r+mH/ZU0mbYZflR0Z5kw5kITtKTRYMhm1JMClOFYdHnQszEvqw==
393
+  dependencies:
394
+    "@types/node" "*"
395
+
396
+"@types/gm@^1.18.7":
397
+  version "1.18.7"
398
+  resolved "https://registry.yarnpkg.com/@types/gm/-/gm-1.18.7.tgz#03a90d5140496b94c3ce406df62a1ba3defb594a"
399
+  integrity sha512-7gOsCmtTqq3NSKinO2WsYA2uC2RVcW0wlPWXsMDP3rPNoV8Ba+8+OZhfkVstCjar2Yud0RM3jwAIv/h2cLTcSA==
400
+  dependencies:
401
+    "@types/node" "*"
402
+
382 403
 "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
383 404
   version "2.0.1"
384 405
   resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff"
@@ -399,18 +420,35 @@
399 420
     "@types/istanbul-lib-coverage" "*"
400 421
     "@types/istanbul-lib-report" "*"
401 422
 
402
-"@types/jest@^24.9.0":
403
-  version "24.9.0"
404
-  resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.9.0.tgz#78c6991cd1734cf0d390be24875e310bb0a9fb74"
405
-  integrity sha512-dXvuABY9nM1xgsXlOtLQXJKdacxZJd7AtvLsKZ/0b57ruMXDKCOXAC/M75GbllQX6o1pcZ5hAG4JzYy7Z/wM2w==
423
+"@types/jest@^24.9.1":
424
+  version "24.9.1"
425
+  resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.9.1.tgz#02baf9573c78f1b9974a5f36778b366aa77bd534"
426
+  integrity sha512-Fb38HkXSVA4L8fGKEZ6le5bB8r6MRWlOCZbVuWZcmOMSCd2wCYOwN1ibj8daIoV9naq7aaOZjrLCoCMptKU/4Q==
406 427
   dependencies:
407 428
     jest-diff "^24.3.0"
408 429
 
430
+"@types/minimist@^1.2.0":
431
+  version "1.2.0"
432
+  resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6"
433
+  integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=
434
+
435
+"@types/node@*", "@types/node@^13.1.8":
436
+  version "13.1.8"
437
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.8.tgz#1d590429fe8187a02707720ecf38a6fe46ce294b"
438
+  integrity sha512-6XzyyNM9EKQW4HKuzbo/CkOIjn/evtCmsU+MUM1xDfJ+3/rNjBttM1NgN7AOQvN6tP1Sl1D1PIKMreTArnxM9A==
439
+
409 440
 "@types/stack-utils@^1.0.1":
410 441
   version "1.0.1"
411 442
   resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e"
412 443
   integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==
413 444
 
445
+"@types/xml2js@^0.4.5":
446
+  version "0.4.5"
447
+  resolved "https://registry.yarnpkg.com/@types/xml2js/-/xml2js-0.4.5.tgz#d21759b056f282d9c7066f15bbf5c19b908f22fa"
448
+  integrity sha512-yohU3zMn0fkhlape1nxXG2bLEGZRc1FeqF80RoHaYXJN7uibaauXfhzhOJr1Xh36sn+/tx21QAOf07b/xYVk1w==
449
+  dependencies:
450
+    "@types/node" "*"
451
+
414 452
 "@types/yargs-parser@*":
415 453
   version "15.0.0"
416 454
   resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d"
@@ -543,6 +581,16 @@ array-equal@^1.0.0:
543 581
   resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
544 582
   integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=
545 583
 
584
+array-parallel@~0.1.3:
585
+  version "0.1.3"
586
+  resolved "https://registry.yarnpkg.com/array-parallel/-/array-parallel-0.1.3.tgz#8f785308926ed5aa478c47e64d1b334b6c0c947d"
587
+  integrity sha1-j3hTCJJu1apHjEfmTRszS2wMlH0=
588
+
589
+array-series@~0.1.5:
590
+  version "0.1.5"
591
+  resolved "https://registry.yarnpkg.com/array-series/-/array-series-0.1.5.tgz#df5d37bfc5c2ef0755e2aa4f92feae7d4b5a972f"
592
+  integrity sha1-3103v8XC7wdV4qpPkv6ufUtaly8=
593
+
546 594
 array-unique@^0.3.2:
547 595
   version "0.3.2"
548 596
   resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
@@ -590,6 +638,13 @@ aws4@^1.8.0:
590 638
   resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.1.tgz#7e33d8f7d449b3f673cd72deb9abdc552dbe528e"
591 639
   integrity sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==
592 640
 
641
+axios@*, axios@^0.19.2:
642
+  version "0.19.2"
643
+  resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
644
+  integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
645
+  dependencies:
646
+    follow-redirects "1.5.10"
647
+
593 648
 babel-jest@^25.1.0:
594 649
   version "25.1.0"
595 650
   resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-25.1.0.tgz#206093ac380a4b78c4404a05b3277391278f80fb"
@@ -655,6 +710,16 @@ bcrypt-pbkdf@^1.0.0:
655 710
   dependencies:
656 711
     tweetnacl "^0.14.3"
657 712
 
713
+bignumber.js@^2.1.0:
714
+  version "2.4.0"
715
+  resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-2.4.0.tgz#838a992da9f9d737e0f4b2db0be62bb09dd0c5e8"
716
+  integrity sha1-g4qZLan51zfg9LLbC+YrsJ3Qxeg=
717
+
718
+bmp-js@0.0.1:
719
+  version "0.0.1"
720
+  resolved "https://registry.yarnpkg.com/bmp-js/-/bmp-js-0.0.1.tgz#5ad0147099d13a9f38aa7b99af1d6e78666ed37f"
721
+  integrity sha1-WtAUcJnROp84qnuZrx1ueGZu038=
722
+
658 723
 brace-expansion@^1.1.7:
659 724
   version "1.1.11"
660 725
   resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -712,6 +777,11 @@ bser@2.1.1:
712 777
   dependencies:
713 778
     node-int64 "^0.4.0"
714 779
 
780
+buffer-equal@0.0.1:
781
+  version "0.0.1"
782
+  resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b"
783
+  integrity sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs=
784
+
715 785
 buffer-from@1.x, buffer-from@^1.0.0:
716 786
   version "1.1.1"
717 787
   resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
@@ -886,6 +956,14 @@ core-util-is@1.0.2:
886 956
   resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
887 957
   integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
888 958
 
959
+cross-spawn@^4.0.0:
960
+  version "4.0.2"
961
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41"
962
+  integrity sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=
963
+  dependencies:
964
+    lru-cache "^4.0.1"
965
+    which "^1.2.9"
966
+
889 967
 cross-spawn@^6.0.0:
890 968
   version "6.0.5"
891 969
   resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
@@ -917,9 +995,9 @@ cssom@~0.3.6:
917 995
   integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==
918 996
 
919 997
 cssstyle@^2.0.0:
920
-  version "2.1.0"
921
-  resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.1.0.tgz#99f50a3aa21d4af16e758ae3e454dcf5940b9122"
922
-  integrity sha512-1iwCdymVYhMdQWiZ+9mB7x+urdNLPGTWsIZt6euFk8Yi+dOERK2ccoAUA3Bl8I5vmK5qfz/eLkBRyLbs42ov4A==
998
+  version "2.2.0"
999
+  resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.2.0.tgz#e4c44debccd6b7911ed617a4395e5754bba59992"
1000
+  integrity sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA==
923 1001
   dependencies:
924 1002
     cssom "~0.3.6"
925 1003
 
@@ -939,6 +1017,13 @@ data-urls@^1.1.0:
939 1017
     whatwg-mimetype "^2.2.0"
940 1018
     whatwg-url "^7.0.0"
941 1019
 
1020
+debug@=3.1.0:
1021
+  version "3.1.0"
1022
+  resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
1023
+  integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
1024
+  dependencies:
1025
+    ms "2.0.0"
1026
+
942 1027
 debug@^2.2.0, debug@^2.3.3:
943 1028
   version "2.6.9"
944 1029
   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
@@ -946,6 +1031,13 @@ debug@^2.2.0, debug@^2.3.3:
946 1031
   dependencies:
947 1032
     ms "2.0.0"
948 1033
 
1034
+debug@^3.1.0:
1035
+  version "3.2.6"
1036
+  resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
1037
+  integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
1038
+  dependencies:
1039
+    ms "^2.1.1"
1040
+
949 1041
 debug@^4.1.0, debug@^4.1.1:
950 1042
   version "4.1.1"
951 1043
   resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
@@ -1022,6 +1114,11 @@ diff@^4.0.1:
1022 1114
   resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
1023 1115
   integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
1024 1116
 
1117
+dom-walk@^0.1.0:
1118
+  version "0.1.1"
1119
+  resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018"
1120
+  integrity sha1-ZyIm3HTI95mtNTB9+TaroRrNYBg=
1121
+
1025 1122
 domexception@^1.0.1:
1026 1123
   version "1.0.1"
1027 1124
   resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90"
@@ -1075,6 +1172,11 @@ es-to-primitive@^1.2.1:
1075 1172
     is-date-object "^1.0.1"
1076 1173
     is-symbol "^1.0.2"
1077 1174
 
1175
+es6-promise@^3.0.2:
1176
+  version "3.3.1"
1177
+  resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613"
1178
+  integrity sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=
1179
+
1078 1180
 escape-string-regexp@^1.0.5:
1079 1181
   version "1.0.5"
1080 1182
   resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
@@ -1141,6 +1243,11 @@ execa@^3.2.0:
1141 1243
     signal-exit "^3.0.2"
1142 1244
     strip-final-newline "^2.0.0"
1143 1245
 
1246
+exif-parser@^0.1.9:
1247
+  version "0.1.12"
1248
+  resolved "https://registry.yarnpkg.com/exif-parser/-/exif-parser-0.1.12.tgz#58a9d2d72c02c1f6f02a0ef4a9166272b7760922"
1249
+  integrity sha1-WKnS1ywCwfbwKg70qRZicrd2CSI=
1250
+
1144 1251
 exit@^0.1.2:
1145 1252
   version "0.1.2"
1146 1253
   resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c"
@@ -1237,6 +1344,11 @@ fb-watchman@^2.0.0:
1237 1344
   dependencies:
1238 1345
     bser "2.1.1"
1239 1346
 
1347
+file-type@^3.1.0:
1348
+  version "3.9.0"
1349
+  resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9"
1350
+  integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek=
1351
+
1240 1352
 fill-range@^4.0.0:
1241 1353
   version "4.0.0"
1242 1354
   resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
@@ -1262,6 +1374,13 @@ find-up@^4.0.0, find-up@^4.1.0:
1262 1374
     locate-path "^5.0.0"
1263 1375
     path-exists "^4.0.0"
1264 1376
 
1377
+follow-redirects@1.5.10:
1378
+  version "1.5.10"
1379
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
1380
+  integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
1381
+  dependencies:
1382
+    debug "=3.1.0"
1383
+
1265 1384
 for-in@^1.0.2:
1266 1385
   version "1.0.2"
1267 1386
   resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
@@ -1288,6 +1407,15 @@ fragment-cache@^0.2.1:
1288 1407
   dependencies:
1289 1408
     map-cache "^0.2.2"
1290 1409
 
1410
+fs-extra@^8.1.0:
1411
+  version "8.1.0"
1412
+  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
1413
+  integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
1414
+  dependencies:
1415
+    graceful-fs "^4.2.0"
1416
+    jsonfile "^4.0.0"
1417
+    universalify "^0.1.0"
1418
+
1291 1419
 fs.realpath@^1.0.0:
1292 1420
   version "1.0.0"
1293 1421
   resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
@@ -1351,12 +1479,30 @@ glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4:
1351 1479
     once "^1.3.0"
1352 1480
     path-is-absolute "^1.0.0"
1353 1481
 
1482
+global@~4.3.0:
1483
+  version "4.3.2"
1484
+  resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f"
1485
+  integrity sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=
1486
+  dependencies:
1487
+    min-document "^2.19.0"
1488
+    process "~0.5.1"
1489
+
1354 1490
 globals@^11.1.0:
1355 1491
   version "11.12.0"
1356 1492
   resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
1357 1493
   integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
1358 1494
 
1359
-graceful-fs@^4.2.3:
1495
+gm@^1.23.1:
1496
+  version "1.23.1"
1497
+  resolved "https://registry.yarnpkg.com/gm/-/gm-1.23.1.tgz#2edeeb958084d0f8ea7988e5d995b1c7dfc14777"
1498
+  integrity sha1-Lt7rlYCE0PjqeYjl2ZWxx9/BR3c=
1499
+  dependencies:
1500
+    array-parallel "~0.1.3"
1501
+    array-series "~0.1.5"
1502
+    cross-spawn "^4.0.0"
1503
+    debug "^3.1.0"
1504
+
1505
+graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.3:
1360 1506
   version "4.2.3"
1361 1507
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
1362 1508
   integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
@@ -1491,6 +1637,11 @@ inherits@2:
1491 1637
   resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
1492 1638
   integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
1493 1639
 
1640
+ip-regex@^1.0.1:
1641
+  version "1.0.3"
1642
+  resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-1.0.3.tgz#dc589076f659f419c222039a33316f1c7387effd"
1643
+  integrity sha1-3FiQdvZZ9BnCIgOaMzFvHHOH7/0=
1644
+
1494 1645
 ip-regex@^2.1.0:
1495 1646
   version "2.1.0"
1496 1647
   resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
@@ -1581,6 +1732,11 @@ is-fullwidth-code-point@^3.0.0:
1581 1732
   resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
1582 1733
   integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
1583 1734
 
1735
+is-function@^1.0.1:
1736
+  version "1.0.1"
1737
+  resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5"
1738
+  integrity sha1-Es+5i2W1fdPRk6MSH19uL0N2ArU=
1739
+
1584 1740
 is-generator-fn@^2.0.0:
1585 1741
   version "2.1.0"
1586 1742
   resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118"
@@ -1598,6 +1754,11 @@ is-number@^7.0.0:
1598 1754
   resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
1599 1755
   integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
1600 1756
 
1757
+is-plain-obj@^1.1.0:
1758
+  version "1.1.0"
1759
+  resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
1760
+  integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
1761
+
1601 1762
 is-plain-object@^2.0.3, is-plain-object@^2.0.4:
1602 1763
   version "2.0.4"
1603 1764
   resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
@@ -2078,6 +2239,32 @@ jest@^25.1.0:
2078 2239
     import-local "^3.0.2"
2079 2240
     jest-cli "^25.1.0"
2080 2241
 
2242
+jimp@0.2.27:
2243
+  version "0.2.27"
2244
+  resolved "https://registry.yarnpkg.com/jimp/-/jimp-0.2.27.tgz#41ef5082d8b63201d54747e04fe8bcacbaf25474"
2245
+  integrity sha1-Qe9Qgti2MgHVR0fgT+i8rLryVHQ=
2246
+  dependencies:
2247
+    bignumber.js "^2.1.0"
2248
+    bmp-js "0.0.1"
2249
+    es6-promise "^3.0.2"
2250
+    exif-parser "^0.1.9"
2251
+    file-type "^3.1.0"
2252
+    jpeg-js "^0.2.0"
2253
+    load-bmfont "^1.2.3"
2254
+    mime "^1.3.4"
2255
+    pixelmatch "^4.0.0"
2256
+    pngjs "^3.0.0"
2257
+    read-chunk "^1.0.1"
2258
+    request "^2.65.0"
2259
+    stream-to-buffer "^0.1.0"
2260
+    tinycolor2 "^1.1.2"
2261
+    url-regex "^3.0.0"
2262
+
2263
+jpeg-js@^0.2.0:
2264
+  version "0.2.0"
2265
+  resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.2.0.tgz#53e448ec9d263e683266467e9442d2c5a2ef5482"
2266
+  integrity sha1-U+RI7J0mPmgyZkZ+lELSxaLvVII=
2267
+
2081 2268
 js-tokens@^4.0.0:
2082 2269
   version "4.0.0"
2083 2270
   resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -2155,6 +2342,13 @@ json5@2.x, json5@^2.1.0:
2155 2342
   dependencies:
2156 2343
     minimist "^1.2.0"
2157 2344
 
2345
+jsonfile@^4.0.0:
2346
+  version "4.0.0"
2347
+  resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
2348
+  integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
2349
+  optionalDependencies:
2350
+    graceful-fs "^4.1.6"
2351
+
2158 2352
 jsprim@^1.2.2:
2159 2353
   version "1.4.1"
2160 2354
   resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
@@ -2207,6 +2401,20 @@ levn@~0.3.0:
2207 2401
     prelude-ls "~1.1.2"
2208 2402
     type-check "~0.3.2"
2209 2403
 
2404
+load-bmfont@^1.2.3:
2405
+  version "1.4.0"
2406
+  resolved "https://registry.yarnpkg.com/load-bmfont/-/load-bmfont-1.4.0.tgz#75f17070b14a8c785fe7f5bee2e6fd4f98093b6b"
2407
+  integrity sha512-kT63aTAlNhZARowaNYcY29Fn/QYkc52M3l6V1ifRcPewg2lvUZDAj7R6dXjOL9D0sict76op3T5+odumDSF81g==
2408
+  dependencies:
2409
+    buffer-equal "0.0.1"
2410
+    mime "^1.3.4"
2411
+    parse-bmfont-ascii "^1.0.3"
2412
+    parse-bmfont-binary "^1.0.5"
2413
+    parse-bmfont-xml "^1.1.4"
2414
+    phin "^2.9.1"
2415
+    xhr "^2.0.1"
2416
+    xtend "^4.0.0"
2417
+
2210 2418
 locate-path@^5.0.0:
2211 2419
   version "5.0.0"
2212 2420
   resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
@@ -2236,6 +2444,14 @@ lolex@^5.0.0:
2236 2444
   dependencies:
2237 2445
     "@sinonjs/commons" "^1.7.0"
2238 2446
 
2447
+lru-cache@^4.0.1:
2448
+  version "4.1.5"
2449
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
2450
+  integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
2451
+  dependencies:
2452
+    pseudomap "^1.0.2"
2453
+    yallist "^2.1.2"
2454
+
2239 2455
 make-dir@^3.0.0:
2240 2456
   version "3.0.0"
2241 2457
   resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.0.0.tgz#1b5f39f6b9270ed33f9f054c5c0f84304989f801"
@@ -2267,6 +2483,14 @@ map-visit@^1.0.0:
2267 2483
   dependencies:
2268 2484
     object-visit "^1.0.0"
2269 2485
 
2486
+merge-img@^2.1.3:
2487
+  version "2.1.3"
2488
+  resolved "https://registry.yarnpkg.com/merge-img/-/merge-img-2.1.3.tgz#276bc334f9ef06391ddb9548063eac20d1eaf0b6"
2489
+  integrity sha512-PA8caQPleTulKV7s2CXGvzTPxVoT5wkFCB0jf0RVzIYG+job08wibDA9lMYlpcHjCOvup3p1UPk1JgTwgJnu6g==
2490
+  dependencies:
2491
+    is-plain-obj "^1.1.0"
2492
+    jimp "0.2.27"
2493
+
2270 2494
 merge-stream@^2.0.0:
2271 2495
   version "2.0.0"
2272 2496
   resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
@@ -2311,11 +2535,23 @@ mime-types@^2.1.12, mime-types@~2.1.19:
2311 2535
   dependencies:
2312 2536
     mime-db "1.43.0"
2313 2537
 
2538
+mime@^1.3.4:
2539
+  version "1.6.0"
2540
+  resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
2541
+  integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
2542
+
2314 2543
 mimic-fn@^2.1.0:
2315 2544
   version "2.1.0"
2316 2545
   resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
2317 2546
   integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
2318 2547
 
2548
+min-document@^2.19.0:
2549
+  version "2.19.0"
2550
+  resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
2551
+  integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=
2552
+  dependencies:
2553
+    dom-walk "^0.1.0"
2554
+
2319 2555
 minimatch@^3.0.4:
2320 2556
   version "3.0.4"
2321 2557
   resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
@@ -2553,6 +2789,29 @@ p-try@^2.0.0:
2553 2789
   resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
2554 2790
   integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
2555 2791
 
2792
+parse-bmfont-ascii@^1.0.3:
2793
+  version "1.0.6"
2794
+  resolved "https://registry.yarnpkg.com/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz#11ac3c3ff58f7c2020ab22769079108d4dfa0285"
2795
+  integrity sha1-Eaw8P/WPfCAgqyJ2kHkQjU36AoU=
2796
+
2797
+parse-bmfont-binary@^1.0.5:
2798
+  version "1.0.6"
2799
+  resolved "https://registry.yarnpkg.com/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz#d038b476d3e9dd9db1e11a0b0e53a22792b69006"
2800
+  integrity sha1-0Di0dtPp3Z2x4RoLDlOiJ5K2kAY=
2801
+
2802
+parse-bmfont-xml@^1.1.4:
2803
+  version "1.1.4"
2804
+  resolved "https://registry.yarnpkg.com/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz#015319797e3e12f9e739c4d513872cd2fa35f389"
2805
+  integrity sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==
2806
+  dependencies:
2807
+    xml-parse-from-string "^1.0.0"
2808
+    xml2js "^0.4.5"
2809
+
2810
+parse-headers@^2.0.0:
2811
+  version "2.0.3"
2812
+  resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.3.tgz#5e8e7512383d140ba02f0c7aa9f49b4399c92515"
2813
+  integrity sha512-QhhZ+DCCit2Coi2vmAKbq5RGTRcQUOE2+REgv8vdyu7MnYx2eZztegqtTx99TZ86GTIwqiy3+4nQTWZ2tgmdCA==
2814
+
2556 2815
 parse5@5.1.0:
2557 2816
   version "5.1.0"
2558 2817
   resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2"
@@ -2593,6 +2852,11 @@ performance-now@^2.1.0:
2593 2852
   resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
2594 2853
   integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
2595 2854
 
2855
+phin@^2.9.1:
2856
+  version "2.9.3"
2857
+  resolved "https://registry.yarnpkg.com/phin/-/phin-2.9.3.tgz#f9b6ac10a035636fb65dfc576aaaa17b8743125c"
2858
+  integrity sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==
2859
+
2596 2860
 picomatch@^2.0.4, picomatch@^2.0.5:
2597 2861
   version "2.2.1"
2598 2862
   resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a"
@@ -2605,6 +2869,13 @@ pirates@^4.0.1:
2605 2869
   dependencies:
2606 2870
     node-modules-regexp "^1.0.0"
2607 2871
 
2872
+pixelmatch@^4.0.0:
2873
+  version "4.0.2"
2874
+  resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-4.0.2.tgz#8f47dcec5011b477b67db03c243bc1f3085e8854"
2875
+  integrity sha1-j0fc7FARtHe2fbA8JDvB8wheiFQ=
2876
+  dependencies:
2877
+    pngjs "^3.0.0"
2878
+
2608 2879
 pkg-dir@^4.2.0:
2609 2880
   version "4.2.0"
2610 2881
   resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
@@ -2617,6 +2888,11 @@ pn@^1.1.0:
2617 2888
   resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb"
2618 2889
   integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==
2619 2890
 
2891
+pngjs@^3.0.0:
2892
+  version "3.4.0"
2893
+  resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f"
2894
+  integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==
2895
+
2620 2896
 posix-character-classes@^0.1.0:
2621 2897
   version "0.1.1"
2622 2898
   resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
@@ -2652,6 +2928,11 @@ pretty-format@^25.1.0:
2652 2928
     ansi-styles "^4.0.0"
2653 2929
     react-is "^16.12.0"
2654 2930
 
2931
+process@~0.5.1:
2932
+  version "0.5.2"
2933
+  resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf"
2934
+  integrity sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=
2935
+
2655 2936
 prompts@^2.0.1:
2656 2937
   version "2.3.0"
2657 2938
   resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.0.tgz#a444e968fa4cc7e86689a74050685ac8006c4cc4"
@@ -2660,6 +2941,11 @@ prompts@^2.0.1:
2660 2941
     kleur "^3.0.3"
2661 2942
     sisteransi "^1.0.3"
2662 2943
 
2944
+pseudomap@^1.0.2:
2945
+  version "1.0.2"
2946
+  resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
2947
+  integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
2948
+
2663 2949
 psl@^1.1.24, psl@^1.1.28:
2664 2950
   version "1.7.0"
2665 2951
   resolved "https://registry.yarnpkg.com/psl/-/psl-1.7.0.tgz#f1c4c47a8ef97167dea5d6bbf4816d736e884a3c"
@@ -2693,6 +2979,11 @@ react-is@^16.12.0, react-is@^16.8.4:
2693 2979
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.12.0.tgz#2cc0fe0fba742d97fd527c42a13bec4eeb06241c"
2694 2980
   integrity sha512-rPCkf/mWBtKc97aLL9/txD8DZdemK0vkA3JMLShjlJB3Pj3s+lpf1KaBzMfQrAmhMQB0n1cU/SUGgKKBCe837Q==
2695 2981
 
2982
+read-chunk@^1.0.1:
2983
+  version "1.0.1"
2984
+  resolved "https://registry.yarnpkg.com/read-chunk/-/read-chunk-1.0.1.tgz#5f68cab307e663f19993527d9b589cace4661194"
2985
+  integrity sha1-X2jKswfmY/GZk1J9m1icrORmEZQ=
2986
+
2696 2987
 realpath-native@^1.1.0:
2697 2988
   version "1.1.0"
2698 2989
   resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c"
@@ -2739,7 +3030,7 @@ request-promise-native@^1.0.7:
2739 3030
     stealthy-require "^1.1.1"
2740 3031
     tough-cookie "^2.3.3"
2741 3032
 
2742
-request@^2.88.0:
3033
+request@^2.65.0, request@^2.88.0:
2743 3034
   version "2.88.0"
2744 3035
   resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
2745 3036
   integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
@@ -2858,6 +3149,11 @@ sane@^4.0.3:
2858 3149
     minimist "^1.1.1"
2859 3150
     walker "~1.0.5"
2860 3151
 
3152
+sax@>=0.6.0:
3153
+  version "1.2.4"
3154
+  resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
3155
+  integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
3156
+
2861 3157
 saxes@^3.1.9:
2862 3158
   version "3.1.11"
2863 3159
   resolved "https://registry.yarnpkg.com/saxes/-/saxes-3.1.11.tgz#d59d1fd332ec92ad98a2e0b2ee644702384b1c5b"
@@ -3053,6 +3349,18 @@ stealthy-require@^1.1.1:
3053 3349
   resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
3054 3350
   integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=
3055 3351
 
3352
+stream-to-buffer@^0.1.0:
3353
+  version "0.1.0"
3354
+  resolved "https://registry.yarnpkg.com/stream-to-buffer/-/stream-to-buffer-0.1.0.tgz#26799d903ab2025c9bd550ac47171b00f8dd80a9"
3355
+  integrity sha1-JnmdkDqyAlyb1VCsRxcbAPjdgKk=
3356
+  dependencies:
3357
+    stream-to "~0.2.0"
3358
+
3359
+stream-to@~0.2.0:
3360
+  version "0.2.2"
3361
+  resolved "https://registry.yarnpkg.com/stream-to/-/stream-to-0.2.2.tgz#84306098d85fdb990b9fa300b1b3ccf55e8ef01d"
3362
+  integrity sha1-hDBgmNhf25kLn6MAsbPM9V6O8B0=
3363
+
3056 3364
 string-length@^3.1.0:
3057 3365
   version "3.1.0"
3058 3366
   resolved "https://registry.yarnpkg.com/string-length/-/string-length-3.1.0.tgz#107ef8c23456e187a8abd4a61162ff4ac6e25837"
@@ -3164,6 +3472,11 @@ throat@^5.0.0:
3164 3472
   resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b"
3165 3473
   integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==
3166 3474
 
3475
+tinycolor2@^1.1.2:
3476
+  version "1.4.1"
3477
+  resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8"
3478
+  integrity sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g=
3479
+
3167 3480
 tmpl@1.0.x:
3168 3481
   version "1.0.4"
3169 3482
   resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
@@ -3238,10 +3551,10 @@ tr46@^1.0.1:
3238 3551
   dependencies:
3239 3552
     punycode "^2.1.0"
3240 3553
 
3241
-ts-jest@^24.3.0:
3242
-  version "24.3.0"
3243
-  resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-24.3.0.tgz#b97814e3eab359ea840a1ac112deae68aa440869"
3244
-  integrity sha512-Hb94C/+QRIgjVZlJyiWwouYUF+siNJHJHknyspaOcZ+OQAIdFG/UrdQVXw/0B8Z3No34xkUXZJpOTy9alOWdVQ==
3554
+ts-jest@^25.0.0:
3555
+  version "25.0.0"
3556
+  resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-25.0.0.tgz#d83b266e6ffda0c458a129951b3fe3567f8ce8df"
3557
+  integrity sha512-F+hZg3j7XYOFpXJteXb4lnqy7vQzTmpTmX7AJT6pvSGeZejyXj1Lk0ArpnrEPOpv6Zu/NugHc5W7FINngC9WZQ==
3245 3558
   dependencies:
3246 3559
     bs-logger "0.x"
3247 3560
     buffer-from "1.x"
@@ -3341,6 +3654,11 @@ union-value@^1.0.0:
3341 3654
     is-extendable "^0.1.1"
3342 3655
     set-value "^2.0.1"
3343 3656
 
3657
+universalify@^0.1.0:
3658
+  version "0.1.2"
3659
+  resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
3660
+  integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
3661
+
3344 3662
 unset-value@^1.0.0:
3345 3663
   version "1.0.0"
3346 3664
   resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
@@ -3361,6 +3679,13 @@ urix@^0.1.0:
3361 3679
   resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
3362 3680
   integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
3363 3681
 
3682
+url-regex@^3.0.0:
3683
+  version "3.2.0"
3684
+  resolved "https://registry.yarnpkg.com/url-regex/-/url-regex-3.2.0.tgz#dbad1e0c9e29e105dd0b1f09f6862f7fdb482724"
3685
+  integrity sha1-260eDJ4p4QXdCx8J9oYvf9tIJyQ=
3686
+  dependencies:
3687
+    ip-regex "^1.0.1"
3688
+
3364 3689
 use@^3.1.0:
3365 3690
   version "3.1.1"
3366 3691
   resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
@@ -3501,21 +3826,59 @@ ws@^7.0.0:
3501 3826
   resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.1.tgz#03ed52423cd744084b2cf42ed197c8b65a936b8e"
3502 3827
   integrity sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A==
3503 3828
 
3829
+xhr@^2.0.1:
3830
+  version "2.5.0"
3831
+  resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.5.0.tgz#bed8d1676d5ca36108667692b74b316c496e49dd"
3832
+  integrity sha512-4nlO/14t3BNUZRXIXfXe+3N6w3s1KoxcJUUURctd64BLRe67E4gRwp4PjywtDY72fXpZ1y6Ch0VZQRY/gMPzzQ==
3833
+  dependencies:
3834
+    global "~4.3.0"
3835
+    is-function "^1.0.1"
3836
+    parse-headers "^2.0.0"
3837
+    xtend "^4.0.0"
3838
+
3504 3839
 xml-name-validator@^3.0.0:
3505 3840
   version "3.0.0"
3506 3841
   resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
3507 3842
   integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==
3508 3843
 
3844
+xml-parse-from-string@^1.0.0:
3845
+  version "1.0.1"
3846
+  resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28"
3847
+  integrity sha1-qQKekp09vN7RafPG4oI42VpdWig=
3848
+
3849
+xml2js@^0.4.5:
3850
+  version "0.4.23"
3851
+  resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
3852
+  integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
3853
+  dependencies:
3854
+    sax ">=0.6.0"
3855
+    xmlbuilder "~11.0.0"
3856
+
3857
+xmlbuilder@~11.0.0:
3858
+  version "11.0.1"
3859
+  resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
3860
+  integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==
3861
+
3509 3862
 xmlchars@^2.1.1:
3510 3863
   version "2.2.0"
3511 3864
   resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
3512 3865
   integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==
3513 3866
 
3867
+xtend@^4.0.0:
3868
+  version "4.0.2"
3869
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
3870
+  integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
3871
+
3514 3872
 y18n@^4.0.0:
3515 3873
   version "4.0.0"
3516 3874
   resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
3517 3875
   integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
3518 3876
 
3877
+yallist@^2.1.2:
3878
+  version "2.1.2"
3879
+  resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
3880
+  integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
3881
+
3519 3882
 yargs-parser@10.x:
3520 3883
   version "10.1.0"
3521 3884
   resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8"