├── .npmignore
├── .gitignore
├── doc
├── preview.png
└── preview.eq.png
├── runConfigurations
└── test.run.xml
├── src
├── dev.js
├── stopwatch.js
├── marzipano.js
├── randomaccessfile.js
├── scale.js
├── pannellum.js
├── cli.js
├── renderer.js
├── img.js
├── psd.js
└── converter.js
├── LICENSE
├── package.json
├── README.md
└── yarn.lock
/.npmignore:
--------------------------------------------------------------------------------
1 | runConfigurations
2 | .idea
3 | yarn-error.log
4 | doc
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .idea
3 | bck
4 | yarn-error.log
5 | package-lock.json
6 |
--------------------------------------------------------------------------------
/doc/preview.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zebrajaeger/sphere2cube-js/HEAD/doc/preview.png
--------------------------------------------------------------------------------
/doc/preview.eq.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zebrajaeger/sphere2cube-js/HEAD/doc/preview.eq.png
--------------------------------------------------------------------------------
/runConfigurations/test.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/dev.js:
--------------------------------------------------------------------------------
1 | const converter = require('./converter');
2 |
3 | // const file = 'C:/temp/test.psd';
4 | const file = 'C:/temp/test_10k.psd';
5 | // const file = 'C:/prj.lars/sphere2cube/samples/test.psb';
6 | const basePath = 'c:/temp/!panotest/';
7 |
8 | const cfg = {
9 | targetImgSize: undefined,
10 | previewWidth: 1000,
11 | tileSize: 512,
12 | backgroundColor: {r: 0, g: 0, b: 0, a: 0}
13 | };
14 |
15 | converter.renderPano(file, basePath, cfg).then();
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | ISC License
2 |
3 | Copyright (c) [year], [fullname]
4 |
5 | Permission to use, copy, modify, and/or distribute this software for any
6 | purpose with or without fee is hereby granted, provided that the above
7 | copyright notice and this permission notice appear in all copies.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@zebrajaeger/createpano",
3 | "version": "0.3.3",
4 | "description": "Converter for images to panoramic viewer",
5 | "main": "src/index.js",
6 | "scripts": {
7 | "test": "nodemon --max-old-space-size=10000 src/dev.js",
8 | "deploy": "npm publish --access public"
9 | },
10 | "keywords": [],
11 | "author": "Lars Brandt",
12 | "license": "ISC",
13 | "repository": {
14 | "type": "git",
15 | "url": "https://github.com/zebrajaeger/sphere2cube-js.git"
16 | },
17 | "homepage": "https://github.com/zebrajaeger/sphere2cube-js/",
18 | "dependencies": {
19 | "archiver": "^4.0.2",
20 | "cli-progress": "^3.8.2",
21 | "commander": "^5.1.0",
22 | "execution-time": "^1.4.1",
23 | "exif-parser": "^0.1.12",
24 | "humanize-duration": "^3.23.1",
25 | "jpeg-js": "^0.4.1",
26 | "pngjs": "^5.0.0",
27 | "pretty-bytes": "^5.3.0",
28 | "twig": "^1.15.1",
29 | "xml2js": "^0.4.23"
30 | },
31 | "devDependencies": {
32 | "marzipano": "^0.9.1",
33 | "nodemon": "^2.0.4"
34 | },
35 | "bin": {
36 | "createpano": "./src/cli.js",
37 | "cpn": "./src/cli.js"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/stopwatch.js:
--------------------------------------------------------------------------------
1 | const {performance} = require('perf_hooks');
2 |
3 | const humanizeDuration = require("humanize-duration");
4 |
5 | module.exports.Stopwatch = class {
6 | _startTime;
7 |
8 | begin() {
9 | this._startTime = performance.now();
10 | return this;
11 | }
12 |
13 | getDuration() {
14 | const now = performance.now();
15 | return this.round(now - this._startTime, -2)
16 | }
17 |
18 | getTimeString() {
19 | return humanizeDuration(this.getDuration());
20 | }
21 |
22 | round(value, exp) {
23 | if (typeof exp === 'undefined' || +exp === 0)
24 | return Math.round(value);
25 |
26 | value = +value;
27 | exp = +exp;
28 |
29 | if (isNaN(value) || !(typeof exp === 'number' && exp % 1 === 0))
30 | return NaN;
31 |
32 | // Shift
33 | value = value.toString().split('e');
34 | value = Math.round(+(value[0] + 'e' + (value[1] ? (+value[1] + exp) : exp)));
35 |
36 | // Shift back
37 | value = value.toString().split('e');
38 | return +(value[0] + 'e' + (value[1] ? (+value[1] - exp) : -exp));
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/marzipano.js:
--------------------------------------------------------------------------------
1 | // {f} : tile face (one of b, d, f, l, r, u)
2 | // {z} : tile level index (0 is the smallest level)
3 | // {x} : tile horizontal index
4 | // {y} : tile vertical index
5 |
6 | module.exports = {
7 | createHtml: createHtml
8 | }
9 |
10 | function createHtml(config, data) {
11 | return `
12 |
13 |
14 | ${config.htmlTitle}
15 |
16 |
17 |
18 |
19 |
20 |
32 |
33 |
34 | `}
35 |
--------------------------------------------------------------------------------
/src/randomaccessfile.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 |
3 | async function read(fd, position, length) {
4 | return new Promise((resolve, reject) => {
5 | const b = new Buffer.alloc(length);
6 | fs.read(fd, b, 0, length, position, (err, bytesRead, buffer) => {
7 | if (err) {
8 | reject(err);
9 | } else {
10 | if (length !== bytesRead) {
11 | reject('File to short')
12 | } else {
13 | resolve(buffer);
14 | }
15 | }
16 | })
17 | });
18 | }
19 |
20 | exports.RandomAccessFile = {
21 | open: async (path) => {
22 | return new Promise((resolve, reject) => {
23 | fs.open(path, 'r', (err, fd) => {
24 | if (err) {
25 | reject(err);
26 | } else {
27 | resolve(fd);
28 | }
29 | })
30 | })
31 | },
32 |
33 | close: async (fd) => {
34 | return new Promise((resolve, reject) => {
35 | fs.close(fd, (err) => {
36 | if (err) {
37 | reject(err);
38 | } else {
39 | resolve();
40 | }
41 | })
42 | })
43 | },
44 |
45 | read: read,
46 |
47 | fileSize: (filename) => {
48 | const stats = fs.statSync(filename)
49 | return stats["size"]
50 | }
51 | }
52 |
53 |
--------------------------------------------------------------------------------
/src/scale.js:
--------------------------------------------------------------------------------
1 | const EventEmitter = require('events');
2 |
3 | class Bilinear extends EventEmitter {
4 | scale(srcParams, targetParams, getPixel, setPixel) {
5 |
6 | const wSrc = srcParams.w;
7 | const hSrc = srcParams.h;
8 |
9 | const wDst = targetParams.w;
10 | const hDst = targetParams.h;
11 |
12 | const assign = function (dX, dY,
13 | x, xMin, xMax,
14 | y, yMin, yMax,
15 | getPixel, setPixel) {
16 | const vMin = interpolate(x, xMin, getPixel(xMin, yMin), xMax, getPixel(xMax, yMin));
17 |
18 | // special case, y is integer
19 | if (yMax === yMin) {
20 | setPixel(dX, dY, vMin);
21 | } else {
22 | const vMax = interpolate(x, xMin, getPixel(xMin, yMax), xMax, getPixel(xMax, yMax));
23 | setPixel(dX, dY, interpolate(y, yMin, vMin, yMax, vMax));
24 | }
25 | }
26 |
27 | const interpolate = function (k, kMin, vMin, kMax, vMax) {
28 | // special case - k is integer
29 | if (kMin === kMax) {
30 | return vMin;
31 | }
32 |
33 | return {
34 | r: Math.round((k - kMin) * vMax.r + (kMax - k) * vMin.r),
35 | g: Math.round((k - kMin) * vMax.g + (kMax - k) * vMin.g),
36 | b: Math.round((k - kMin) * vMax.b + (kMax - k) * vMin.b),
37 | a: Math.round((k - kMin) * vMax.a + (kMax - k) * vMin.a)
38 | }
39 | }
40 |
41 | this.emit('begin', hDst - 1);
42 | for (let i = 0; i < hDst; i++) {
43 | for (let j = 0; j < wDst; j++) {
44 | // x & y in src coordinates
45 | const x = (j * wSrc) / wDst;
46 | const xMin = Math.floor(x);
47 | const xMax = Math.min(Math.ceil(x), wSrc - 1);
48 |
49 | const y = (i * hSrc) / hDst;
50 | const yMin = Math.floor(y);
51 | const yMax = Math.min(Math.ceil(y), hSrc - 1);
52 |
53 | assign(j, i, x, xMin, xMax, y, yMin, yMax, getPixel, setPixel);
54 | }
55 | this.emit('progress', i)
56 | }
57 | this.emit('end')
58 | }
59 |
60 | }
61 |
62 | module.exports.Bilinear = Bilinear;
63 |
64 |
65 | module.exports.nearestNeighbour = (src, dst, getPixel, setPixel) => {
66 | const wSrc = src.w;
67 | const hSrc = src.h;
68 |
69 | const wDst = dst.w;
70 | const hDst = dst.h;
71 |
72 | console.log('nearestNeighbour', {src, dst}, {wSrc, hSrc, wDst, hDst})
73 | for (let i = 0; i < hDst; i++) {
74 | for (let j = 0; j < wDst; j++) {
75 | const iSrc = Math.floor((i * hSrc) / hDst);
76 | const jSrc = Math.floor((j * wSrc) / wDst);
77 | setPixel(j, i, getPixel(jSrc, iSrc));
78 | }
79 | }
80 | }
81 |
82 |
--------------------------------------------------------------------------------
/src/pannellum.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | createHtml: createHtml
3 | }
4 |
5 | function createHtml(config,data) {
6 | return `
7 |
8 |
9 |
10 |
11 | ${config.htmlTitle}
12 |
13 |
14 |
25 |
26 |
27 |
28 |
29 |
30 |
84 |
85 |
86 | `;
87 | }
88 |
89 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # @zebrajaeger/createpano
2 |
3 | [](https://www.npmjs.org/package/@zebrajaeger/createpano)
4 | [](https://packagephobia.now.sh/result?p=@zebrajaeger/createpano)
5 | [](https://img.shields.io/github/license/zebrajaeger/sphere2cube-js)
6 |
7 | Convert
8 | - full spheric panorama image to viewer (equirectangular)
9 | - 360° panorama image to viewer (y to small for equirectangular)
10 | - partial panorama image to viewer
11 |
12 | Reads
13 | - PSD and PSB with RAW or RLE Encoding
14 | - jpg
15 | - png
16 |
17 | Writes
18 | - preview (cubic)
19 | - preview (downscaled)
20 | - tiles (pyramide levels)
21 | - html (pannellum implementation)
22 | - all above as zip file
23 |
24 | ## Installation
25 |
26 | ```bash
27 | $ npm install -g @zebrajaeger/createpano
28 | ```
29 |
30 | ## Usage
31 |
32 | ### Minimum
33 |
34 | ```bash
35 | $ createpano -i sourceimage.psd
36 | ```
37 |
38 | ## Options
39 | ```bash
40 | Usage: cli [options]
41 |
42 | Options:
43 | -V, --version output the version number
44 | -i, --source Source image (mandatory)
45 | -ipa, --panoAngle Angle of pano (default: "360")
46 | -ipy, --panoYOffset Y-Offset in degree [-90.0...90.0] (default: "0")
47 | -o, --output Output folder (default: "_dist")
48 | -te, --targetSize Image edge length of a face @ max resolution (default: inputImage.x / 4)
49 | -fr, --facesToRender Faces To render (default: "flrbud")
50 | -ti, --tilesIgnore Dont render tiles
51 | -ts, --tileSize Tile size (default: "512")
52 | -tq, --tileJpgQuality Jpg Image quality of tiles in percent (default: "85")
53 | -tp, --tilePathTemplate Tile path template (default: "{{levelCount}}/{{face}}{{y}}_{{x}}.{{fileType}}")
54 | -tpt, --tilePathType Tile image type (default: "jpg")
55 | -c, --renderCube Render cube sites in full resolution
56 | -cp, --cubePath Cube sites path (default: "{{face}}.jpg")
57 | -cq, --cubeJpgQuality Cube Jpg Image quality (default: "85")
58 | -pi, --previewIgnore Dont render preview
59 | -pcp, --previewCubePath Path and name of preview image (default: "preview.q.jpg")
60 | -pcq, --previewCubeJpgQuality Preview quality in percent (default: "85")
61 | -pfp, --previewFlatPath Path and name of preview image (default: "preview.f.jpg")
62 | -pfo, --previewFlatOrder Face order from left to right (default: "bdflru")
63 | -pfq, --previewFlatJpgQuality Preview quality in percent (default: "85")
64 | -psp, --previewScaledPath Path and name of preview image (default: "preview.s.jpg")
65 | -psf, --previewScaledFactor Factor for one Downscaling (default: "1.4142135623730951")
66 | -psq, --previewScaledJpgQuality Preview quality in percent (default: "85")
67 | -pw, --previewWidth Preview width (default: "1000")
68 | -sp, --signaturImagePath Signature image
69 | -ss, --signaturSide Signature side (default: "d")
70 | -sb, --signaturBelow Signature below pano image
71 | -hi, --htmlIgnore Don't render html
72 | -ht, --htmlTitle Head-Title-Tag (default: inputImage)
73 | -hpp, --htmlPannellumFile Path of Pannellum .html file (default: "index.p.html")
74 | -hmp, --htmlMarzipanoFile Path of Marzipano .html file (default: "index.m.html")
75 | -zi, --zipIgnore Don't zip
76 | -zp, --zipPath Path for Zip File (default: "pano.zip")
77 | -v, --verbose verbose
78 | -h, --help display help for command
79 | ```
80 |
81 | ## Preview
82 |
83 | Made here: 47.162081, 10.923371
84 |
85 | ### Downscaled
86 |
87 | 
88 |
89 | ### Cubic
90 |
91 | 
92 |
93 | ## TODO
94 |
95 | - Flat image example
96 | - zip refactoring
97 | - parse exif data (needed?)
98 | - parse xmp (for Autopano Giga, but GoPro seems to let it die. So needed?)
99 |
100 | ## Many Thanks to
101 |
102 | - https://stackoverflow.com/questions/29678510/convert-21-equirectangular-panorama-to-cube-map
103 | - https://de.wikipedia.org/wiki/Alpha_Blending
104 | - https://stackoverflow.com/questions/1726630/formatting-a-number-with-exactly-two-decimals-in-javascript
105 |
--------------------------------------------------------------------------------
/src/cli.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | const converter = require('./converter');
4 | const {program} = require('commander');
5 | const fs = require('fs');
6 | const path = require('path');
7 |
8 | // find and parse package.json
9 | const pjp = path.resolve(__dirname, '..', 'package.json');
10 | const packageJson = JSON.parse(fs.readFileSync(pjp, 'utf-8'))
11 |
12 | // cli
13 | program.version(packageJson.version)
14 | program
15 | // Source
16 | .option('-i, --source ', 'Source image or config', 'panoconfig.json')
17 | .option('-ipa, --panoAngle ', 'Angle of pano', '360')
18 | .option('-ipy, --panoYOffset ', 'Y-Offset in degree [-90.0...90.0]', '0')
19 |
20 | // Output
21 | .option('-o, --output ', 'Output folder', null)
22 | .option('-te, --targetSize ', 'Image edge length of a face @ max resolution (default: inputImage.x / 4)', null)
23 | .option('-fr, --facesToRender ', 'Faces To render', 'flrbud')
24 |
25 | // Config file
26 | .option('-cs, --configSave', 'Save Config', 'false')
27 |
28 | // Tiles
29 | .option('-ti, --tilesIgnore', 'Dont render tiles', 'false')
30 | .option('-ts, --tileSize ', 'Tile size', '512')
31 | .option('-tq, --tileJpgQuality ', 'Jpg Image quality of tiles in percent', '85')
32 | .option('-tp, --tilePathTemplate ', 'Tile path template', '{{levelCount}}/{{face}}{{y}}_{{x}}.{{fileType}}')
33 | .option('-tpt, --tilePathType ', 'Tile image type', 'jpg')
34 |
35 | // Cube
36 | .option('-c, --renderCube', 'Render cube sites in full resolution', 'true')
37 | .option('-cp, --cubePath ', 'Cube sites path', '{{face}}.jpg')
38 | .option('-cq, --cubeJpgQuality ', 'Cube Jpg Image quality', '85')
39 |
40 | // Preview
41 | .option('-pi, --previewIgnore', 'Dont render preview', 'false')
42 | .option('-pcp, --previewCubePath ', 'Path and name of preview image', 'preview.q.jpg')
43 | .option('-pcq, --previewCubeJpgQuality ', 'Preview quality in percent', '85')
44 | .option('-pfp, --previewFlatPath ', 'Path and name of preview image', 'preview.f.jpg')
45 | .option('-pfo, --previewFlatOrder ', 'Face order from left to right', 'bdflru')
46 | .option('-pfq, --previewFlatJpgQuality ', 'Preview quality in percent', '85')
47 | .option('-psp, --previewScaledPath ', 'Path and name of preview image', 'preview.s.jpg')
48 | .option('-psf, --previewScaledFactor ', 'Factor for one Downscaling', '2')
49 | .option('-psq, --previewScaledJpgQuality ', 'Preview quality in percent', '85')
50 | .option('-pw, --previewWidth ', 'Preview width', '1000')
51 |
52 | // Signature
53 | .option('-sp, --signaturImagePath ', 'Signature image', null)
54 | .option('-ss, --signaturSide ', 'Signature side', 'd')
55 | .option('-sb, --signaturBelow', 'Signature below pano image', 'false')
56 |
57 | // Html
58 | .option('-hi, --htmlIgnore', 'Don\'t render html', 'false')
59 | .option('-ht, --htmlTitle ', 'Head-Title-Tag (default: inputImage)', null)
60 | .option('-hpp, --htmlPannellumFile ', 'Path of Pannellum .html file', 'index.p.html')
61 | .option('-hmp, --htmlMarzipanoFile ', 'Path of Marzipano .html file', 'index.m.html')
62 |
63 | // Zip
64 | .option('-zi, --zipIgnore', 'Don\'t zip', 'false')
65 | .option('-zp, --zipPath ', 'Path for Zip File', null)
66 |
67 | // Debug
68 | .option('-v, --verbose', 'verbose', 'true')
69 |
70 | .parse(process.argv);
71 |
72 | let cfg;
73 | if (program.source.endsWith('.json')) {
74 | console.log(`Load config from File ${program.source}`)
75 | cfg = JSON.parse(fs.readFileSync(program.source, "utf8"));
76 | } else {
77 | let htmlTitle = program.source;
78 | if (program.htmlTitle && program.htmlTitle.length !== 0) {
79 | htmlTitle = program.htmlTitle;
80 | }
81 |
82 | let zipPath = program.zipPath;
83 | if (!zipPath) {
84 | const x = path.parse(program.source);
85 | x.base = `${x.name}.zip`;
86 | zipPath = path.format(x);
87 | }
88 |
89 | let outputPath = program.output;
90 | if (!outputPath) {
91 | const x = path.parse(program.source);
92 | x.base = x.name;
93 | outputPath = path.format(x);
94 | }
95 |
96 | cfg = {
97 | // Source
98 | sourceImage: program.source,
99 | panoAngle: parseFloat(program.panoAngle),
100 | panoYOffset: parseFloat(program.panoYOffset),
101 |
102 | // Target
103 | targetFolder: outputPath,
104 | targetImgSize: program.targetSize,
105 | facesToRender: program.facesToRender,
106 |
107 | // Tiles
108 | backgroundColor: {r: 0, g: 0, b: 0, a: 0},
109 | tilesIgnore: Boolean(program.tilesIgnore),
110 | tileSize: parseInt(program.tileSize, 10),
111 | tileJpgQuality: parseInt(program.tileJpgQuality, 10),
112 | tileFileType: program.tilePathType,
113 | tilePathTemplate: program.tilePathTemplate,
114 |
115 | // Cube
116 | renderCube: Boolean(program.renderCube),
117 | cubePath: program.cubePath,
118 | cubeJpgQuality: program.cubeJpgQuality,
119 |
120 | // Preview
121 | previewIgnore: Boolean(program.previewIgnore),
122 | previewWidth: parseInt(program.previewWidth, 10),
123 | previewCubePath: program.previewCubePath,
124 | previewCubeJpgQuality: parseInt(program.previewCubeJpgQuality, 10),
125 | previewFlatPath: program.previewFlatPath,
126 | previewFlatJpgQuality: parseInt(program.previewFlatJpgQuality, 10),
127 | previewFlatOrder: program.previewFlatOrder,
128 | previewScaledPath: program.previewScaledPath,
129 | previewScaledFactor: parseFloat(program.previewScaledFactor),
130 | previewScaledJpgQuality: parseInt(program.previewScaledJpgQuality, 10),
131 |
132 | // Signature
133 | signaturImagePath: program.signaturImagePath,
134 | signaturSide: program.signaturSide,
135 | signaturBelow: Boolean(program.signaturBelow),
136 |
137 | // Html
138 | htmlIgnore: Boolean(program.htmlIgnore),
139 | htmlTitle,
140 | htmlPannellumFile: program.htmlPannellumFile,
141 | htmlMarzipanoFile: program.htmlMarzipanoFile,
142 |
143 | // Zip
144 | zipPath: zipPath,
145 | zipIgnore: Boolean(program.zipIgnore),
146 |
147 | // Debug
148 | verbose: Boolean(program.verbose)
149 | };
150 |
151 | if (program.configSave) {
152 | let cfgFileName = program.input || 'panoconfig.json';
153 | fs.writeFileSync(cfgFileName, JSON.stringify(cfg, null, 2));
154 |
155 | return;
156 | }
157 | }
158 |
159 | if (cfg.verbose) {
160 | console.log(cfg)
161 | }
162 |
163 | converter.renderPano(cfg).then();
164 |
--------------------------------------------------------------------------------
/src/renderer.js:
--------------------------------------------------------------------------------
1 | const EventEmitter = require('events');
2 | const {IMG,BigIMG} = require('./img');
3 |
4 | class FaceRenderer extends EventEmitter {
5 |
6 | constructor(sourceImage, w, xOffset, yOffset) {
7 | super();
8 | this.sourceImage = sourceImage;
9 | this.w = w;
10 | this.xOffset = xOffset;
11 | this.yOffset = yOffset;
12 | }
13 |
14 | render(face, outImgSize) {
15 | console.log('FaceRenderer.render', {face, outImgSize})
16 | const img = new BigIMG();
17 | img.create(outImgSize, outImgSize);
18 | img.fill({r: 0, g: 0, b: 0, a: 0});
19 |
20 | this.convert2(this.w,
21 | outImgSize,
22 | face,
23 | (x, y) => this.sourceImage.getPixel(x - this.xOffset, y - this.yOffset),
24 | (x, y, color) => img.setPixel(x, y, color)
25 | )
26 | return img;
27 | }
28 |
29 | outImgToXYZ2(a, b, face) {
30 | // a: [-1..1]
31 | // b: [-1..1]
32 | if (face === 0) {
33 | // back
34 | return {x: -1, y: -a, z: -b}
35 | } else if (face === 1) {
36 | // left
37 | return {x: a, y: -1, z: -b}
38 | } else if (face === 2) {
39 | // front
40 | return {x: 1, y: a, z: -b}
41 | } else if (face === 3) {
42 | // right
43 | return {x: -a, y: 1, z: -b}
44 | } else if (face === 4) {
45 | // top
46 | return {x: b, y: a, z: 1}
47 | } else if (face === 5) {
48 | // bottom
49 | return {x: -b, y: a, z: -1}
50 | }
51 | }
52 |
53 | convert2(inX, edgeOut, face, getPixel, setPixel) {
54 | const inSize = {x: inX, y: inX / 2, edge: inX / 4}
55 |
56 | this.emit('begin', edgeOut * edgeOut);
57 |
58 | for (let i = 0; i < edgeOut; ++i) {
59 | const a = (2 * i / edgeOut) - 1; // [-1..1[
60 |
61 | for (let j = 0; j < edgeOut; ++j) {
62 | const b = (2 * j / edgeOut) - 1; // [-1..1[
63 |
64 | const xyz = this.outImgToXYZ2(a, b, face)
65 | try {
66 | let rgba = calcPixel(xyz, inSize, getPixel);
67 | setPixel(i, j, rgba);
68 | } catch (err) {
69 | console.log(err, {i, j, a, b, xyz})
70 | throw err;
71 | }
72 |
73 | }
74 | if(i%100===0){
75 | this.emit('progress', (edgeOut * i));
76 | }
77 | }
78 |
79 | this.emit('progress', edgeOut * edgeOut);
80 | this.emit('end');
81 | }
82 | }
83 |
84 | class PreviewRenderer extends EventEmitter {
85 |
86 | constructor(sourceImage, w, xOffset, yOffset) {
87 | // constructor(sourceImage) {
88 | super();
89 | this.sourceImage = sourceImage;
90 | this.w = w;
91 | this.xOffset = xOffset;
92 | this.yOffset = yOffset;
93 | }
94 |
95 | render(previewWidth) {
96 | const img = new IMG();
97 | img.create(previewWidth, previewWidth * 3 / 4);
98 |
99 | this.convert(
100 | this.w,
101 | previewWidth,
102 | (x, y) => this.sourceImage.getPixel(x - this.xOffset, y - this.yOffset),
103 | (x, y, pixel) => img.setPixel(x, y, pixel)
104 | )
105 | return img;
106 | }
107 |
108 | outImgToXYZ(a, b, face) {
109 | // a: [0..8[
110 | // b: [0..6[
111 | if (face === 0) {
112 | // back
113 | // a: [0..2[
114 | // b: [2..4[
115 | return {x: -1.0, y: 1.0 - a, z: 3.0 - b} // y,z: [-1..1]
116 | } else if (face === 1) {
117 | // left
118 | // a: [2..4[
119 | // b: [2..4[
120 | return {x: a - 3.0, y: -1.0, z: 3.0 - b} // x,z: [-1..1]
121 | } else if (face === 2) {
122 | // front
123 | // a: [4..6[
124 | // b: [2..4[
125 | return {x: 1.0, y: a - 5.0, z: 3.0 - b} // y,z: [-1..1]
126 | } else if (face === 3) {
127 | // right
128 | // a: [6..8[
129 | // b: [2..4[
130 | return {x: 7.0 - a, y: 1.0, z: 3.0 - b} // x,z: [-1..1]
131 | } else if (face === 4) {
132 | // top
133 | // a: [4..6[
134 | // b: [0..2[
135 | return {x: b - 1.0, y: a - 5.0, z: 1.0} // x,y: [-1..1]
136 | } else if (face === 5) {
137 | // bottom
138 | // a: [4..6[
139 | // b: [4..6[
140 | return {x: 5.0 - b, y: a - 5.0, z: -1.0} // y,z: [-1..1]
141 | }
142 | }
143 |
144 |
145 | convert(inX, outX, getPixel, setPixel) {
146 | const inSize = {x: inX, y: inX / 2, edge: inX / 4}
147 |
148 | const outSize = {x: outX, y: outX * 3 / 4}
149 | const edgeOut = outSize.x / 4 // the length of each edge in pixels
150 |
151 | for (let i = 0; i < outSize.x; ++i) {
152 | const a = 2 * i / edgeOut; // [0..8[
153 |
154 | const face = Math.floor(i / edgeOut) // 0 - back, 1 - left 2 - front, 3 - right
155 | let j1, j2;
156 | if (face === 2) {
157 | j1 = 0;
158 | j2 = edgeOut * 3;
159 | } else {
160 | j1 = edgeOut;
161 | j2 = edgeOut * 2;
162 | }
163 |
164 | for (let j = j1; j < j2; ++j) {
165 | const b = 2 * j / edgeOut; // [0..6[
166 |
167 | let face2;
168 | if (j < edgeOut) {
169 | // top
170 | face2 = 4
171 | } else if (j >= 2 * edgeOut) {
172 | // bottom
173 | face2 = 5
174 | } else {
175 | face2 = face
176 | }
177 |
178 | const xyz = this.outImgToXYZ(a, b, face2)
179 | let rgba = calcPixel(xyz, inSize, getPixel);
180 |
181 | setPixel(i, j, rgba);
182 | }
183 | }
184 | }
185 | }
186 |
187 | function calcPixel(xyz, inSize, getPixel) {
188 | const theta = Math.atan2(xyz.y, xyz.x) // range -pi to pi
189 | const r = Math.hypot(xyz.x, xyz.y)
190 | const phi = Math.atan2(xyz.z, r) // range -pi/2 to pi/2
191 |
192 | // source img coords
193 | const uf = (2.0 * inSize.edge * (theta + Math.PI) / Math.PI)
194 | const vf = (2.0 * inSize.edge * (Math.PI / 2 - phi) / Math.PI)
195 |
196 | // Use bilinear interpolation between the four surrounding pixels
197 | const u1 = Math.floor(uf) // coord of pixel to bottom left
198 | const v1 = Math.floor(vf)
199 | const u2 = u1 + 1 // coords of pixel to top right
200 | const v2 = v1 + 1
201 | const mu = uf - u1 // fraction of way across pixel
202 | const nu = vf - v1
203 |
204 | // Pixel values of four corners
205 | try {
206 | const A = getPixel(u1 % inSize.x, clip(v1, 0, inSize.y - 1));
207 | const B = getPixel(u2 % inSize.x, clip(v1, 0, inSize.y - 1))
208 | const C = getPixel(u1 % inSize.x, clip(v2, 0, inSize.y - 1))
209 | const D = getPixel(u2 % inSize.x, clip(v2, 0, inSize.y - 1))
210 |
211 | // interpolate
212 | return {
213 | r: Math.floor(A.r * (1 - mu) * (1 - nu) + B.r * (mu) * (1 - nu) + C.r * (1 - mu) * nu + D.r * mu * nu),
214 | g: Math.floor(A.g * (1 - mu) * (1 - nu) + B.g * (mu) * (1 - nu) + C.g * (1 - mu) * nu + D.g * mu * nu),
215 | b: Math.floor(A.b * (1 - mu) * (1 - nu) + B.b * (mu) * (1 - nu) + C.b * (1 - mu) * nu + D.b * mu * nu),
216 | a: Math.floor(A.a * (1 - mu) * (1 - nu) + B.a * (mu) * (1 - nu) + C.a * (1 - mu) * nu + D.a * mu * nu)
217 | };
218 | } catch (err) {
219 | console.log({u1, v1, u2, v2, mu, nu})
220 | throw err;
221 | }
222 | }
223 |
224 | function clip(v, min, max) {
225 | if (v < min) {
226 | return min;
227 | }
228 | if (v > max) {
229 | return max;
230 | }
231 | return v;
232 | }
233 |
234 | module.exports.FaceRenderer = FaceRenderer;
235 | module.exports.PreviewRenderer = PreviewRenderer;
236 |
--------------------------------------------------------------------------------
/src/img.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const EventEmitter = require('events');
3 | const buffer = require('buffer');
4 |
5 | const jpeg = require('jpeg-js');
6 | const PNG = require("pngjs").PNG;
7 |
8 | const {Bilinear} = require('./scale');
9 |
10 | class BaseIMG extends EventEmitter {
11 | _width;
12 | _height;
13 | _backgroundColor = {r: 0, g: 0, b: 0, a: 0}
14 |
15 | constructor() {
16 | super();
17 | }
18 |
19 | create(w, h) {
20 | this._width = w;
21 | this._height = h;
22 | return this;
23 | }
24 |
25 | fill(color) {
26 | this.emit('fillBegin', this._height);
27 |
28 | for (let j = 0; j < this._height; ++j) {
29 | for (let i = 0; i < this._width; ++i) {
30 | this.setPixel(i, j, color)
31 | }
32 | this.emit('fillProgress', this.j + 1);
33 | }
34 |
35 | this.emit('fillEnd');
36 | return this;
37 | }
38 |
39 | drawImg(sourceImg, xOff, yOff) {
40 | for (let j = 0; j < sourceImg.height; ++j) {
41 | for (let i = 0; i < sourceImg.height; ++i) {
42 | this.setPixel(i + xOff, j + yOff, sourceImg.getPixel(i, j));
43 | }
44 | }
45 | }
46 |
47 | /**
48 | * like drawImh but with alpha blending Wikipedia
49 | *
50 | * @param sourceImg
51 | * @param xOff
52 | * @param yOff
53 | * @param below
54 | */
55 | blendImg(sourceImg, xOff, yOff, below = false) {
56 | for (let y = 0; y < sourceImg.height; ++y) {
57 | for (let x = 0; x < sourceImg.width; ++x) {
58 |
59 | let A = sourceImg.getPixel(x, y);
60 | let B = this.getPixel(x + xOff, y + yOff);
61 | if (below) {
62 | let x = A;
63 | A = B;
64 | B = x;
65 | }
66 |
67 | const a_A = A.a / 255;
68 | const a_NA = 1 - a_A;
69 | const b_A = B.a / 255;
70 | const a_C = a_A + (a_NA * b_A);
71 | const pixel = {
72 | r: ((B.r * a_NA * b_A) + (A.r * a_A)) / a_C,
73 | g: ((B.g * a_NA * b_A) + (A.g * a_A)) / a_C,
74 | b: ((B.b * a_NA * b_A) + (A.b * a_A)) / a_C,
75 | a: a_C
76 | }
77 |
78 | this.setPixel(x + xOff, y + yOff, pixel);
79 | }
80 | }
81 | }
82 |
83 | newScaledByFactor(factor) {
84 | const tX = Math.round(this.width * factor);
85 | const tY = Math.round(this._height * factor);
86 |
87 | const resultImage = (BaseIMG.isBigIMGNeeded(tX, tY))
88 | ? new BigIMG().create(tX, tY)
89 | : new IMG().create(tX, tY);
90 |
91 | const bilinear = new Bilinear();
92 | bilinear.on('begin', lineCount => this.emit('scaleBegin', lineCount));
93 | bilinear.on('progress', line => this.emit('scaleProgress', line));
94 | bilinear.on('end', () => this.emit('scaleEnd'))
95 | bilinear.scale(
96 | {w: this.width, h: this.height},
97 | {w: resultImage.width, h: resultImage.height},
98 | (x, y) => {
99 | return this.getPixel(x, y)
100 | },
101 | (x, y, pixel) => {
102 | resultImage.setPixel(x, y, pixel)
103 | });
104 |
105 | return resultImage;
106 | }
107 |
108 | toIMG() {
109 | return this;
110 | }
111 |
112 | get width() {
113 | return this._width;
114 | }
115 |
116 | get height() {
117 | return this._height;
118 | }
119 |
120 | get backgroundColor() {
121 | return this._backgroundColor;
122 | }
123 |
124 | set backgroundColor(value) {
125 | this._backgroundColor = value;
126 | }
127 |
128 | write(path, options) {
129 | throw new Error('Not supported');
130 | }
131 |
132 | load(path) {
133 | throw new Error('Not supported');
134 | }
135 |
136 | getPixel(x, y) {
137 | throw new Error('Not supported');
138 | }
139 |
140 | setPixel(x, y, pixel) {
141 | throw new Error('Not supported');
142 | }
143 |
144 | static isJpg(path) {
145 | const p = path.toLowerCase();
146 | return (p.endsWith('.jpg') || p.endsWith('.jpg'));
147 | }
148 |
149 | static isPng(path) {
150 | const p = path.toLowerCase();
151 | return (p.endsWith('.png'));
152 | }
153 |
154 | static isBigIMGNeeded(w, h) {
155 | const l = h * w * 4;
156 | return (l > buffer.constants.MAX_LENGTH);
157 | }
158 | }
159 |
160 | class BigIMG
161 | extends BaseIMG {
162 | _data;
163 |
164 | constructor() {
165 | super();
166 | }
167 |
168 | create(w, h) {
169 | super.create(w, h);
170 | this._data = [];
171 | for (let i = 0; i < h; ++i) {
172 | this._data.push(new Buffer.alloc(w * 4));
173 | }
174 | return this;
175 | }
176 |
177 | getPixel(x, y) {
178 | if (x < 0 || x >= this._width || y < 0 || y >= this._height) {
179 | return this._backgroundColor;
180 | } else {
181 | const b = this._data[y];
182 | const adr = (x << 2);
183 | return {r: b[adr], g: b[adr + 1], b: b[adr + 2], a: b[adr + 3],}
184 | }
185 | }
186 |
187 | setPixel(x, y, pixel) {
188 | if (x >= 0 && x < this._width && y >= 0 && y < this._height) {
189 | const b = this._data[y];
190 | let adr = (x << 2);
191 |
192 | b[adr++] = pixel.r;
193 | b[adr++] = pixel.g;
194 | b[adr++] = pixel.b;
195 | b[adr] = pixel.a;
196 | }
197 | }
198 |
199 | toIMG() {
200 | const result = new IMG();
201 | result.create(this._width, this._height);
202 | for (let y = 0; y < this._height; ++y) {
203 | for (let x = 0; x < this._width; ++x) {
204 | result.setPixel(x, y, this.getPixel(x, y));
205 | }
206 | }
207 | return result;
208 | }
209 |
210 | }
211 |
212 |
213 | class IMG extends BaseIMG {
214 | _data;
215 |
216 | constructor() {
217 | super();
218 | }
219 |
220 | create(w, h) {
221 | super.create(w, h);
222 | const l = h * w * 4;
223 | if (l > buffer.constants.MAX_LENGTH) {
224 | throw new Error(`IMG cant handle this size: ${l}. Max is ${buffer.constants.MAX_LENGTH}`)
225 | }
226 | this._data = new Buffer.alloc(l);
227 | return this;
228 | }
229 |
230 | write(path, options) {
231 | options = options || {jpgQuality: 85}
232 | if (BaseIMG.isPng(path)) {
233 | const buffer = PNG.sync.write({width: this._width, height: this._height, data: this._data}, {
234 | colorType: 6,
235 | inputHasAlpha: true
236 | });
237 | fs.writeFileSync(path, buffer);
238 | return true;
239 | } else if (BaseIMG.isJpg(path)) {
240 | const jpegImageData = jpeg.encode({
241 | width: this._width,
242 | height: this.height,
243 | data: this._data
244 | }, options.jpgQuality);
245 | fs.writeFileSync(path, jpegImageData.data);
246 | return true;
247 | }
248 | return false;
249 | }
250 |
251 | async load(path) {
252 | if (BaseIMG.isJpg(path)) {
253 | const jpegData = fs.readFileSync(path);
254 | const rawImageData = jpeg.decode(jpegData, {maxMemoryUsageInMB: 100000, maxResolutionInMP: 100000});
255 | this._data = rawImageData.data;
256 | this._width = rawImageData.width;
257 | this._height = rawImageData.height;
258 | return true;
259 | } else if (BaseIMG.isPng(path)) {
260 | const data = fs.readFileSync(path);
261 | const png = PNG.sync.read(data);
262 | this._data = png.data;
263 | this._width = png.width;
264 | this._height = png.height;
265 | }
266 | return false;
267 | }
268 |
269 | getPixel(x, y) {
270 | if (x < 0 || x >= this._width || y < 0 || y >= this._height) {
271 | return this._backgroundColor;
272 | } else {
273 | const adr = ((y * this._width) + x) << 2;
274 | return {r: this._data[adr], g: this._data[adr + 1], b: this._data[adr + 2], a: this._data[adr + 3],}
275 | }
276 | }
277 |
278 | setPixel(x, y, pixel) {
279 | if (x >= 0 && x < this._width && y >= 0 && y < this._height) {
280 | let adr = ((y * this._width) + x) << 2;
281 | this._data[adr++] = pixel.r;
282 | this._data[adr++] = pixel.g;
283 | this._data[adr++] = pixel.b;
284 | this._data[adr] = pixel.a;
285 | }
286 | }
287 | }
288 |
289 | module.exports.IMG = IMG;
290 | module.exports.BigIMG = BigIMG;
291 |
--------------------------------------------------------------------------------
/src/psd.js:
--------------------------------------------------------------------------------
1 | const {RandomAccessFile} = require('./randomaccessfile');
2 | const EventEmitter = require('events');
3 | const xml2js = require('xml2js');
4 |
5 | module.exports.PSD = class PSD extends EventEmitter {
6 | _lines = [];
7 | _width;
8 | _height;
9 | _channels;
10 | _backgroundColor = {r: 0, g: 0, b: 0, a: 0}
11 |
12 | constructor() {
13 | super();
14 | }
15 |
16 | get backgroundColor() {
17 | return this._backgroundColor;
18 | }
19 |
20 | set backgroundColor(value) {
21 | this._backgroundColor = value;
22 | }
23 |
24 | get width() {
25 | return this._width;
26 | }
27 |
28 | get height() {
29 | return this._height;
30 | }
31 |
32 | getPixel(x, y) {
33 | // console.log(this._lines)
34 | if (x < 0 || x >= this._width || y < 0 || y >= this._height) {
35 | return this._backgroundColor;
36 | } else {
37 | return {
38 | r: this._lines[y][x],
39 | g: this._lines[y + this._height][x],
40 | b: this._lines[y + this._height + this._height][x],
41 | a: 255
42 | }
43 | }
44 | }
45 |
46 | async loadHeaderOnly(path) {
47 | return new Promise(async resolve => {
48 | let {fd} = await this.readHeader(path);
49 | await RandomAccessFile.close(fd);
50 | resolve(true);
51 | });
52 | }
53 |
54 | async load(path) {
55 | return new Promise(async resolve => {
56 | let {offset, fd, version} = await this.readHeader(path);
57 |
58 | // Image Data
59 | // type 0:raw, 1:rle
60 | let buf = await RandomAccessFile.read(fd, offset, 2);
61 | offset += 2;
62 | let compression = buf.readUInt16BE(0);
63 | console.log('Compression', compression);
64 | if (compression === 0) {
65 | await this.readRAWData(buf, fd, offset);
66 | } else if (compression === 1) {
67 | await this.readRLEData(version, buf, fd, offset);
68 | }
69 |
70 | await RandomAccessFile.close(fd);
71 |
72 | resolve(true);
73 | });
74 | }
75 |
76 | async readHeader(path) {
77 | let buf;
78 | let offset = 0;
79 |
80 | const fileSize = RandomAccessFile.fileSize(path);
81 | console.log('fileSize', fileSize);
82 |
83 | const fd = await RandomAccessFile.open(path);
84 |
85 | // File Header
86 | buf = await RandomAccessFile.read(fd, offset, 26);
87 | offset += 26;
88 | console.log('Signature', buf.toString('UTF-8', 0, 3));
89 | let version = buf.readUInt16BE(4); // PSD: 1; PSB: 2
90 | console.log('Version', version);
91 | this._channels = buf.readUInt16BE(12);
92 | console.log('Channels', this._channels);
93 | this._height = buf.readUInt32BE(14);
94 | console.log('Height', this._height);
95 | this._width = buf.readUInt32BE(18);
96 | console.log('Width', this._width);
97 | console.log('Depth', buf.readUInt16BE(22));
98 | console.log('ColorMode', buf.readUInt16BE(24));
99 |
100 | // Color Mode Data
101 | buf = await RandomAccessFile.read(fd, offset, 4);
102 | offset += 4;
103 | let colorModeLength = buf.readUInt32BE(0);
104 | console.log('Color Mode Data length', colorModeLength);
105 | offset += colorModeLength;
106 |
107 | // Image Resources
108 | buf = await RandomAccessFile.read(fd, offset, 4);
109 | offset += 4;
110 | let imageResourceLength = buf.readUInt32BE(0);
111 | console.log('Image Resources length', imageResourceLength);
112 | buf = await RandomAccessFile.read(fd, offset, imageResourceLength);
113 | await this.parseImageResource(buf);
114 |
115 | offset += imageResourceLength;
116 |
117 | // Layer and Mask Information
118 | let layerAndMaskInformationLength;
119 | if (version === 1) {
120 | buf = await RandomAccessFile.read(fd, offset, 4);
121 | offset += 4;
122 | layerAndMaskInformationLength = buf.readUInt32BE(0);
123 | } else {
124 | buf = await RandomAccessFile.read(fd, offset, 8);
125 | offset += 8;
126 | layerAndMaskInformationLength = (buf.readUInt32BE(0) * Math.pow(2, 32)) + buf.readUInt32BE(4);
127 | }
128 | console.log('Layer and Mask Information length', layerAndMaskInformationLength);
129 |
130 | return {offset, fd, version};
131 | }
132 |
133 | async parseImageResource(buf) {
134 | let idx = 0;
135 | const signature = buf.toString('utf8', 0, 4);
136 | for (; idx < buf.length;) {
137 |
138 | if (signature === '8BIM') {
139 | idx += 4;
140 | const id = buf.readUInt16BE(idx);
141 | idx += 2;
142 | let name = '';
143 | for (; ;) {
144 | const a = buf[idx];
145 | const b = buf[idx + 1];
146 | idx += 2;
147 | if (b === 0) {
148 | if (a !== 0) {
149 | name += String.fromCharCode(a);
150 | }
151 | break;
152 | } else {
153 | name += String.fromCharCode(a);
154 | name += String.fromCharCode(b);
155 | }
156 | }
157 | const size = buf.readUInt32BE(idx);
158 | idx += 4;
159 | const data = buf.subarray(idx, idx + size);
160 | console.log({id, name, size})
161 | idx += size;
162 | if (id === 1058) {
163 | await this.parseExif(data)
164 | // EXIF Data 1
165 | }
166 | if (id === 1059) {
167 | // EXIF Data 3
168 | // console.log('EXIF Data 3', data.toString());
169 | }
170 | if (id === 1060) {
171 | // XMP metadata
172 | await this.parseXMP(data)
173 | }
174 | //console.log(buf.toString())
175 | }
176 | }
177 | }
178 |
179 | async parseExif(data) {
180 | // add jpg prefix, see https://www.media.mit.edu/pia/Research/deepview/exif.html
181 | const l = data.length + 8;
182 | const l1 = Math.floor(l / 256);
183 | const l2 = l % 256;
184 | const prefix = Buffer.from([0xff, 0xe1, l1, l2, 0x45, 0x78, 0x69, 0x66, 0, 0])
185 | const jpg = Buffer.concat([prefix, data])
186 |
187 | const result = require('exif-parser').create(jpg).parse();
188 | console.log('EXIF:', result.tags)
189 | }
190 |
191 | async parseXMP(data) {
192 | //console.log('XMP metadata', data.toString());
193 | const parser = new xml2js.Parser();
194 | try {
195 | parser.parseString(data.toString(), (e, d) => {
196 | // https://developers.google.com/streetview/spherical-metadata?hl=de
197 | d['x:xmpmeta']['rdf:RDF'][0]['rdf:Description'].forEach(description => {
198 | if (description['$']['xmlns:GPano']) {
199 | console.log('XMP:', JSON.stringify(description['$'], null, 2))
200 | }
201 | })
202 | })
203 | } catch (err) {
204 | console.log(err)
205 | }
206 | }
207 |
208 | async readRAWData(buf, fd, offset) {
209 | console.log('read RAW Data');
210 | this._lines = [];
211 | const lineCount = this.height * this._channels;
212 | this.emit('begin', lineCount);
213 | for (let x = 0; x < lineCount; ++x) {
214 | buf = await RandomAccessFile.read(fd, offset, this.width);
215 | this._lines.push(buf)
216 | offset += this.width;
217 | if (x % 100 === 0) {
218 | this.emit('progress', x);
219 | }
220 | }
221 | this.emit('progress', lineCount);
222 | this.emit('end');
223 | }
224 |
225 | async readRLEData(version, buf, fd, offset) {
226 | console.log('read RLE Data');
227 | this._lines = [];
228 | // line lengths
229 | const lineSizes = [];
230 | const lineCount = this._height * this._channels;
231 | console.log('lineCount', lineCount);
232 | if (version === 1) {
233 | buf = await RandomAccessFile.read(fd, offset, (lineCount * 2));
234 | offset += (lineCount * 2);
235 | console.log('lineSizes size', buf.length)
236 | for (let i = 0; i < lineCount; ++i) {
237 | lineSizes.push(buf.readUInt16BE(i << 1));
238 | }
239 | } else if (version === 2) {
240 | buf = await RandomAccessFile.read(fd, offset, (lineCount * 4));
241 | offset += (lineCount * 4);
242 | console.log('lineSizes size', buf.length)
243 | for (let i = 0; i < lineCount; ++i) {
244 | lineSizes.push(buf.readUInt32BE(i << 2));
245 | }
246 | }
247 | // console.log('Line Sizes', lineSizes);
248 | console.log('offset', offset);
249 |
250 | console.log('Read Image Data.');
251 |
252 | this.emit('begin', lineCount);
253 | for (let x = 0; x < lineCount; ++x) {
254 | buf = await RandomAccessFile.read(fd, offset, lineSizes[x]);
255 | let l = this.decodePackbits(buf, this.width);
256 | this._lines.push(l)
257 | offset += lineSizes[x];
258 | if (x % 100 === 0) {
259 | this.emit('progress', x);
260 | }
261 | }
262 | this.emit('progress', lineCount);
263 | this.emit('end');
264 | }
265 |
266 | decodePackbits(sourceBuffer, resultSize) {
267 | const result = Buffer.alloc(resultSize);
268 |
269 | let targetIndex = 0;
270 | let sourceIndex = 0;
271 | while (sourceIndex < sourceBuffer.length) {
272 | const byte = sourceBuffer.readInt8(sourceIndex++);
273 | // -128 -> skip
274 | if (byte === -128) {
275 | continue;
276 | }
277 |
278 | if (byte < 0) {
279 | // -1 to -127 -> one byte of data repeated (1 - byte) times
280 | let length = 1 - byte;
281 | const val = sourceBuffer[sourceIndex++];
282 | for (let i = 0; i < length; ++i) {
283 | result[targetIndex++] = val;
284 | }
285 | } else {
286 | // 0 to 127 -> (1 + byte) literal bytes
287 | let length = 1 + byte;
288 | for (let j = 0; j < length; ++j) {
289 | result[targetIndex++] = sourceBuffer[sourceIndex++];
290 | }
291 | }
292 | }
293 |
294 | if (targetIndex !== resultSize) {
295 | throw Error(`Wrong line size. Expected: ${resultSize} but is: ${targetIndex}`)
296 | }
297 |
298 | return result;
299 | }
300 |
301 | }
302 |
--------------------------------------------------------------------------------
/src/converter.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 |
4 | const archiver = require('archiver');
5 | const cliProgress = require('cli-progress');
6 | const prettyBytes = require('pretty-bytes');
7 | const twig = require('twig').twig;
8 |
9 | const {PSD} = require('./psd');
10 | const {IMG, BigIMG} = require('./img');
11 | const {Bilinear} = require('./scale');
12 | const pannellum = require('./pannellum');
13 | const marzipano = require('./marzipano');
14 | const {FaceRenderer, PreviewRenderer} = require('./renderer');
15 | const {Stopwatch} = require('./stopwatch');
16 |
17 | const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_grey)
18 |
19 | const defaultFaceNames = {
20 | 0: {filePrefix: 'b', index: 0, name: 'Back'},
21 | 1: {filePrefix: 'l', index: 1, name: 'Left'},
22 | 2: {filePrefix: 'f', index: 2, name: 'Front'},
23 | 3: {filePrefix: 'r', index: 3, name: 'Right'},
24 | 4: {filePrefix: 'u', index: 4, name: 'Top'},
25 | 5: {filePrefix: 'd', index: 5, name: 'Bottom'},
26 | 'b': {filePrefix: 'b', index: 0, name: 'Back'},
27 | 'l': {filePrefix: 'l', index: 1, name: 'Left'},
28 | 'f': {filePrefix: 'f', index: 2, name: 'Front'},
29 | 'r': {filePrefix: 'r', index: 3, name: 'Right'},
30 | 'u': {filePrefix: 'u', index: 4, name: 'Top'},
31 | 'd': {filePrefix: 'd', index: 5, name: 'Bottom'},
32 | };
33 |
34 | module.exports.renderPano = renderPano;
35 |
36 | async function renderPano(config) {
37 | const zipSource = {files: [], folders: []};
38 |
39 | const overallStopwatch = new Stopwatch().begin();
40 |
41 | // faceNames = faceNames || defaultFaceNames;
42 |
43 | console.log(config.sourceImage.toLowerCase().endsWith('.psd') || config.sourceImage.toLowerCase().endsWith('.psb'));
44 |
45 | // load Source Image
46 | const swImg = new Stopwatch().begin();
47 | let srcImage;
48 | console.log()
49 | console.log('+------------------------------------------------------------------------')
50 | console.log(`| Load Image '${config.sourceImage}'`);
51 | console.log('+------------------------------------------------------------------------')
52 | if (config.sourceImage.toLowerCase().endsWith('.psd') || config.sourceImage.toLowerCase().endsWith('.psb')) {
53 | srcImage = new PSD();
54 | srcImage.on('begin', lineCount => progressBar.start(lineCount - 1, 0, {speed: "N/A"}));
55 | srcImage.on('progress', line => progressBar.update(line));
56 | srcImage.on('end', () => progressBar.stop())
57 | if (config.previewIgnore && config.tilesIgnore && !config.renderCube) {
58 | await srcImage.loadHeaderOnly(config.sourceImage);
59 | } else {
60 | await srcImage.load(config.sourceImage);
61 | }
62 | } else {
63 | srcImage = new IMG();
64 | if (!await srcImage.load(config.sourceImage)) {
65 | throw 'Unsupported image file type'
66 | }
67 | }
68 | console.log(`Image loaded in ${swImg.getTimeString()}`)
69 |
70 | // Equirectangular outer bound
71 | console.log()
72 | console.log('+------------------------------------------------------------------------')
73 | console.log('| Equirectangular calculations')
74 | console.log('+------------------------------------------------------------------------')
75 |
76 | const outerWidth = config.panoAngle === 360 ? srcImage.width : Math.floor(srcImage.width * 360 / config.panoAngle);
77 | const outerHeight = Math.floor(outerWidth / 2);
78 | console.log({angel: config.panoAngle})
79 |
80 | // offset foy y-center pos
81 | const yShift = Math.floor(outerHeight * config.panoYOffset / 180);
82 | const yOff = Math.floor((outerHeight - srcImage.height) / 2) - yShift;
83 | const xOff = Math.floor((outerWidth - srcImage.width) / 2);
84 | console.log({outerWidth, outerHeight, srcImageWidth: srcImage.width, srcImageHeight: srcImage.height})
85 | console.log({xOff, yOff})
86 |
87 | // Preview
88 | const previewCubedPath = getPathAndCreateDir(config.targetFolder, config.previewCubePath);
89 | zipSource.files.push(previewCubedPath);
90 | const previewFlatPath = getPathAndCreateDir(config.targetFolder, config.previewFlatPath);
91 | zipSource.files.push(previewFlatPath);
92 | const previewScaledPath = getPathAndCreateDir(config.targetFolder, config.previewScaledPath);
93 | zipSource.files.push(previewScaledPath);
94 |
95 | if (!config.previewIgnore) {
96 | previewCube(config, srcImage, outerWidth, xOff, yOff, previewCubedPath);
97 | previewFlat(config, srcImage, outerWidth, xOff, yOff, previewFlatPath);
98 | previewScaled(srcImage, config, previewScaledPath);
99 | }
100 |
101 | // Level Data
102 | console.log()
103 | console.log('+------------------------------------------------------------------------')
104 | console.log('| Level Data')
105 | console.log('+------------------------------------------------------------------------')
106 |
107 | const targetImageSize = calculateTargetImageSize(config.targetImgSize || Math.floor(srcImage.width / 4), config.tileSize);
108 | console.log({targetImageSize});
109 | let levels = calculateLevels(targetImageSize, config.tileSize);
110 | // TODO levels may not the first part of path
111 | for (let i = 1; i <= levels.levelCount; ++i) {
112 | const folderPath = path.resolve(config.targetFolder, i.toString());
113 | zipSource.folders.push(folderPath);
114 | }
115 | console.log(JSON.stringify(levels, null, 2))
116 |
117 | // Tiles
118 | await tiles(srcImage, outerWidth, xOff, yOff, defaultFaceNames, targetImageSize, config, levels);
119 |
120 | // Html
121 | const hAngel = srcImage.height * 180 / outerHeight
122 | const area = {
123 | x: {min: config.panoAngle / -2, max: config.panoAngle / 2},
124 | y: {min: (hAngel / -2) + config.panoYOffset, max: (hAngel / 2) + config.panoYOffset}
125 | }
126 | let data = {
127 | autoLoad: true,
128 | levels,
129 | targetImageSize,
130 | area,
131 | pannellumPath: getPathAndCreateDir(config.targetFolder, config.htmlPannellumFile),
132 | marzipanoPath: getPathAndCreateDir(config.targetFolder, config.htmlMarzipanoFile)
133 | };
134 | console.log(JSON.stringify(data, null, 2))
135 | zipSource.files.push(data.pannellumPath);
136 | zipSource.files.push(data.marzipanoPath);
137 | if (!config.htmlIgnore) {
138 | html(config, data);
139 | }
140 |
141 | // Zip
142 | if (!config.zipIgnore) {
143 | await zip(config, zipSource);
144 | }
145 |
146 | console.log();
147 | console.log('+------------------------------------------------------------------------')
148 | console.log(`| finished in ${overallStopwatch.getTimeString()}`);
149 | console.log('+------------------------------------------------------------------------')
150 | }
151 |
152 | function calculateTargetImageSize(minSize, tileSize) {
153 |
154 | let result = 0;
155 | for (let e = 0; result < minSize; ++e) {
156 | result = Math.pow(2, e) * tileSize;
157 | }
158 | return result;
159 | }
160 |
161 | function zip(config, zipSource) {
162 | return new Promise((resolve, reject) => {
163 | const sw = new Stopwatch().begin();
164 |
165 | console.log()
166 | console.log('+------------------------------------------------------------------------')
167 | console.log('| ZIP')
168 | console.log('+------------------------------------------------------------------------')
169 | console.log(zipSource)
170 | let progress = false;
171 |
172 | // zip stream
173 | const zipFilePath = getPathAndCreateDir(config.targetFolder, config.zipPath);
174 | let zipStream = fs.createWriteStream(zipFilePath);
175 | zipStream.on('close', () => {
176 | console.log(`File Size: ${prettyBytes(archive.pointer())}`);
177 | resolve();
178 | console.log(`Zipped in ${sw.getTimeString()}`)
179 | });
180 | zipStream.on('warning', function (err) {
181 | if (err.code === 'ENOENT') {
182 | console.log('Warning', err)
183 | } else {
184 | reject(err);
185 | }
186 | });
187 | zipStream.on('error', function (err) {
188 | reject(err);
189 | });
190 |
191 | // archive
192 | let archive = archiver('zip', {
193 | zlib: {level: 9} // Sets the compression level.
194 | });
195 | archive.on('progress', function (progressData) {
196 | if (!progress) {
197 | progressBar.start(progressData.entries.total, progressData.entries.processed);
198 | progress = true;
199 | } else {
200 | progressBar.update(progressData.entries.processed);
201 | if (progressData.entries.total === progressData.entries.processed) {
202 | progressBar.stop()
203 | }
204 | }
205 | });
206 | archive.pipe(zipStream);
207 |
208 | // add files
209 | zipSource.files.forEach(file => {
210 | const name = path.parse(file).base;
211 | console.log(`Add file '${file}' as '${name}'`)
212 | archive.file(file, {name})
213 | });
214 |
215 | // add folders
216 | zipSource.folders.forEach(folder => {
217 | const name = path.parse(folder).base;
218 | console.log(`Add folder '${folder}' as '${name}'`)
219 | archive.directory(folder, name, {});
220 | });
221 |
222 | archive.finalize();
223 | });
224 | }
225 |
226 | function html(config, data) {
227 | const sw = new Stopwatch().begin();
228 |
229 | console.log()
230 | console.log('+------------------------------------------------------------------------')
231 | console.log('| Render Html')
232 | console.log('+------------------------------------------------------------------------')
233 |
234 | fs.writeFileSync(data.pannellumPath, pannellum.createHtml(config, data))
235 | fs.writeFileSync(data.marzipanoPath, marzipano.createHtml(config, data))
236 |
237 | console.log(`Html generated in ${sw.getTimeString()}`);
238 | }
239 |
240 | async function tiles(srcImage, w, xOff, yOff, faceNames, targetImageSize, config, levels) {
241 | if(config.tilesIgnore && !config.renderCube){
242 | return;
243 | }
244 |
245 | const swAll = new Stopwatch().begin();
246 |
247 | // load Signature Image
248 | let signatureImage;
249 | if (config.signaturImagePath && config.signaturSide.length > 0) {
250 | console.log(`Load signature image: '${config.signaturImagePath}'`)
251 | signatureImage = new IMG();
252 | await signatureImage.load(config.signaturImagePath);
253 | }
254 |
255 | // faces to render
256 | for (const f of config.facesToRender) {
257 | const swFace = new Stopwatch().begin();
258 |
259 | const face = defaultFaceNames[f];
260 | console.log()
261 | console.log('+------------------------------------------------------------------------')
262 | console.log(`| Render Face Tiles '${face.name}' (${targetImageSize}x${targetImageSize})px² (${face.index + 1}/6)`)
263 | console.log('+------------------------------------------------------------------------')
264 |
265 | const faceRenderer = new FaceRenderer(srcImage, w, xOff, yOff);
266 | console.log('Render Face');
267 | faceRenderer.on('begin', count => progressBar.start(count - 1, 0, {speed: "N/A"}));
268 | faceRenderer.on('progress', v => progressBar.update(v));
269 | faceRenderer.on('end', () => progressBar.stop())
270 | let faceImg = faceRenderer.render(face.index, targetImageSize);
271 | console.log(`Face rendered ${swFace.getTimeString()}`);
272 | console.log();
273 |
274 | // Set signature image
275 | if (signatureImage && config.signaturSide.indexOf(f) !== -1) {
276 | console.log(`Set signature image ${swFace.getTimeString()}`);
277 | console.log();
278 | const offX = (targetImageSize - signatureImage.width) / 2;
279 | const offY = (targetImageSize - signatureImage.height) / 2;
280 |
281 | // TODO use IMG.blendImg
282 | for (let y = 0; y < signatureImage.height; ++y) {
283 | for (let x = 0; x < signatureImage.width; ++x) {
284 |
285 | // https://de.wikipedia.org/wiki/Alpha_Blending
286 | let A = signatureImage.getPixel(x, y);
287 | let B = faceImg.getPixel(x + offX, y + offY);
288 | if (config.signaturBelow) {
289 | let x = A;
290 | A = B;
291 | B = x;
292 | }
293 |
294 | const a_A = A.a / 255;
295 | const a_NA = 1 - a_A;
296 | const b_A = B.a / 255;
297 | const a_C = a_A + (a_NA * b_A);
298 | const pixel = {
299 | r: ((B.r * a_NA * b_A) + (A.r * a_A)) / a_C,
300 | g: ((B.g * a_NA * b_A) + (A.g * a_A)) / a_C,
301 | b: ((B.b * a_NA * b_A) + (A.b * a_A)) / a_C,
302 | a: a_C
303 | }
304 |
305 | faceImg.setPixel(x + offX, y + offY, pixel);
306 | }
307 | }
308 | }
309 |
310 | // Save cube face
311 | if (config.renderCube) {
312 | const cubePathTemplate = twig({data: config.cubePath});
313 | const facePath = cubePathTemplate.render({face: f})
314 | const absFacePath = getPathAndCreateDir(config.targetFolder, facePath)
315 | console.log(`Render cube side to '${absFacePath}'`);
316 |
317 | faceImg.write(absFacePath, {jpgQuality: config.cubeJpgQuality});
318 | }
319 |
320 | // create and store tiles
321 | if (!config.tilesIgnore) {
322 | console.log('Create Tiles');
323 | swFace.begin();
324 | const tilePathTemplate = twig({data: config.tilePathTemplate});
325 | for (let level = levels.levelCount; level > 0; level--) {
326 | const countX = Math.ceil(faceImg.height / config.tileSize);
327 | const countY = Math.ceil(faceImg.width / config.tileSize);
328 | console.log(` Render Level: ${level} (${countX}x${countY} = ${countX*countY} Tiles)`)
329 |
330 | const imgCount = countX * countY;
331 | progressBar.start(imgCount, 0, {speed: "N/A"})
332 | for (let y = 0; y < countY; y++) {
333 | for (let x = 0; x < countX; x++) {
334 |
335 | let tilePath = tilePathTemplate.render({
336 | levelCount: level,
337 | levelIndex: level - 1,
338 | face: face.filePrefix,
339 | fileType: config.tileFileType,
340 | x, y
341 | })
342 | const tile = createTile(faceImg, x, y, config.tileSize);
343 | tile.write(getPathAndCreateDir(config.targetFolder, tilePath), {jpgQuality: config.tileJpgQuality});
344 | progressBar.update((y * countX) + x + 1);
345 | }
346 | }
347 | progressBar.stop()
348 |
349 | // TODO for HQ: double scale by Math.sqr(2) instead of 0.5
350 | faceImg = faceImg.newScaledByFactor(0.5);
351 | }
352 | console.log(`Face tiles created in ${swFace.getTimeString()}`);
353 | }
354 | }
355 |
356 | console.log(`All tiles created in ${swAll.getTimeString()}`);
357 | }
358 |
359 | function previewCube(config, srcImage, outerWidth, xOff, yOff, previewCubedPath) {
360 | const sw = new Stopwatch().begin();
361 |
362 | console.log()
363 | console.log('+------------------------------------------------------------------------')
364 | console.log(`| Render cubic preview(${config.previewWidth}x${config.previewWidth * 3 / 4}; xOff: ${xOff}, yOff:${yOff})`)
365 | console.log('+------------------------------------------------------------------------')
366 |
367 | const previewRenderer = new PreviewRenderer(srcImage, outerWidth, xOff, yOff);
368 | const previewImage = previewRenderer.render(config.previewWidth);
369 |
370 | previewImage.write(previewCubedPath, {jpgQuality: config.previewCubeJpgQuality});
371 |
372 | console.log(`Cubic preview generated in ${sw.getTimeString()}`);
373 | }
374 |
375 | function previewFlat(config, srcImage, outerWidth, xOff, yOff, previewCubedPath) {
376 | const sw = new Stopwatch().begin();
377 |
378 | const faceW = Math.floor(config.previewWidth / 6);
379 | console.log()
380 | console.log('+------------------------------------------------------------------------')
381 | console.log(`| Render flat preview(${faceW * 6}x${faceW}; xOff: ${xOff}, yOff:${yOff})`)
382 | console.log('+------------------------------------------------------------------------')
383 |
384 | const result = new IMG().create(faceW * 6, faceW);
385 | const faceRenderer = new FaceRenderer(srcImage, outerWidth, xOff, yOff);
386 |
387 | let faceOffset = 0;
388 | for (const f of config.previewFlatOrder) {
389 | const face = defaultFaceNames[f];
390 | let faceImg = faceRenderer.render(face.index, faceW);
391 | result.drawImg(faceImg, faceOffset, 0);
392 | faceOffset += faceW;
393 | }
394 |
395 | result.write(previewCubedPath, {jpgQuality: config.previewFlatJpgQuality});
396 |
397 | console.log(`Flat preview generated in ${sw.getTimeString()}`);
398 | }
399 |
400 | function previewScaled(srcImage, config, targetPath) {
401 | const sw = new Stopwatch().begin();
402 |
403 | console.log()
404 | console.log('+------------------------------------------------------------------------')
405 | console.log('| Render scaled preview');
406 | console.log('+------------------------------------------------------------------------')
407 | let previewImage = srcImage;
408 | const pMax = 1000;
409 | const f = config.previewScaledFactor;
410 |
411 | let w = previewImage.width;
412 | let h = previewImage.height;
413 | for (; ;) {
414 | const toScale = Math.max(previewImage.width / pMax, previewImage.height / pMax);
415 | let n = Math.min(f, toScale);
416 | console.log('Downscale for Preview', {toScale, n})
417 | if (n === 1) {
418 | previewImage.toIMG().write(targetPath, {jpgQuality: config.previewScaledJpgQuality});
419 | break;
420 | }
421 |
422 | const tempImg = new BigIMG().create(Math.round(w / n), Math.round(h / n));
423 |
424 | const bilinear = new Bilinear();
425 | bilinear.on('begin', lineCount => progressBar.start(lineCount - 1, 0, {speed: "N/A"}));
426 | bilinear.on('progress', line => progressBar.update(line));
427 | bilinear.on('end', () => progressBar.stop())
428 | bilinear.scale(
429 | {w: previewImage.width, h: previewImage.height},
430 | {w: tempImg.width, h: tempImg.height},
431 | (x, y) => {
432 | return previewImage.getPixel(x, y)
433 | },
434 | (x, y, pixel) => {
435 | tempImg.setPixel(x, y, pixel)
436 | });
437 | w /= n;
438 | h /= n;
439 | previewImage = tempImg;
440 | }
441 |
442 | console.log(`Scaled preview generated in ${sw.getTimeString()}`);
443 | }
444 |
445 | function createTile(sourceImage, xOffset, yOffset, tileSize) {
446 | let offX = xOffset * tileSize;
447 | let offY = yOffset * tileSize;
448 | let imgX = Math.min(tileSize, sourceImage.width - offX);
449 | let imgY = Math.min(tileSize, sourceImage.height - offY);
450 |
451 | const tile = new IMG();
452 | tile.create(imgX, imgY);
453 | for (let y = 0; y < imgY; ++y) {
454 | for (let x = 0; x < imgX; ++x) {
455 | const pixel = sourceImage.getPixel(offX + x, offY + y);
456 | tile.setPixel(x, y, pixel);
457 | }
458 | }
459 | return tile;
460 | }
461 |
462 | function calculateLevels(imgSize, tileSize) {
463 | const result = {levels: []};
464 | let level = 0;
465 | while (imgSize >= tileSize) {
466 | result.levels.push({tileSize, size: imgSize});
467 | level++;
468 | imgSize = Math.round(imgSize * 0.5);
469 | }
470 | result.levels.reverse();
471 | level = 0;
472 | result.levels.forEach(l => {
473 | l.level = level++;
474 | })
475 |
476 | result.levelCount = level;
477 | return result;
478 | }
479 |
480 | function getPathAndCreateDir(targetFolder, filePath) {
481 | const absoluteFilePath = path.resolve(targetFolder, filePath);
482 | const filDir = path.dirname(absoluteFilePath);
483 | fs.mkdirSync(filDir, {recursive: true});
484 | return absoluteFilePath;
485 | }
486 |
487 | function showMemoryUsage() {
488 | const used = process.memoryUsage();
489 | let res = [];
490 | for (let key in used) {
491 | res.push(`${key} ${Math.round(used[key] / 1024 / 1024 * 100) / 100} MB`);
492 | }
493 | console.log(res.join(' / '))
494 | }
495 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | "@babel/runtime@^7.8.4":
6 | version "7.10.5"
7 | resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.5.tgz#303d8bd440ecd5a491eae6117fd3367698674c5c"
8 | integrity sha512-otddXKhdNn7d0ptoFRHtMLa8LqDxLYwTjB4nYgM1yy5N6gU/MUf8zqyyLltCH3yAVitBzmwK4us+DD0l/MauAg==
9 | dependencies:
10 | regenerator-runtime "^0.13.4"
11 |
12 | "@sindresorhus/is@^0.14.0":
13 | version "0.14.0"
14 | resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
15 | integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
16 |
17 | "@szmarczak/http-timer@^1.1.2":
18 | version "1.1.2"
19 | resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421"
20 | integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==
21 | dependencies:
22 | defer-to-connect "^1.0.1"
23 |
24 | "@types/color-name@^1.1.1":
25 | version "1.1.1"
26 | resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0"
27 | integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==
28 |
29 | abbrev@1:
30 | version "1.1.1"
31 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
32 | integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
33 |
34 | ansi-align@^3.0.0:
35 | version "3.0.0"
36 | resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb"
37 | integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==
38 | dependencies:
39 | string-width "^3.0.0"
40 |
41 | ansi-regex@^4.1.0:
42 | version "4.1.0"
43 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
44 | integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
45 |
46 | ansi-regex@^5.0.0:
47 | version "5.0.0"
48 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
49 | integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
50 |
51 | ansi-styles@^4.1.0:
52 | version "4.2.1"
53 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359"
54 | integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==
55 | dependencies:
56 | "@types/color-name" "^1.1.1"
57 | color-convert "^2.0.1"
58 |
59 | anymatch@~3.1.1:
60 | version "3.1.1"
61 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
62 | integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
63 | dependencies:
64 | normalize-path "^3.0.0"
65 | picomatch "^2.0.4"
66 |
67 | archiver-utils@^2.1.0:
68 | version "2.1.0"
69 | resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-2.1.0.tgz#e8a460e94b693c3e3da182a098ca6285ba9249e2"
70 | integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==
71 | dependencies:
72 | glob "^7.1.4"
73 | graceful-fs "^4.2.0"
74 | lazystream "^1.0.0"
75 | lodash.defaults "^4.2.0"
76 | lodash.difference "^4.5.0"
77 | lodash.flatten "^4.4.0"
78 | lodash.isplainobject "^4.0.6"
79 | lodash.union "^4.6.0"
80 | normalize-path "^3.0.0"
81 | readable-stream "^2.0.0"
82 |
83 | archiver@^4.0.2:
84 | version "4.0.2"
85 | resolved "https://registry.yarnpkg.com/archiver/-/archiver-4.0.2.tgz#43c72865eadb4ddaaa2fb74852527b6a450d927c"
86 | integrity sha512-B9IZjlGwaxF33UN4oPbfBkyA4V1SxNLeIhR1qY8sRXSsbdUkEHrrOvwlYFPx+8uQeCe9M+FG6KgO+imDmQ79CQ==
87 | dependencies:
88 | archiver-utils "^2.1.0"
89 | async "^3.2.0"
90 | buffer-crc32 "^0.2.1"
91 | glob "^7.1.6"
92 | readable-stream "^3.6.0"
93 | tar-stream "^2.1.2"
94 | zip-stream "^3.0.1"
95 |
96 | async@^3.2.0:
97 | version "3.2.0"
98 | resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720"
99 | integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==
100 |
101 | balanced-match@^1.0.0:
102 | version "1.0.0"
103 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
104 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
105 |
106 | base64-js@^1.0.2:
107 | version "1.3.1"
108 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1"
109 | integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==
110 |
111 | binary-extensions@^2.0.0:
112 | version "2.1.0"
113 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.1.0.tgz#30fa40c9e7fe07dbc895678cd287024dea241dd9"
114 | integrity sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==
115 |
116 | bl@^4.0.1:
117 | version "4.0.2"
118 | resolved "https://registry.yarnpkg.com/bl/-/bl-4.0.2.tgz#52b71e9088515d0606d9dd9cc7aa48dc1f98e73a"
119 | integrity sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==
120 | dependencies:
121 | buffer "^5.5.0"
122 | inherits "^2.0.4"
123 | readable-stream "^3.4.0"
124 |
125 | bowser@2.7.0:
126 | version "2.7.0"
127 | resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.7.0.tgz#96eab1fa07fab08c1ec4c75977a7c8ddf8e0fe1f"
128 | integrity sha512-aIlMvstvu8x+34KEiOHD3AsBgdrzg6sxALYiukOWhFvGMbQI6TRP/iY0LMhUrHs56aD6P1G0Z7h45PUJaa5m9w==
129 |
130 | boxen@^4.2.0:
131 | version "4.2.0"
132 | resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64"
133 | integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==
134 | dependencies:
135 | ansi-align "^3.0.0"
136 | camelcase "^5.3.1"
137 | chalk "^3.0.0"
138 | cli-boxes "^2.2.0"
139 | string-width "^4.1.0"
140 | term-size "^2.1.0"
141 | type-fest "^0.8.1"
142 | widest-line "^3.1.0"
143 |
144 | brace-expansion@^1.1.7:
145 | version "1.1.11"
146 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
147 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
148 | dependencies:
149 | balanced-match "^1.0.0"
150 | concat-map "0.0.1"
151 |
152 | braces@~3.0.2:
153 | version "3.0.2"
154 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
155 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
156 | dependencies:
157 | fill-range "^7.0.1"
158 |
159 | buffer-crc32@^0.2.1, buffer-crc32@^0.2.13:
160 | version "0.2.13"
161 | resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242"
162 | integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
163 |
164 | buffer@^5.1.0, buffer@^5.5.0:
165 | version "5.6.0"
166 | resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.6.0.tgz#a31749dc7d81d84db08abf937b6b8c4033f62786"
167 | integrity sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==
168 | dependencies:
169 | base64-js "^1.0.2"
170 | ieee754 "^1.1.4"
171 |
172 | cacheable-request@^6.0.0:
173 | version "6.1.0"
174 | resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912"
175 | integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==
176 | dependencies:
177 | clone-response "^1.0.2"
178 | get-stream "^5.1.0"
179 | http-cache-semantics "^4.0.0"
180 | keyv "^3.0.0"
181 | lowercase-keys "^2.0.0"
182 | normalize-url "^4.1.0"
183 | responselike "^1.0.2"
184 |
185 | camelcase@^5.3.1:
186 | version "5.3.1"
187 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
188 | integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
189 |
190 | chalk@^3.0.0:
191 | version "3.0.0"
192 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
193 | integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
194 | dependencies:
195 | ansi-styles "^4.1.0"
196 | supports-color "^7.1.0"
197 |
198 | chokidar@^3.2.2:
199 | version "3.4.0"
200 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.0.tgz#b30611423ce376357c765b9b8f904b9fba3c0be8"
201 | integrity sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==
202 | dependencies:
203 | anymatch "~3.1.1"
204 | braces "~3.0.2"
205 | glob-parent "~5.1.0"
206 | is-binary-path "~2.1.0"
207 | is-glob "~4.0.1"
208 | normalize-path "~3.0.0"
209 | readdirp "~3.4.0"
210 | optionalDependencies:
211 | fsevents "~2.1.2"
212 |
213 | ci-info@^2.0.0:
214 | version "2.0.0"
215 | resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
216 | integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
217 |
218 | cli-boxes@^2.2.0:
219 | version "2.2.0"
220 | resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.0.tgz#538ecae8f9c6ca508e3c3c95b453fe93cb4c168d"
221 | integrity sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==
222 |
223 | cli-progress@^3.8.2:
224 | version "3.8.2"
225 | resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-3.8.2.tgz#abaf1fc6d6401351f16f068117a410554a0eb8c7"
226 | integrity sha512-qRwBxLldMSfxB+YGFgNRaj5vyyHe1yMpVeDL79c+7puGujdKJHQHydgqXDcrkvQgJ5U/d3lpf6vffSoVVUftVQ==
227 | dependencies:
228 | colors "^1.1.2"
229 | string-width "^4.2.0"
230 |
231 | clone-response@^1.0.2:
232 | version "1.0.2"
233 | resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
234 | integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
235 | dependencies:
236 | mimic-response "^1.0.0"
237 |
238 | color-convert@^2.0.1:
239 | version "2.0.1"
240 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
241 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
242 | dependencies:
243 | color-name "~1.1.4"
244 |
245 | color-name@~1.1.4:
246 | version "1.1.4"
247 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
248 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
249 |
250 | colors@^1.1.2:
251 | version "1.4.0"
252 | resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78"
253 | integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==
254 |
255 | commander@^5.1.0:
256 | version "5.1.0"
257 | resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae"
258 | integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==
259 |
260 | compress-commons@^3.0.0:
261 | version "3.0.0"
262 | resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-3.0.0.tgz#833944d84596e537224dd91cf92f5246823d4f1d"
263 | integrity sha512-FyDqr8TKX5/X0qo+aVfaZ+PVmNJHJeckFBlq8jZGSJOgnynhfifoyl24qaqdUdDIBe0EVTHByN6NAkqYvE/2Xg==
264 | dependencies:
265 | buffer-crc32 "^0.2.13"
266 | crc32-stream "^3.0.1"
267 | normalize-path "^3.0.0"
268 | readable-stream "^2.3.7"
269 |
270 | concat-map@0.0.1:
271 | version "0.0.1"
272 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
273 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
274 |
275 | configstore@^5.0.1:
276 | version "5.0.1"
277 | resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96"
278 | integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==
279 | dependencies:
280 | dot-prop "^5.2.0"
281 | graceful-fs "^4.1.2"
282 | make-dir "^3.0.0"
283 | unique-string "^2.0.0"
284 | write-file-atomic "^3.0.0"
285 | xdg-basedir "^4.0.0"
286 |
287 | core-util-is@~1.0.0:
288 | version "1.0.2"
289 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
290 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
291 |
292 | crc32-stream@^3.0.1:
293 | version "3.0.1"
294 | resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-3.0.1.tgz#cae6eeed003b0e44d739d279de5ae63b171b4e85"
295 | integrity sha512-mctvpXlbzsvK+6z8kJwSJ5crm7yBwrQMTybJzMw1O4lLGJqjlDCXY2Zw7KheiA6XBEcBmfLx1D88mjRGVJtY9w==
296 | dependencies:
297 | crc "^3.4.4"
298 | readable-stream "^3.4.0"
299 |
300 | crc@^3.4.4:
301 | version "3.8.0"
302 | resolved "https://registry.yarnpkg.com/crc/-/crc-3.8.0.tgz#ad60269c2c856f8c299e2c4cc0de4556914056c6"
303 | integrity sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==
304 | dependencies:
305 | buffer "^5.1.0"
306 |
307 | crypto-random-string@^2.0.0:
308 | version "2.0.0"
309 | resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
310 | integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
311 |
312 | debug@^2.2.0:
313 | version "2.6.9"
314 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
315 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
316 | dependencies:
317 | ms "2.0.0"
318 |
319 | debug@^3.2.6:
320 | version "3.2.6"
321 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
322 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
323 | dependencies:
324 | ms "^2.1.1"
325 |
326 | decompress-response@^3.3.0:
327 | version "3.3.0"
328 | resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
329 | integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
330 | dependencies:
331 | mimic-response "^1.0.0"
332 |
333 | deep-extend@^0.6.0:
334 | version "0.6.0"
335 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
336 | integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
337 |
338 | defer-to-connect@^1.0.1:
339 | version "1.1.3"
340 | resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591"
341 | integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==
342 |
343 | dot-prop@^5.2.0:
344 | version "5.2.0"
345 | resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb"
346 | integrity sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==
347 | dependencies:
348 | is-obj "^2.0.0"
349 |
350 | duplexer3@^0.1.4:
351 | version "0.1.4"
352 | resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
353 | integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
354 |
355 | emoji-regex@^7.0.1:
356 | version "7.0.3"
357 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
358 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
359 |
360 | emoji-regex@^8.0.0:
361 | version "8.0.0"
362 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
363 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==
364 |
365 | end-of-stream@^1.1.0, end-of-stream@^1.4.1:
366 | version "1.4.4"
367 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0"
368 | integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==
369 | dependencies:
370 | once "^1.4.0"
371 |
372 | es6-promise@^4.2.5:
373 | version "4.2.8"
374 | resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
375 | integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==
376 |
377 | escape-goat@^2.0.0:
378 | version "2.1.1"
379 | resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
380 | integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==
381 |
382 | execution-time@^1.4.1:
383 | version "1.4.1"
384 | resolved "https://registry.yarnpkg.com/execution-time/-/execution-time-1.4.1.tgz#d942f835ca9fd608691c4912d55458fc4a495271"
385 | integrity sha512-4t9svrTtsXxAEzAs9/tm1R/Voj5AYHqxd72BiLEbGQWJq2PD3tAmW8bXI7Pp0yorjaKshT1+NyKy0ytHlKW4Pg==
386 | dependencies:
387 | pretty-hrtime "^1.0.3"
388 |
389 | exif-parser@^0.1.12:
390 | version "0.1.12"
391 | resolved "https://registry.yarnpkg.com/exif-parser/-/exif-parser-0.1.12.tgz#58a9d2d72c02c1f6f02a0ef4a9166272b7760922"
392 | integrity sha1-WKnS1ywCwfbwKg70qRZicrd2CSI=
393 |
394 | fill-range@^7.0.1:
395 | version "7.0.1"
396 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
397 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
398 | dependencies:
399 | to-regex-range "^5.0.1"
400 |
401 | foreachasync@^3.0.0:
402 | version "3.0.0"
403 | resolved "https://registry.yarnpkg.com/foreachasync/-/foreachasync-3.0.0.tgz#5502987dc8714be3392097f32e0071c9dee07cf6"
404 | integrity sha1-VQKYfchxS+M5IJfzLgBxyd7gfPY=
405 |
406 | fs-constants@^1.0.0:
407 | version "1.0.0"
408 | resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
409 | integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
410 |
411 | fs.realpath@^1.0.0:
412 | version "1.0.0"
413 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
414 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
415 |
416 | fsevents@~2.1.2:
417 | version "2.1.3"
418 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e"
419 | integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==
420 |
421 | get-stream@^4.1.0:
422 | version "4.1.0"
423 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
424 | integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
425 | dependencies:
426 | pump "^3.0.0"
427 |
428 | get-stream@^5.1.0:
429 | version "5.1.0"
430 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.1.0.tgz#01203cdc92597f9b909067c3e656cc1f4d3c4dc9"
431 | integrity sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==
432 | dependencies:
433 | pump "^3.0.0"
434 |
435 | gl-matrix@3.1.0:
436 | version "3.1.0"
437 | resolved "https://registry.yarnpkg.com/gl-matrix/-/gl-matrix-3.1.0.tgz#f5b2de17d8fed95a79e5025b10cded0ab9ccbed0"
438 | integrity sha512-526NA+3EA+ztAQi0IZpSWiM0fyQXIp7IbRvfJ4wS/TjjQD0uv0fVybXwwqqSOlq33UckivI0yMDlVtboWm3k7A==
439 |
440 | glob-parent@~5.1.0:
441 | version "5.1.1"
442 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229"
443 | integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==
444 | dependencies:
445 | is-glob "^4.0.1"
446 |
447 | glob@^7.1.4, glob@^7.1.6:
448 | version "7.1.6"
449 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6"
450 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==
451 | dependencies:
452 | fs.realpath "^1.0.0"
453 | inflight "^1.0.4"
454 | inherits "2"
455 | minimatch "^3.0.4"
456 | once "^1.3.0"
457 | path-is-absolute "^1.0.0"
458 |
459 | global-dirs@^2.0.1:
460 | version "2.0.1"
461 | resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.0.1.tgz#acdf3bb6685bcd55cb35e8a052266569e9469201"
462 | integrity sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==
463 | dependencies:
464 | ini "^1.3.5"
465 |
466 | got@^9.6.0:
467 | version "9.6.0"
468 | resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
469 | integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==
470 | dependencies:
471 | "@sindresorhus/is" "^0.14.0"
472 | "@szmarczak/http-timer" "^1.1.2"
473 | cacheable-request "^6.0.0"
474 | decompress-response "^3.3.0"
475 | duplexer3 "^0.1.4"
476 | get-stream "^4.1.0"
477 | lowercase-keys "^1.0.1"
478 | mimic-response "^1.0.1"
479 | p-cancelable "^1.0.0"
480 | to-readable-stream "^1.0.0"
481 | url-parse-lax "^3.0.0"
482 |
483 | graceful-fs@^4.1.2, graceful-fs@^4.2.0:
484 | version "4.2.4"
485 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb"
486 | integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==
487 |
488 | hammerjs@2.0.4:
489 | version "2.0.4"
490 | resolved "https://registry.yarnpkg.com/hammerjs/-/hammerjs-2.0.4.tgz#e161706d2e610ef295b16eadc515df7d9c59aa23"
491 | integrity sha1-4WFwbS5hDvKVsW6txRXffZxZqiM=
492 |
493 | has-flag@^3.0.0:
494 | version "3.0.0"
495 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
496 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
497 |
498 | has-flag@^4.0.0:
499 | version "4.0.0"
500 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
501 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
502 |
503 | has-yarn@^2.1.0:
504 | version "2.1.0"
505 | resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77"
506 | integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==
507 |
508 | http-cache-semantics@^4.0.0:
509 | version "4.1.0"
510 | resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
511 | integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
512 |
513 | humanize-duration@^3.23.1:
514 | version "3.23.1"
515 | resolved "https://registry.yarnpkg.com/humanize-duration/-/humanize-duration-3.23.1.tgz#59cb8d01287479c1aa7cd5b1efc260d799bef89b"
516 | integrity sha512-aoOEkomAETmVuQyBx4E7/LfPlC9s8pAA/USl7vFRQpDjepo3aiyvFfOhtXSDqPowdBVPFUZ7onG/KyuolX0qPg==
517 |
518 | ieee754@^1.1.4:
519 | version "1.1.13"
520 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
521 | integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
522 |
523 | ignore-by-default@^1.0.1:
524 | version "1.0.1"
525 | resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
526 | integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk=
527 |
528 | import-lazy@^2.1.0:
529 | version "2.1.0"
530 | resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
531 | integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
532 |
533 | imurmurhash@^0.1.4:
534 | version "0.1.4"
535 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
536 | integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
537 |
538 | inflight@^1.0.4:
539 | version "1.0.6"
540 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
541 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
542 | dependencies:
543 | once "^1.3.0"
544 | wrappy "1"
545 |
546 | inherits@2, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
547 | version "2.0.4"
548 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
549 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
550 |
551 | ini@^1.3.5, ini@~1.3.0:
552 | version "1.3.5"
553 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
554 | integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
555 |
556 | is-binary-path@~2.1.0:
557 | version "2.1.0"
558 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
559 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
560 | dependencies:
561 | binary-extensions "^2.0.0"
562 |
563 | is-ci@^2.0.0:
564 | version "2.0.0"
565 | resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c"
566 | integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==
567 | dependencies:
568 | ci-info "^2.0.0"
569 |
570 | is-extglob@^2.1.1:
571 | version "2.1.1"
572 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
573 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
574 |
575 | is-fullwidth-code-point@^2.0.0:
576 | version "2.0.0"
577 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
578 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
579 |
580 | is-fullwidth-code-point@^3.0.0:
581 | version "3.0.0"
582 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
583 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==
584 |
585 | is-glob@^4.0.1, is-glob@~4.0.1:
586 | version "4.0.1"
587 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
588 | integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
589 | dependencies:
590 | is-extglob "^2.1.1"
591 |
592 | is-installed-globally@^0.3.1:
593 | version "0.3.2"
594 | resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141"
595 | integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==
596 | dependencies:
597 | global-dirs "^2.0.1"
598 | is-path-inside "^3.0.1"
599 |
600 | is-npm@^4.0.0:
601 | version "4.0.0"
602 | resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d"
603 | integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==
604 |
605 | is-number@^7.0.0:
606 | version "7.0.0"
607 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
608 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
609 |
610 | is-obj@^2.0.0:
611 | version "2.0.0"
612 | resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982"
613 | integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==
614 |
615 | is-path-inside@^3.0.1:
616 | version "3.0.2"
617 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017"
618 | integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==
619 |
620 | is-typedarray@^1.0.0:
621 | version "1.0.0"
622 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
623 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
624 |
625 | is-yarn-global@^0.3.0:
626 | version "0.3.0"
627 | resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232"
628 | integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==
629 |
630 | isarray@~1.0.0:
631 | version "1.0.0"
632 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
633 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
634 |
635 | jpeg-js@^0.4.1:
636 | version "0.4.1"
637 | resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.1.tgz#937a3ae911eb6427f151760f8123f04c8bfe6ef7"
638 | integrity sha512-jA55yJiB5tCXEddos8JBbvW+IMrqY0y1tjjx9KNVtA+QPmu7ND5j0zkKopClpUTsaETL135uOM2XfcYG4XRjmw==
639 |
640 | json-buffer@3.0.0:
641 | version "3.0.0"
642 | resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
643 | integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=
644 |
645 | keyv@^3.0.0:
646 | version "3.1.0"
647 | resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
648 | integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==
649 | dependencies:
650 | json-buffer "3.0.0"
651 |
652 | latest-version@^5.0.0:
653 | version "5.1.0"
654 | resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face"
655 | integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==
656 | dependencies:
657 | package-json "^6.3.0"
658 |
659 | lazystream@^1.0.0:
660 | version "1.0.0"
661 | resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4"
662 | integrity sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=
663 | dependencies:
664 | readable-stream "^2.0.5"
665 |
666 | locutus@^2.0.11:
667 | version "2.0.11"
668 | resolved "https://registry.yarnpkg.com/locutus/-/locutus-2.0.11.tgz#83f85109971fd3dd620482a04381916e4a31d4f0"
669 | integrity sha512-C0q1L38lK5q1t+wE0KY21/9szrBHxye6o2z5EJzU+5B79tubNOC+nLAEzTTn1vPUGoUuehKh8kYKqiVUTWRyaQ==
670 | dependencies:
671 | es6-promise "^4.2.5"
672 |
673 | lodash.defaults@^4.2.0:
674 | version "4.2.0"
675 | resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
676 | integrity sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=
677 |
678 | lodash.difference@^4.5.0:
679 | version "4.5.0"
680 | resolved "https://registry.yarnpkg.com/lodash.difference/-/lodash.difference-4.5.0.tgz#9ccb4e505d486b91651345772885a2df27fd017c"
681 | integrity sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw=
682 |
683 | lodash.flatten@^4.4.0:
684 | version "4.4.0"
685 | resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
686 | integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
687 |
688 | lodash.isplainobject@^4.0.6:
689 | version "4.0.6"
690 | resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
691 | integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=
692 |
693 | lodash.union@^4.6.0:
694 | version "4.6.0"
695 | resolved "https://registry.yarnpkg.com/lodash.union/-/lodash.union-4.6.0.tgz#48bb5088409f16f1821666641c44dd1aaae3cd88"
696 | integrity sha1-SLtQiECfFvGCFmZkHETdGqrjzYg=
697 |
698 | lowercase-keys@^1.0.0, lowercase-keys@^1.0.1:
699 | version "1.0.1"
700 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
701 | integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
702 |
703 | lowercase-keys@^2.0.0:
704 | version "2.0.0"
705 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
706 | integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
707 |
708 | make-dir@^3.0.0:
709 | version "3.1.0"
710 | resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f"
711 | integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==
712 | dependencies:
713 | semver "^6.0.0"
714 |
715 | marzipano@^0.9.1:
716 | version "0.9.1"
717 | resolved "https://registry.yarnpkg.com/marzipano/-/marzipano-0.9.1.tgz#38bed4dc71838bfeb8506c247021f288dbfa6817"
718 | integrity sha512-oiMPvESMRHtW34nSOIC3pXREHbnFsD+Jcqim0KX70dBtET6SQ80UY9yl8VhPb7FHQPBn/r4Qit9SER/lpuwrLQ==
719 | dependencies:
720 | bowser "2.7.0"
721 | gl-matrix "3.1.0"
722 | hammerjs "2.0.4"
723 | minimal-event-emitter "1.0.0"
724 |
725 | mimic-response@^1.0.0, mimic-response@^1.0.1:
726 | version "1.0.1"
727 | resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
728 | integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
729 |
730 | minimal-event-emitter@1.0.0:
731 | version "1.0.0"
732 | resolved "https://registry.yarnpkg.com/minimal-event-emitter/-/minimal-event-emitter-1.0.0.tgz#9ce6203aaa1da7d6b62206c78a670212847e605b"
733 | integrity sha512-jZFCw+HUAgVWGSnCpff4NaB1PRwNcnIYRN1hgaA1QfOxG5lBhNmqpmcVW/o2+28Pc8CxPImsipDNrfUQhHCukw==
734 |
735 | minimatch@3.0.x, minimatch@^3.0.4:
736 | version "3.0.4"
737 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
738 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
739 | dependencies:
740 | brace-expansion "^1.1.7"
741 |
742 | minimist@^1.2.0:
743 | version "1.2.5"
744 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
745 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
746 |
747 | ms@2.0.0:
748 | version "2.0.0"
749 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
750 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
751 |
752 | ms@^2.1.1:
753 | version "2.1.2"
754 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
755 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
756 |
757 | nodemon@^2.0.4:
758 | version "2.0.4"
759 | resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.4.tgz#55b09319eb488d6394aa9818148c0c2d1c04c416"
760 | integrity sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ==
761 | dependencies:
762 | chokidar "^3.2.2"
763 | debug "^3.2.6"
764 | ignore-by-default "^1.0.1"
765 | minimatch "^3.0.4"
766 | pstree.remy "^1.1.7"
767 | semver "^5.7.1"
768 | supports-color "^5.5.0"
769 | touch "^3.1.0"
770 | undefsafe "^2.0.2"
771 | update-notifier "^4.0.0"
772 |
773 | nopt@~1.0.10:
774 | version "1.0.10"
775 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
776 | integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=
777 | dependencies:
778 | abbrev "1"
779 |
780 | normalize-path@^3.0.0, normalize-path@~3.0.0:
781 | version "3.0.0"
782 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
783 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
784 |
785 | normalize-url@^4.1.0:
786 | version "4.5.0"
787 | resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129"
788 | integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==
789 |
790 | once@^1.3.0, once@^1.3.1, once@^1.4.0:
791 | version "1.4.0"
792 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
793 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
794 | dependencies:
795 | wrappy "1"
796 |
797 | p-cancelable@^1.0.0:
798 | version "1.1.0"
799 | resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"
800 | integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==
801 |
802 | package-json@^6.3.0:
803 | version "6.5.0"
804 | resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0"
805 | integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==
806 | dependencies:
807 | got "^9.6.0"
808 | registry-auth-token "^4.0.0"
809 | registry-url "^5.0.0"
810 | semver "^6.2.0"
811 |
812 | path-is-absolute@^1.0.0:
813 | version "1.0.1"
814 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
815 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
816 |
817 | picomatch@^2.0.4, picomatch@^2.2.1:
818 | version "2.2.2"
819 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
820 | integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
821 |
822 | pngjs@^5.0.0:
823 | version "5.0.0"
824 | resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb"
825 | integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==
826 |
827 | prepend-http@^2.0.0:
828 | version "2.0.0"
829 | resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
830 | integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
831 |
832 | pretty-bytes@^5.3.0:
833 | version "5.3.0"
834 | resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.3.0.tgz#f2849e27db79fb4d6cfe24764fc4134f165989f2"
835 | integrity sha512-hjGrh+P926p4R4WbaB6OckyRtO0F0/lQBiT+0gnxjV+5kjPBrfVBFCsCLbMqVQeydvIoouYTCmmEURiH3R1Bdg==
836 |
837 | pretty-hrtime@^1.0.3:
838 | version "1.0.3"
839 | resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1"
840 | integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=
841 |
842 | process-nextick-args@~2.0.0:
843 | version "2.0.1"
844 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
845 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
846 |
847 | pstree.remy@^1.1.7:
848 | version "1.1.8"
849 | resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
850 | integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==
851 |
852 | pump@^3.0.0:
853 | version "3.0.0"
854 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
855 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
856 | dependencies:
857 | end-of-stream "^1.1.0"
858 | once "^1.3.1"
859 |
860 | pupa@^2.0.1:
861 | version "2.0.1"
862 | resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.0.1.tgz#dbdc9ff48ffbea4a26a069b6f9f7abb051008726"
863 | integrity sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==
864 | dependencies:
865 | escape-goat "^2.0.0"
866 |
867 | rc@^1.2.8:
868 | version "1.2.8"
869 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
870 | integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
871 | dependencies:
872 | deep-extend "^0.6.0"
873 | ini "~1.3.0"
874 | minimist "^1.2.0"
875 | strip-json-comments "~2.0.1"
876 |
877 | readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.3.7:
878 | version "2.3.7"
879 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
880 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
881 | dependencies:
882 | core-util-is "~1.0.0"
883 | inherits "~2.0.3"
884 | isarray "~1.0.0"
885 | process-nextick-args "~2.0.0"
886 | safe-buffer "~5.1.1"
887 | string_decoder "~1.1.1"
888 | util-deprecate "~1.0.1"
889 |
890 | readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
891 | version "3.6.0"
892 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
893 | integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
894 | dependencies:
895 | inherits "^2.0.3"
896 | string_decoder "^1.1.1"
897 | util-deprecate "^1.0.1"
898 |
899 | readdirp@~3.4.0:
900 | version "3.4.0"
901 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.4.0.tgz#9fdccdf9e9155805449221ac645e8303ab5b9ada"
902 | integrity sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==
903 | dependencies:
904 | picomatch "^2.2.1"
905 |
906 | regenerator-runtime@^0.13.4:
907 | version "0.13.7"
908 | resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz#cac2dacc8a1ea675feaabaeb8ae833898ae46f55"
909 | integrity sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==
910 |
911 | registry-auth-token@^4.0.0:
912 | version "4.1.1"
913 | resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.1.1.tgz#40a33be1e82539460f94328b0f7f0f84c16d9479"
914 | integrity sha512-9bKS7nTl9+/A1s7tnPeGrUpRcVY+LUh7bfFgzpndALdPfXQBfQV77rQVtqgUV3ti4vc/Ik81Ex8UJDWDQ12zQA==
915 | dependencies:
916 | rc "^1.2.8"
917 |
918 | registry-url@^5.0.0:
919 | version "5.1.0"
920 | resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009"
921 | integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==
922 | dependencies:
923 | rc "^1.2.8"
924 |
925 | responselike@^1.0.2:
926 | version "1.0.2"
927 | resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7"
928 | integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=
929 | dependencies:
930 | lowercase-keys "^1.0.0"
931 |
932 | safe-buffer@~5.1.0, safe-buffer@~5.1.1:
933 | version "5.1.2"
934 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
935 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
936 |
937 | safe-buffer@~5.2.0:
938 | version "5.2.1"
939 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
940 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
941 |
942 | sax@>=0.6.0:
943 | version "1.2.4"
944 | resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
945 | integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
946 |
947 | semver-diff@^3.1.1:
948 | version "3.1.1"
949 | resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b"
950 | integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==
951 | dependencies:
952 | semver "^6.3.0"
953 |
954 | semver@^5.7.1:
955 | version "5.7.1"
956 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
957 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
958 |
959 | semver@^6.0.0, semver@^6.2.0, semver@^6.3.0:
960 | version "6.3.0"
961 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
962 | integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
963 |
964 | signal-exit@^3.0.2:
965 | version "3.0.3"
966 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
967 | integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
968 |
969 | string-width@^3.0.0:
970 | version "3.1.0"
971 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
972 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
973 | dependencies:
974 | emoji-regex "^7.0.1"
975 | is-fullwidth-code-point "^2.0.0"
976 | strip-ansi "^5.1.0"
977 |
978 | string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0:
979 | version "4.2.0"
980 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5"
981 | integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==
982 | dependencies:
983 | emoji-regex "^8.0.0"
984 | is-fullwidth-code-point "^3.0.0"
985 | strip-ansi "^6.0.0"
986 |
987 | string_decoder@^1.1.1:
988 | version "1.3.0"
989 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e"
990 | integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
991 | dependencies:
992 | safe-buffer "~5.2.0"
993 |
994 | string_decoder@~1.1.1:
995 | version "1.1.1"
996 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
997 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
998 | dependencies:
999 | safe-buffer "~5.1.0"
1000 |
1001 | strip-ansi@^5.1.0:
1002 | version "5.2.0"
1003 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
1004 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
1005 | dependencies:
1006 | ansi-regex "^4.1.0"
1007 |
1008 | strip-ansi@^6.0.0:
1009 | version "6.0.0"
1010 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532"
1011 | integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==
1012 | dependencies:
1013 | ansi-regex "^5.0.0"
1014 |
1015 | strip-json-comments@~2.0.1:
1016 | version "2.0.1"
1017 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
1018 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
1019 |
1020 | supports-color@^5.5.0:
1021 | version "5.5.0"
1022 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
1023 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
1024 | dependencies:
1025 | has-flag "^3.0.0"
1026 |
1027 | supports-color@^7.1.0:
1028 | version "7.1.0"
1029 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1"
1030 | integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==
1031 | dependencies:
1032 | has-flag "^4.0.0"
1033 |
1034 | tar-stream@^2.1.2:
1035 | version "2.1.3"
1036 | resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.3.tgz#1e2022559221b7866161660f118255e20fa79e41"
1037 | integrity sha512-Z9yri56Dih8IaK8gncVPx4Wqt86NDmQTSh49XLZgjWpGZL9GK9HKParS2scqHCC4w6X9Gh2jwaU45V47XTKwVA==
1038 | dependencies:
1039 | bl "^4.0.1"
1040 | end-of-stream "^1.4.1"
1041 | fs-constants "^1.0.0"
1042 | inherits "^2.0.3"
1043 | readable-stream "^3.1.1"
1044 |
1045 | term-size@^2.1.0:
1046 | version "2.2.0"
1047 | resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753"
1048 | integrity sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==
1049 |
1050 | to-readable-stream@^1.0.0:
1051 | version "1.0.0"
1052 | resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771"
1053 | integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==
1054 |
1055 | to-regex-range@^5.0.1:
1056 | version "5.0.1"
1057 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
1058 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
1059 | dependencies:
1060 | is-number "^7.0.0"
1061 |
1062 | touch@^3.1.0:
1063 | version "3.1.0"
1064 | resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"
1065 | integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==
1066 | dependencies:
1067 | nopt "~1.0.10"
1068 |
1069 | twig@^1.15.1:
1070 | version "1.15.1"
1071 | resolved "https://registry.yarnpkg.com/twig/-/twig-1.15.1.tgz#68448ee2d8124adaca92d8d6a145f499f570039a"
1072 | integrity sha512-SPGkUM0p7hjgo+y5Dlm/XCSuZe0G3kfcgRPrxkMFln5e8bvQbxDOsia8QEo8xqXfjLR1Emp9FGkVYHya2b8qdA==
1073 | dependencies:
1074 | "@babel/runtime" "^7.8.4"
1075 | locutus "^2.0.11"
1076 | minimatch "3.0.x"
1077 | walk "2.3.x"
1078 |
1079 | type-fest@^0.8.1:
1080 | version "0.8.1"
1081 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
1082 | integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
1083 |
1084 | typedarray-to-buffer@^3.1.5:
1085 | version "3.1.5"
1086 | resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080"
1087 | integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==
1088 | dependencies:
1089 | is-typedarray "^1.0.0"
1090 |
1091 | undefsafe@^2.0.2:
1092 | version "2.0.3"
1093 | resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae"
1094 | integrity sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==
1095 | dependencies:
1096 | debug "^2.2.0"
1097 |
1098 | unique-string@^2.0.0:
1099 | version "2.0.0"
1100 | resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d"
1101 | integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==
1102 | dependencies:
1103 | crypto-random-string "^2.0.0"
1104 |
1105 | update-notifier@^4.0.0:
1106 | version "4.1.0"
1107 | resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.0.tgz#4866b98c3bc5b5473c020b1250583628f9a328f3"
1108 | integrity sha512-w3doE1qtI0/ZmgeoDoARmI5fjDoT93IfKgEGqm26dGUOh8oNpaSTsGNdYRN/SjOuo10jcJGwkEL3mroKzktkew==
1109 | dependencies:
1110 | boxen "^4.2.0"
1111 | chalk "^3.0.0"
1112 | configstore "^5.0.1"
1113 | has-yarn "^2.1.0"
1114 | import-lazy "^2.1.0"
1115 | is-ci "^2.0.0"
1116 | is-installed-globally "^0.3.1"
1117 | is-npm "^4.0.0"
1118 | is-yarn-global "^0.3.0"
1119 | latest-version "^5.0.0"
1120 | pupa "^2.0.1"
1121 | semver-diff "^3.1.1"
1122 | xdg-basedir "^4.0.0"
1123 |
1124 | url-parse-lax@^3.0.0:
1125 | version "3.0.0"
1126 | resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c"
1127 | integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=
1128 | dependencies:
1129 | prepend-http "^2.0.0"
1130 |
1131 | util-deprecate@^1.0.1, util-deprecate@~1.0.1:
1132 | version "1.0.2"
1133 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
1134 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
1135 |
1136 | walk@2.3.x:
1137 | version "2.3.14"
1138 | resolved "https://registry.yarnpkg.com/walk/-/walk-2.3.14.tgz#60ec8631cfd23276ae1e7363ce11d626452e1ef3"
1139 | integrity sha512-5skcWAUmySj6hkBdH6B6+3ddMjVQYH5Qy9QGbPmN8kVmLteXk+yVXg+yfk1nbX30EYakahLrr8iPcCxJQSCBeg==
1140 | dependencies:
1141 | foreachasync "^3.0.0"
1142 |
1143 | widest-line@^3.1.0:
1144 | version "3.1.0"
1145 | resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca"
1146 | integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==
1147 | dependencies:
1148 | string-width "^4.0.0"
1149 |
1150 | wrappy@1:
1151 | version "1.0.2"
1152 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
1153 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
1154 |
1155 | write-file-atomic@^3.0.0:
1156 | version "3.0.3"
1157 | resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8"
1158 | integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==
1159 | dependencies:
1160 | imurmurhash "^0.1.4"
1161 | is-typedarray "^1.0.0"
1162 | signal-exit "^3.0.2"
1163 | typedarray-to-buffer "^3.1.5"
1164 |
1165 | xdg-basedir@^4.0.0:
1166 | version "4.0.0"
1167 | resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
1168 | integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
1169 |
1170 | xml2js@^0.4.23:
1171 | version "0.4.23"
1172 | resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66"
1173 | integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==
1174 | dependencies:
1175 | sax ">=0.6.0"
1176 | xmlbuilder "~11.0.0"
1177 |
1178 | xmlbuilder@~11.0.0:
1179 | version "11.0.1"
1180 | resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3"
1181 | integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==
1182 |
1183 | zip-stream@^3.0.1:
1184 | version "3.0.1"
1185 | resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-3.0.1.tgz#cb8db9d324a76c09f9b76b31a12a48638b0b9708"
1186 | integrity sha512-r+JdDipt93ttDjsOVPU5zaq5bAyY+3H19bDrThkvuVxC0xMQzU1PJcS6D+KrP3u96gH9XLomcHPb+2skoDjulQ==
1187 | dependencies:
1188 | archiver-utils "^2.1.0"
1189 | compress-commons "^3.0.0"
1190 | readable-stream "^3.6.0"
1191 |
--------------------------------------------------------------------------------