@appium/support 2.55.2 → 2.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/lib/env.js +102 -0
- package/build/lib/fs.js +74 -56
- package/build/lib/image-util.js +4 -332
- package/build/lib/index.js +18 -6
- package/build/lib/log-internal.js +2 -4
- package/build/lib/logger.js +2 -4
- package/build/lib/logging.js +2 -4
- package/build/lib/mjpeg.js +2 -4
- package/build/lib/mkdirp.js +7 -11
- package/build/lib/net.js +2 -4
- package/build/lib/node.js +99 -2
- package/build/lib/npm.js +240 -0
- package/build/lib/plist.js +2 -4
- package/build/lib/process.js +2 -4
- package/build/lib/system.js +2 -4
- package/build/lib/tempdir.js +2 -4
- package/build/lib/timing.js +2 -4
- package/build/lib/util.js +6 -8
- package/build/lib/zip.js +4 -8
- package/lib/env.js +162 -0
- package/lib/fs.js +193 -69
- package/lib/image-util.js +3 -570
- package/lib/index.js +8 -2
- package/lib/log-internal.js +2 -2
- package/lib/logging.js +1 -1
- package/lib/mkdirp.js +3 -6
- package/lib/net.js +4 -4
- package/lib/node.js +104 -1
- package/lib/npm.js +335 -0
- package/lib/tempdir.js +6 -6
- package/lib/util.js +28 -24
- package/lib/zip.js +7 -8
- package/package.json +20 -9
- package/build/test/assets/sample_binary.plist +0 -0
- package/build/test/assets/sample_text.plist +0 -28
- package/build/test/fs-specs.js +0 -264
- package/build/test/helpers.js +0 -35
- package/build/test/image-util-e2e-specs.js +0 -227
- package/build/test/index-specs.js +0 -49
- package/build/test/log-internals-specs.js +0 -97
- package/build/test/logger/helpers.js +0 -71
- package/build/test/logger/logger-force-specs.js +0 -41
- package/build/test/logger/logger-normal-specs.js +0 -113
- package/build/test/logger/logger-test-specs.js +0 -40
- package/build/test/mjpeg-e2e-specs.js +0 -96
- package/build/test/net-e2e-specs.js +0 -32
- package/build/test/node-e2e-specs.js +0 -22
- package/build/test/plist-specs.js +0 -54
- package/build/test/process-specs.js +0 -104
- package/build/test/system-specs.js +0 -136
- package/build/test/tempdir-specs.js +0 -86
- package/build/test/timing-specs.js +0 -125
- package/build/test/util-e2e-specs.js +0 -136
- package/build/test/util-specs.js +0 -537
- package/build/test/zip-e2e-specs.js +0 -233
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
-
|
|
5
|
-
require("source-map-support/register");
|
|
6
|
-
|
|
7
|
-
var _path = _interopRequireDefault(require("path"));
|
|
8
|
-
|
|
9
|
-
var zip = _interopRequireWildcard(require("../lib/zip"));
|
|
10
|
-
|
|
11
|
-
var _index = require("../lib/index");
|
|
12
|
-
|
|
13
|
-
var _helpers = require("./helpers");
|
|
14
|
-
|
|
15
|
-
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
16
|
-
|
|
17
|
-
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
18
|
-
|
|
19
|
-
describe('#zip', function () {
|
|
20
|
-
const optionMap = new Map([['native JS unzip', {}], ['system unzip', {
|
|
21
|
-
useSystemUnzip: true
|
|
22
|
-
}]]);
|
|
23
|
-
optionMap.forEach((options, desc) => {
|
|
24
|
-
describe(desc, function () {
|
|
25
|
-
let assetsPath;
|
|
26
|
-
let zippedFilePath;
|
|
27
|
-
let tmpRoot;
|
|
28
|
-
beforeEach(async function () {
|
|
29
|
-
assetsPath = await _index.tempDir.openDir();
|
|
30
|
-
tmpRoot = await _index.tempDir.openDir();
|
|
31
|
-
const zippedBase64 = 'UEsDBAoAAAAAALlzk0oAAAAAAAAAAAAAAAAJABAAdW56aXBwZWQvVVgMANBO+VjO1vdY9QEUAFBLAwQKAAAAAADAc5NKAAAAAAAAAAAAAAAAEgAQAHVuemlwcGVkL3Rlc3QtZGlyL1VYDADQTvlY19b3WPUBFABQSwMEFAAIAAgAwnOTSgAAAAAAAAAAAAAAABcAEAB1bnppcHBlZC90ZXN0LWRpci9hLnR4dFVYDACDTvlY3Nb3WPUBFADzSM3JyVcIzy/KSQEAUEsHCFaxF0oNAAAACwAAAFBLAwQUAAgACADEc5NKAAAAAAAAAAAAAAAAFwAQAHVuemlwcGVkL3Rlc3QtZGlyL2IudHh0VVgMAINO+Vjf1vdY9QEUAHPLz1dwSiwCAFBLBwhIfrZJCQAAAAcAAABQSwECFQMKAAAAAAC5c5NKAAAAAAAAAAAAAAAACQAMAAAAAAAAAABA7UEAAAAAdW56aXBwZWQvVVgIANBO+VjO1vdYUEsBAhUDCgAAAAAAwHOTSgAAAAAAAAAAAAAAABIADAAAAAAAAAAAQO1BNwAAAHVuemlwcGVkL3Rlc3QtZGlyL1VYCADQTvlY19b3WFBLAQIVAxQACAAIAMJzk0pWsRdKDQAAAAsAAAAXAAwAAAAAAAAAAECkgXcAAAB1bnppcHBlZC90ZXN0LWRpci9hLnR4dFVYCACDTvlY3Nb3WFBLAQIVAxQACAAIAMRzk0pIfrZJCQAAAAcAAAAXAAwAAAAAAAAAAECkgdkAAAB1bnppcHBlZC90ZXN0LWRpci9iLnR4dFVYCACDTvlY39b3WFBLBQYAAAAABAAEADEBAAA3AQAAAAA=';
|
|
32
|
-
zippedFilePath = _path.default.resolve(tmpRoot, 'zipped.zip');
|
|
33
|
-
await _index.fs.writeFile(zippedFilePath, zippedBase64, 'base64');
|
|
34
|
-
await zip.extractAllTo(zippedFilePath, assetsPath, options);
|
|
35
|
-
});
|
|
36
|
-
afterEach(async function () {
|
|
37
|
-
for (const tmpPath of [assetsPath, tmpRoot]) {
|
|
38
|
-
if (!(await _index.fs.exists(tmpPath))) {
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
await _index.fs.rimraf(tmpPath);
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
describe('extractAllTo()', function () {
|
|
46
|
-
it('should extract contents of a .zip file to a directory', async function () {
|
|
47
|
-
await _index.fs.readFile(_path.default.resolve(assetsPath, 'unzipped', 'test-dir', 'a.txt'), {
|
|
48
|
-
encoding: 'utf8'
|
|
49
|
-
}).should.eventually.equal('Hello World');
|
|
50
|
-
await _index.fs.readFile(_path.default.resolve(assetsPath, 'unzipped', 'test-dir', 'b.txt'), {
|
|
51
|
-
encoding: 'utf8'
|
|
52
|
-
}).should.eventually.equal('Foo Bar');
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
describe('assertValidZip', function () {
|
|
56
|
-
it('should not throw an error if a valid ZIP file is passed', async function () {
|
|
57
|
-
await zip.assertValidZip(zippedFilePath).should.eventually.be.fulfilled;
|
|
58
|
-
});
|
|
59
|
-
it('should throw an error if the file does not exist', async function () {
|
|
60
|
-
await zip.assertValidZip('blabla').should.eventually.be.rejected;
|
|
61
|
-
});
|
|
62
|
-
it('should throw an error if the file is invalid', async function () {
|
|
63
|
-
await zip.assertValidZip(_path.default.resolve(assetsPath, 'unzipped', 'test-dir', 'a.txt')).should.eventually.be.rejected;
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
describe('readEntries()', function () {
|
|
67
|
-
const expectedEntries = [{
|
|
68
|
-
name: 'unzipped/'
|
|
69
|
-
}, {
|
|
70
|
-
name: 'unzipped/test-dir/'
|
|
71
|
-
}, {
|
|
72
|
-
name: 'unzipped/test-dir/a.txt',
|
|
73
|
-
contents: 'Hello World'
|
|
74
|
-
}, {
|
|
75
|
-
name: 'unzipped/test-dir/b.txt',
|
|
76
|
-
contents: 'Foo Bar'
|
|
77
|
-
}];
|
|
78
|
-
it('should iterate entries (directories and files) of zip file', async function () {
|
|
79
|
-
let i = 0;
|
|
80
|
-
await zip.readEntries(zippedFilePath, async ({
|
|
81
|
-
entry,
|
|
82
|
-
extractEntryTo
|
|
83
|
-
}) => {
|
|
84
|
-
entry.fileName.should.equal(expectedEntries[i].name);
|
|
85
|
-
|
|
86
|
-
if (expectedEntries[i].contents) {
|
|
87
|
-
await extractEntryTo(tmpRoot);
|
|
88
|
-
await _index.fs.readFile(_path.default.resolve(tmpRoot, entry.fileName), {
|
|
89
|
-
flags: 'r',
|
|
90
|
-
encoding: 'utf8'
|
|
91
|
-
}).should.eventually.equal(expectedEntries[i].contents);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
i++;
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
it('should stop iterating zipFile if onEntry callback returns false', async function () {
|
|
98
|
-
let i = 0;
|
|
99
|
-
await zip.readEntries(zippedFilePath, async () => {
|
|
100
|
-
i++;
|
|
101
|
-
return false;
|
|
102
|
-
});
|
|
103
|
-
i.should.equal(1);
|
|
104
|
-
});
|
|
105
|
-
it('should be rejected if it uses a non-zip file', async function () {
|
|
106
|
-
let promise = zip.readEntries(_path.default.resolve(assetsPath, 'unzipped', 'test-dir', 'a.txt'), async () => {});
|
|
107
|
-
await promise.should.eventually.be.rejected;
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
describe('toInMemoryZip()', function () {
|
|
111
|
-
it('should convert a local file to an in-memory zip buffer', async function () {
|
|
112
|
-
const testFolder = _path.default.resolve(assetsPath, 'unzipped');
|
|
113
|
-
|
|
114
|
-
const buffer = await zip.toInMemoryZip(testFolder);
|
|
115
|
-
Buffer.isBuffer(buffer).should.be.true;
|
|
116
|
-
await _index.fs.writeFile(_path.default.resolve(tmpRoot, 'test.zip'), buffer);
|
|
117
|
-
await zip.extractAllTo(_path.default.resolve(tmpRoot, 'test.zip'), _path.default.resolve(tmpRoot, 'output'), {
|
|
118
|
-
fileNamesEncoding: 'utf8'
|
|
119
|
-
});
|
|
120
|
-
await _index.fs.readFile(_path.default.resolve(tmpRoot, 'output', 'test-dir', 'a.txt'), {
|
|
121
|
-
encoding: 'utf8'
|
|
122
|
-
}).should.eventually.equal('Hello World');
|
|
123
|
-
await _index.fs.readFile(_path.default.resolve(tmpRoot, 'output', 'test-dir', 'b.txt'), {
|
|
124
|
-
encoding: 'utf8'
|
|
125
|
-
}).should.eventually.equal('Foo Bar');
|
|
126
|
-
});
|
|
127
|
-
it('should convert a local folder to an in-memory base64-encoded zip buffer', async function () {
|
|
128
|
-
const testFolder = _path.default.resolve(assetsPath, 'unzipped');
|
|
129
|
-
|
|
130
|
-
const buffer = await zip.toInMemoryZip(testFolder, {
|
|
131
|
-
encodeToBase64: true
|
|
132
|
-
});
|
|
133
|
-
await _index.fs.writeFile(_path.default.resolve(tmpRoot, 'test.zip'), Buffer.from(buffer.toString(), 'base64'));
|
|
134
|
-
await zip.extractAllTo(_path.default.resolve(tmpRoot, 'test.zip'), _path.default.resolve(tmpRoot, 'output'));
|
|
135
|
-
await _index.fs.readFile(_path.default.resolve(tmpRoot, 'output', 'test-dir', 'a.txt'), {
|
|
136
|
-
encoding: 'utf8'
|
|
137
|
-
}).should.eventually.equal('Hello World');
|
|
138
|
-
await _index.fs.readFile(_path.default.resolve(tmpRoot, 'output', 'test-dir', 'b.txt'), {
|
|
139
|
-
encoding: 'utf8'
|
|
140
|
-
}).should.eventually.equal('Foo Bar');
|
|
141
|
-
});
|
|
142
|
-
it('should be rejected if use a bad path', async function () {
|
|
143
|
-
await zip.toInMemoryZip(_path.default.resolve(assetsPath, 'bad_path')).should.be.rejectedWith(/no such/i);
|
|
144
|
-
});
|
|
145
|
-
it('should be rejected if max size is exceeded', async function () {
|
|
146
|
-
const testFolder = _path.default.resolve(assetsPath, 'unzipped');
|
|
147
|
-
|
|
148
|
-
await zip.toInMemoryZip(testFolder, {
|
|
149
|
-
maxSize: 1
|
|
150
|
-
}).should.be.rejectedWith(/must not be greater/);
|
|
151
|
-
});
|
|
152
|
-
});
|
|
153
|
-
describe('_extractEntryTo()', function () {
|
|
154
|
-
let entry, mockZipFile, mockZipStream;
|
|
155
|
-
beforeEach(async function () {
|
|
156
|
-
entry = {
|
|
157
|
-
fileName: _path.default.resolve(await _index.tempDir.openDir(), 'temp', 'file')
|
|
158
|
-
};
|
|
159
|
-
mockZipStream = new _helpers.MockReadWriteStream();
|
|
160
|
-
mockZipFile = {
|
|
161
|
-
openReadStream: (entry, cb) => cb(null, mockZipStream)
|
|
162
|
-
};
|
|
163
|
-
});
|
|
164
|
-
it('should be rejected if zip stream emits an error', async function () {
|
|
165
|
-
mockZipStream.pipe = () => {
|
|
166
|
-
mockZipStream.emit('error', new Error('zip stream error'));
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
await zip._extractEntryTo(mockZipFile, entry).should.be.rejectedWith('zip stream error');
|
|
170
|
-
});
|
|
171
|
-
it('should be rejected if write stream emits an error', async function () {
|
|
172
|
-
mockZipStream.pipe = writeStream => {
|
|
173
|
-
writeStream.emit('error', new Error('write stream error'));
|
|
174
|
-
mockZipStream.end();
|
|
175
|
-
writeStream.end();
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
await zip._extractEntryTo(mockZipFile, entry).should.be.rejectedWith('write stream error');
|
|
179
|
-
});
|
|
180
|
-
});
|
|
181
|
-
describe('toArchive', function () {
|
|
182
|
-
it('should zip all files into an archive', async function () {
|
|
183
|
-
const testFolder = _path.default.resolve(assetsPath, 'unzipped');
|
|
184
|
-
|
|
185
|
-
const dstPath = _path.default.resolve(tmpRoot, 'test.zip');
|
|
186
|
-
|
|
187
|
-
await zip.toArchive(dstPath, {
|
|
188
|
-
cwd: testFolder
|
|
189
|
-
});
|
|
190
|
-
await zip.extractAllTo(dstPath, _path.default.resolve(tmpRoot, 'output'));
|
|
191
|
-
await _index.fs.readFile(_path.default.resolve(tmpRoot, 'output', 'test-dir', 'a.txt'), {
|
|
192
|
-
encoding: 'utf8'
|
|
193
|
-
}).should.eventually.equal('Hello World');
|
|
194
|
-
await _index.fs.readFile(_path.default.resolve(tmpRoot, 'output', 'test-dir', 'b.txt'), {
|
|
195
|
-
encoding: 'utf8'
|
|
196
|
-
}).should.eventually.equal('Foo Bar');
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
});
|
|
200
|
-
});
|
|
201
|
-
describe('unicode filename handling', function () {
|
|
202
|
-
let zippedFilePath, assetsPath, tmpRoot;
|
|
203
|
-
beforeEach(async function () {
|
|
204
|
-
assetsPath = await _index.tempDir.openDir();
|
|
205
|
-
tmpRoot = await _index.tempDir.openDir();
|
|
206
|
-
const zippedBase64 = 'UEsDBBQACAAIABF8/EYAAAAAAAAAABoAAAATACAAa2Fuamkt5q2j5LiW5LiVLmFwcFVUDQAHAgO4VVpX+GBZV/hgdXgLAAEE9QEAAAQUAAAAK8nILFYAorz8EoWi1MScnEqFxDyFxIICLgBQSwcIR93jPhoAAAAaAAAAUEsBAhQDFAAIAAgAEXz8Rkfd4z4aAAAAGgAAABMAIAAAAAAAAAAAAKSBAAAAAGthbmppLeato+S4luS4lS5hcHBVVA0ABwIDuFVaV/hgWVf4YHV4CwABBPUBAAAEFAAAAFBLBQYAAAAAAQABAGEAAAB7AAAAAAA=';
|
|
207
|
-
zippedFilePath = _path.default.resolve(tmpRoot, 'zipped.zip');
|
|
208
|
-
await _index.fs.writeFile(zippedFilePath, zippedBase64, 'base64');
|
|
209
|
-
await zip.extractAllTo(zippedFilePath, assetsPath, {
|
|
210
|
-
useSystemUnzip: true
|
|
211
|
-
});
|
|
212
|
-
});
|
|
213
|
-
afterEach(async function () {
|
|
214
|
-
for (const tmpPath of [assetsPath, tmpRoot]) {
|
|
215
|
-
if (!(await _index.fs.exists(tmpPath))) {
|
|
216
|
-
continue;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
await _index.fs.rimraf(tmpPath);
|
|
220
|
-
}
|
|
221
|
-
});
|
|
222
|
-
it('should retain the proper filenames', async function () {
|
|
223
|
-
const expectedPath = _path.default.join(assetsPath, 'kanji-正世丕.app');
|
|
224
|
-
|
|
225
|
-
if (!(await _index.fs.exists(expectedPath))) {
|
|
226
|
-
throw new chai.AssertionError(`Expected ${expectedPath} to exist, but it does not`);
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
});
|
|
230
|
-
});require('source-map-support').install();
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvemlwLWUyZS1zcGVjcy5qcyJdLCJuYW1lcyI6WyJkZXNjcmliZSIsIm9wdGlvbk1hcCIsIk1hcCIsInVzZVN5c3RlbVVuemlwIiwiZm9yRWFjaCIsIm9wdGlvbnMiLCJkZXNjIiwiYXNzZXRzUGF0aCIsInppcHBlZEZpbGVQYXRoIiwidG1wUm9vdCIsImJlZm9yZUVhY2giLCJ0ZW1wRGlyIiwib3BlbkRpciIsInppcHBlZEJhc2U2NCIsInBhdGgiLCJyZXNvbHZlIiwiZnMiLCJ3cml0ZUZpbGUiLCJ6aXAiLCJleHRyYWN0QWxsVG8iLCJhZnRlckVhY2giLCJ0bXBQYXRoIiwiZXhpc3RzIiwicmltcmFmIiwiaXQiLCJyZWFkRmlsZSIsImVuY29kaW5nIiwic2hvdWxkIiwiZXZlbnR1YWxseSIsImVxdWFsIiwiYXNzZXJ0VmFsaWRaaXAiLCJiZSIsImZ1bGZpbGxlZCIsInJlamVjdGVkIiwiZXhwZWN0ZWRFbnRyaWVzIiwibmFtZSIsImNvbnRlbnRzIiwiaSIsInJlYWRFbnRyaWVzIiwiZW50cnkiLCJleHRyYWN0RW50cnlUbyIsImZpbGVOYW1lIiwiZmxhZ3MiLCJwcm9taXNlIiwidGVzdEZvbGRlciIsImJ1ZmZlciIsInRvSW5NZW1vcnlaaXAiLCJCdWZmZXIiLCJpc0J1ZmZlciIsInRydWUiLCJmaWxlTmFtZXNFbmNvZGluZyIsImVuY29kZVRvQmFzZTY0IiwiZnJvbSIsInRvU3RyaW5nIiwicmVqZWN0ZWRXaXRoIiwibWF4U2l6ZSIsIm1vY2taaXBGaWxlIiwibW9ja1ppcFN0cmVhbSIsIk1vY2tSZWFkV3JpdGVTdHJlYW0iLCJvcGVuUmVhZFN0cmVhbSIsImNiIiwicGlwZSIsImVtaXQiLCJFcnJvciIsIl9leHRyYWN0RW50cnlUbyIsIndyaXRlU3RyZWFtIiwiZW5kIiwiZHN0UGF0aCIsInRvQXJjaGl2ZSIsImN3ZCIsImV4cGVjdGVkUGF0aCIsImpvaW4iLCJjaGFpIiwiQXNzZXJ0aW9uRXJyb3IiXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFB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QUFTLENBQUMsa0JBQWtCO0FBQzFCLFdBQUssTUFBTUMsT0FBWCxJQUFzQixDQUFDZCxVQUFELEVBQWFFLE9BQWIsQ0FBdEIsRUFBNkM7QUFDM0MsWUFBSSxFQUFDLE1BQU1PLFVBQUdNLE1BQUgsQ0FBVUQsT0FBVixDQUFQLENBQUosRUFBK0I7QUFDN0I7QUFDRDs7QUFDRCxjQUFNTCxVQUFHTyxNQUFILENBQVVGLE9BQVYsQ0FBTjtBQUNEO0FBQ0YsS0FQUSxDQUFUO0FBU0FHLElBQUFBLEVBQUUsQ0FBQyxvQ0FBRCxFQUF1QyxrQkFBa0I7QUFDekQsWUFBTThDLFlBQVksR0FBR3hELGNBQUt5RCxJQUFMLENBQVVoRSxVQUFWLEVBQXNCLGVBQXRCLENBQXJCOztBQUVBLFVBQUksRUFBQyxNQUFNUyxVQUFHTSxNQUFILENBQVVnRCxZQUFWLENBQVAsQ0FBSixFQUFvQztBQUNsQyxjQUFNLElBQUlFLElBQUksQ0FBQ0MsY0FBVCxDQUF5QixZQUFXSCxZQUFhLDRCQUFqRCxDQUFOO0FBQ0Q7QUFDRixLQU5DLENBQUY7QUFPRCxHQTdCTyxDQUFSO0FBOEJELENBNU5PLENBQVIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCAqIGFzIHppcCBmcm9tICcuLi9saWIvemlwJztcbmltcG9ydCB7IHRlbXBEaXIsIGZzIH0gZnJvbSAnLi4vbGliL2luZGV4JztcbmltcG9ydCB7IE1vY2tSZWFkV3JpdGVTdHJlYW0gfSBmcm9tICcuL2hlbHBlcnMnO1xuXG5cbmRlc2NyaWJlKCcjemlwJywgZnVuY3Rpb24gKCkge1xuXG4gIGNvbnN0IG9wdGlvbk1hcCA9IG5ldyBNYXAoW1snbmF0aXZlIEpTIHVuemlwJywge31dLCBbJ3N5c3RlbSB1bnppcCcsIHt1c2VTeXN0ZW1VbnppcDogdHJ1ZX1dXSk7XG5cbiAgb3B0aW9uTWFwLmZvckVhY2goKG9wdGlvbnMsIGRlc2MpID0+IHtcbiAgICBkZXNjcmliZShkZXNjLCBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQgYXNzZXRzUGF0aDtcbiAgICAgIGxldCB6aXBwZWRGaWxlUGF0aDtcbiAgICAgIGxldCB0bXBSb290O1xuXG4gICAgICBiZWZvcmVFYWNoKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYXNzZXRzUGF0aCA9IGF3YWl0IHRlbXBEaXIub3BlbkRpcigpO1xuICAgICAgICB0bXBSb290ID0gYXdhaXQgdGVtcERpci5vcGVuRGlyKCk7XG4gICAgICAgIGNvbnN0IHppcHBlZEJhc2U2NCA9ICdVRXNEQkFvQUFBQUFBTGx6azBvQUFBQUFBQUFBQUFBQUFBQUpBQkFBZFc1NmFYQndaV1F2VlZnTUFOQk8rVmpPMXZkWTlRRVVBRkJMQXdRS0FBQUFBQURBYzVOS0FBQUFBQUFBQUFBQUFBQUFFZ0FRQUhWdWVtbHdjR1ZrTDNSbGMzUXRaR2x5TDFWWURBRFFUdmxZMTliM1dQVUJGQUJRU3dNRUZBQUlBQWdBd25PVFNnQUFBQUFBQUFBQUFBQUFBQmNBRUFCMWJucHBjSEJsWkM5MFpYTjBMV1JwY2k5aExuUjRkRlZZREFDRFR2bFkzTmIzV1BVQkZBRHpTTTNKeVZjSXp5L0tTUUVBVUVzSENGYXhGMG9OQUFBQUN3QUFBRkJMQXdRVUFBZ0FDQURFYzVOS0FBQUFBQUFBQUFBQUFBQUFGd0FRQUhWdWVtbHdjR1ZrTDNSbGMzUXRaR2x5TDJJdWRIaDBWVmdNQUlOTytWamYxdmRZOVFFVUFIUEx6MWR3U2l3Q0FGQkxCd2hJZnJaSkNRQUFBQWNBQUFCUVN3RUNGUU1LQUFBQUFBQzVjNU5LQUFBQUFBQUFBQUFBQUFBQUNRQU1BQUFBQUFBQUFBQkE3VUVBQUFBQWRXNTZhWEJ3WldRdlZWZ0lBTkJPK1ZqTzF2ZFlVRXNCQWhVRENnQUFBQUFBd0hPVFNnQUFBQUFBQUFBQUFBQUFBQklBREFBQUFBQUFBQUFBUU8xQk53QUFBSFZ1ZW1sd2NHVmtMM1JsYzNRdFpHbHlMMVZZQ0FEUVR2bFkxOWIzV0ZCTEFRSVZBeFFBQ0FBSUFNSnprMHBXc1JkS0RRQUFBQXNBQUFBWEFBd0FBQUFBQUFBQUFFQ2tnWGNBQUFCMWJucHBjSEJsWkM5MFpYTjBMV1JwY2k5aExuUjRkRlZZQ0FDRFR2bFkzTmIzV0ZCTEFRSVZBeFFBQ0FBSUFNUnprMHBJZnJaSkNRQUFBQWNBQUFBWEFBd0FBQUFBQUFBQUFFQ2tnZGtBQUFCMWJucHBjSEJsWkM5MFpYTjBMV1JwY2k5aUxuUjRkRlZZQ0FDRFR2bFkzOWIzV0ZCTEJRWUFBQUFBQkFBRUFERUJBQUEzQVFBQUFBQT0nO1xuICAgICAgICB6aXBwZWRGaWxlUGF0aCA9IHBhdGgucmVzb2x2ZSh0bXBSb290LCAnemlwcGVkLnppcCcpO1xuICAgICAgICBhd2FpdCBmcy53cml0ZUZpbGUoemlwcGVkRmlsZVBhdGgsIHppcHBlZEJhc2U2NCwgJ2Jhc2U2NCcpO1xuICAgICAgICBhd2FpdCB6aXAuZXh0cmFjdEFsbFRvKHppcHBlZEZpbGVQYXRoLCBhc3NldHNQYXRoLCBvcHRpb25zKTtcbiAgICAgIH0pO1xuXG4gICAgICBhZnRlckVhY2goYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBmb3IgKGNvbnN0IHRtcFBhdGggb2YgW2Fzc2V0c1BhdGgsIHRtcFJvb3RdKSB7XG4gICAgICAgICAgaWYgKCFhd2FpdCBmcy5leGlzdHModG1wUGF0aCkpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgICBhd2FpdCBmcy5yaW1yYWYodG1wUGF0aCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZSgnZXh0cmFjdEFsbFRvKCknLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGl0KCdzaG91bGQgZXh0cmFjdCBjb250ZW50cyBvZiBhIC56aXAgZmlsZSB0byBhIGRpcmVjdG9yeScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBhd2FpdCBmcy5yZWFkRmlsZShwYXRoLnJlc29sdmUoYXNzZXRzUGF0aCwgJ3VuemlwcGVkJywgJ3Rlc3QtZGlyJywgJ2EudHh0JyksIHtlbmNvZGluZzogJ3V0ZjgnfSkuc2hvdWxkLmV2ZW50dWFsbHkuZXF1YWwoJ0hlbGxvIFdvcmxkJyk7XG4gICAgICAgICAgYXdhaXQgZnMucmVhZEZpbGUocGF0aC5yZXNvbHZlKGFzc2V0c1BhdGgsICd1bnppcHBlZCcsICd0ZXN0LWRpcicsICdiLnR4dCcpLCB7ZW5jb2Rpbmc6ICd1dGY4J30pLnNob3VsZC5ldmVudHVhbGx5LmVxdWFsKCdGb28gQmFyJyk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKCdhc3NlcnRWYWxpZFppcCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaXQoJ3Nob3VsZCBub3QgdGhyb3cgYW4gZXJyb3IgaWYgYSB2YWxpZCBaSVAgZmlsZSBpcyBwYXNzZWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgYXdhaXQgemlwLmFzc2VydFZhbGlkWmlwKHppcHBlZEZpbGVQYXRoKS5zaG91bGQuZXZlbnR1YWxseS5iZS5mdWxmaWxsZWQ7XG4gICAgICAgIH0pO1xuICAgICAgICBpdCgnc2hvdWxkIHRocm93IGFuIGVycm9yIGlmIHRoZSBmaWxlIGRvZXMgbm90IGV4aXN0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGF3YWl0IHppcC5hc3NlcnRWYWxpZFppcCgnYmxhYmxhJykuc2hvdWxkLmV2ZW50dWFsbHkuYmUucmVqZWN0ZWQ7XG4gICAgICAgIH0pO1xuICAgICAgICBpdCgnc2hvdWxkIHRocm93IGFuIGVycm9yIGlmIHRoZSBmaWxlIGlzIGludmFsaWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgYXdhaXQgemlwLmFzc2VydFZhbGlkWmlwKHBhdGgucmVzb2x2ZShhc3NldHNQYXRoLCAndW56aXBwZWQnLCAndGVzdC1kaXInLCAnYS50eHQnKSkuc2hvdWxkLmV2ZW50dWFsbHkuYmUucmVqZWN0ZWQ7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKCdyZWFkRW50cmllcygpJywgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCBleHBlY3RlZEVudHJpZXMgPSBbXG4gICAgICAgICAge25hbWU6ICd1bnppcHBlZC8nfSxcbiAgICAgICAgICB7bmFtZTogJ3VuemlwcGVkL3Rlc3QtZGlyLyd9LFxuICAgICAgICAgIHtuYW1lOiAndW56aXBwZWQvdGVzdC1kaXIvYS50eHQnLCBjb250ZW50czogJ0hlbGxvIFdvcmxkJ30sXG4gICAgICAgICAge25hbWU6ICd1bnppcHBlZC90ZXN0LWRpci9iLnR4dCcsIGNvbnRlbnRzOiAnRm9vIEJhcid9LFxuICAgICAgICBdO1xuXG4gICAgICAgIGl0KCdzaG91bGQgaXRlcmF0ZSBlbnRyaWVzIChkaXJlY3RvcmllcyBhbmQgZmlsZXMpIG9mIHppcCBmaWxlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGxldCBpID0gMDtcbiAgICAgICAgICBhd2FpdCB6aXAucmVhZEVudHJpZXMoemlwcGVkRmlsZVBhdGgsIGFzeW5jICh7ZW50cnksIGV4dHJhY3RFbnRyeVRvfSkgPT4ge1xuICAgICAgICAgICAgZW50cnkuZmlsZU5hbWUuc2hvdWxkLmVxdWFsKGV4cGVjdGVkRW50cmllc1tpXS5uYW1lKTtcblxuICAgICAgICAgICAgLy8gSWYgaXQncyBhIGZpbGUsIHRlc3QgdGhhdCB3ZSBjYW4gZXh0cmFjdCBpdCB0byBhIHRlbXBvcmFyeSBkaXJlY3RvcnkgYW5kIHRoYXQgdGhlIGNvbnRlbnRzIGFyZSBjb3JyZWN0XG4gICAgICAgICAgICBpZiAoZXhwZWN0ZWRFbnRyaWVzW2ldLmNvbnRlbnRzKSB7XG4gICAgICAgICAgICAgIGF3YWl0IGV4dHJhY3RFbnRyeVRvKHRtcFJvb3QpO1xuICAgICAgICAgICAgICBhd2FpdCBmcy5yZWFkRmlsZShwYXRoLnJlc29sdmUodG1wUm9vdCwgZW50cnkuZmlsZU5hbWUpLCB7XG4gICAgICAgICAgICAgICAgZmxhZ3M6ICdyJyxcbiAgICAgICAgICAgICAgICBlbmNvZGluZzogJ3V0ZjgnXG4gICAgICAgICAgICAgIH0pLnNob3VsZC5ldmVudHVhbGx5LmVxdWFsKGV4cGVjdGVkRW50cmllc1tpXS5jb250ZW50cyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpKys7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KCdzaG91bGQgc3RvcCBpdGVyYXRpbmcgemlwRmlsZSBpZiBvbkVudHJ5IGNhbGxiYWNrIHJldHVybnMgZmFsc2UnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgbGV0IGkgPSAwO1xuICAgICAgICAgIGF3YWl0IHppcC5yZWFkRW50cmllcyh6aXBwZWRGaWxlUGF0aCwgYXN5bmMgKCkgPT4geyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIHJlcXVpcmUtYXdhaXRcbiAgICAgICAgICAgIGkrKztcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgICBpLnNob3VsZC5lcXVhbCgxKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoJ3Nob3VsZCBiZSByZWplY3RlZCBpZiBpdCB1c2VzIGEgbm9uLXppcCBmaWxlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGxldCBwcm9taXNlID0gemlwLnJlYWRFbnRyaWVzKHBhdGgucmVzb2x2ZShhc3NldHNQYXRoLCAndW56aXBwZWQnLCAndGVzdC1kaXInLCAnYS50eHQnKSwgYXN5bmMgKCkgPT4ge30pO1xuICAgICAgICAgIGF3YWl0IHByb21pc2Uuc2hvdWxkLmV2ZW50dWFsbHkuYmUucmVqZWN0ZWQ7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKCd0b0luTWVtb3J5WmlwKCknLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGl0KCdzaG91bGQgY29udmVydCBhIGxvY2FsIGZpbGUgdG8gYW4gaW4tbWVtb3J5IHppcCBidWZmZXInLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgLy8gQ29udmVydCBkaXJlY3RvcnkgdG8gaW4tbWVtb3J5IGJ1ZmZlclxuICAgICAgICAgIGNvbnN0IHRlc3RGb2xkZXIgPSBwYXRoLnJlc29sdmUoYXNzZXRzUGF0aCwgJ3VuemlwcGVkJyk7XG4gICAgICAgICAgY29uc3QgYnVmZmVyID0gYXdhaXQgemlwLnRvSW5NZW1vcnlaaXAodGVzdEZvbGRlcik7XG4gICAgICAgICAgQnVmZmVyLmlzQnVmZmVyKGJ1ZmZlcikuc2hvdWxkLmJlLnRydWU7XG5cbiAgICAgICAgICAvLyBXcml0ZSB0aGUgYnVmZmVyIHRvIGEgemlwIGZpbGVcbiAgICAgICAgICBhd2FpdCBmcy53cml0ZUZpbGUocGF0aC5yZXNvbHZlKHRtcFJvb3QsICd0ZXN0LnppcCcpLCBidWZmZXIpO1xuXG4gICAgICAgICAgLy8gVW56aXAgdGhlIGZpbGUgYW5kIHRlc3QgdGhhdCBpdCBoYXMgdGhlIHNhbWUgY29udGVudHMgYXMgdGhlIGRpcmVjdG9yeSB0aGF0IHdhcyB6aXBwZWRcbiAgICAgICAgICBhd2FpdCB6aXAuZXh0cmFjdEFsbFRvKHBhdGgucmVzb2x2ZSh0bXBSb290LCAndGVzdC56aXAnKSwgcGF0aC5yZXNvbHZlKHRtcFJvb3QsICdvdXRwdXQnKSwge1xuICAgICAgICAgICAgZmlsZU5hbWVzRW5jb2Rpbmc6ICd1dGY4J1xuICAgICAgICAgIH0pO1xuICAgICAgICAgIGF3YWl0IGZzLnJlYWRGaWxlKHBhdGgucmVzb2x2ZSh0bXBSb290LCAnb3V0cHV0JywgJ3Rlc3QtZGlyJywgJ2EudHh0JyksIHtcbiAgICAgICAgICAgIGVuY29kaW5nOiAndXRmOCdcbiAgICAgICAgICB9KS5zaG91bGQuZXZlbnR1YWxseS5lcXVhbCgnSGVsbG8gV29ybGQnKTtcbiAgICAgICAgICBhd2FpdCBmcy5yZWFkRmlsZShwYXRoLnJlc29sdmUodG1wUm9vdCwgJ291dHB1dCcsICd0ZXN0LWRpcicsICdiLnR4dCcpLCB7XG4gICAgICAgICAgICBlbmNvZGluZzogJ3V0ZjgnXG4gICAgICAgICAgfSkuc2hvdWxkLmV2ZW50dWFsbHkuZXF1YWwoJ0ZvbyBCYXInKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoJ3Nob3VsZCBjb252ZXJ0IGEgbG9jYWwgZm9sZGVyIHRvIGFuIGluLW1lbW9yeSBiYXNlNjQtZW5jb2RlZCB6aXAgYnVmZmVyJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IHRlc3RGb2xkZXIgPSBwYXRoLnJlc29sdmUoYXNzZXRzUGF0aCwgJ3VuemlwcGVkJyk7XG4gICAgICAgICAgY29uc3QgYnVmZmVyID0gYXdhaXQgemlwLnRvSW5NZW1vcnlaaXAodGVzdEZvbGRlciwge1xuICAgICAgICAgICAgZW5jb2RlVG9CYXNlNjQ6IHRydWUsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICBhd2FpdCBmcy53cml0ZUZpbGUocGF0aC5yZXNvbHZlKHRtcFJvb3QsICd0ZXN0LnppcCcpLCBCdWZmZXIuZnJvbShidWZmZXIudG9TdHJpbmcoKSwgJ2Jhc2U2NCcpKTtcblxuICAgICAgICAgIC8vIFVuemlwIHRoZSBmaWxlIGFuZCB0ZXN0IHRoYXQgaXQgaGFzIHRoZSBzYW1lIGNvbnRlbnRzIGFzIHRoZSBkaXJlY3RvcnkgdGhhdCB3YXMgemlwcGVkXG4gICAgICAgICAgYXdhaXQgemlwLmV4dHJhY3RBbGxUbyhwYXRoLnJlc29sdmUodG1wUm9vdCwgJ3Rlc3QuemlwJyksIHBhdGgucmVzb2x2ZSh0bXBSb290LCAnb3V0cHV0JykpO1xuICAgICAgICAgIGF3YWl0IGZzLnJlYWRGaWxlKHBhdGgucmVzb2x2ZSh0bXBSb290LCAnb3V0cHV0JywgJ3Rlc3QtZGlyJywgJ2EudHh0JyksIHtcbiAgICAgICAgICAgIGVuY29kaW5nOiAndXRmOCdcbiAgICAgICAgICB9KS5zaG91bGQuZXZlbnR1YWxseS5lcXVhbCgnSGVsbG8gV29ybGQnKTtcbiAgICAgICAgICBhd2FpdCBmcy5yZWFkRmlsZShwYXRoLnJlc29sdmUodG1wUm9vdCwgJ291dHB1dCcsICd0ZXN0LWRpcicsICdiLnR4dCcpLCB7XG4gICAgICAgICAgICBlbmNvZGluZzogJ3V0ZjgnXG4gICAgICAgICAgfSkuc2hvdWxkLmV2ZW50dWFsbHkuZXF1YWwoJ0ZvbyBCYXInKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoJ3Nob3VsZCBiZSByZWplY3RlZCBpZiB1c2UgYSBiYWQgcGF0aCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBhd2FpdCB6aXAudG9Jbk1lbW9yeVppcChwYXRoLnJlc29sdmUoYXNzZXRzUGF0aCwgJ2JhZF9wYXRoJykpXG4gICAgICAgICAgICAuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvbm8gc3VjaC9pKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoJ3Nob3VsZCBiZSByZWplY3RlZCBpZiBtYXggc2l6ZSBpcyBleGNlZWRlZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBjb25zdCB0ZXN0Rm9sZGVyID0gcGF0aC5yZXNvbHZlKGFzc2V0c1BhdGgsICd1bnppcHBlZCcpO1xuICAgICAgICAgIGF3YWl0IHppcC50b0luTWVtb3J5WmlwKHRlc3RGb2xkZXIsIHtcbiAgICAgICAgICAgIG1heFNpemU6IDEsXG4gICAgICAgICAgfSkuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvbXVzdCBub3QgYmUgZ3JlYXRlci8pO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZSgnX2V4dHJhY3RFbnRyeVRvKCknLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGxldCBlbnRyeSwgbW9ja1ppcEZpbGUsIG1vY2taaXBTdHJlYW07XG4gICAgICAgIGJlZm9yZUVhY2goYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGVudHJ5ID0ge2ZpbGVOYW1lOiBwYXRoLnJlc29sdmUoYXdhaXQgdGVtcERpci5vcGVuRGlyKCksICd0ZW1wJywgJ2ZpbGUnKX07XG4gICAgICAgICAgbW9ja1ppcFN0cmVhbSA9IG5ldyBNb2NrUmVhZFdyaXRlU3RyZWFtKCk7XG4gICAgICAgICAgbW9ja1ppcEZpbGUgPSB7XG4gICAgICAgICAgICBvcGVuUmVhZFN0cmVhbTogKGVudHJ5LCBjYikgPT4gY2IobnVsbCwgbW9ja1ppcFN0cmVhbSksIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgcHJvbWlzZS9wcmVmZXItYXdhaXQtdG8tY2FsbGJhY2tzXG4gICAgICAgICAgfTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoJ3Nob3VsZCBiZSByZWplY3RlZCBpZiB6aXAgc3RyZWFtIGVtaXRzIGFuIGVycm9yJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIG1vY2taaXBTdHJlYW0ucGlwZSA9ICgpID0+IHtcbiAgICAgICAgICAgIG1vY2taaXBTdHJlYW0uZW1pdCgnZXJyb3InLCBuZXcgRXJyb3IoJ3ppcCBzdHJlYW0gZXJyb3InKSk7XG4gICAgICAgICAgfTtcbiAgICAgICAgICBhd2FpdCB6aXAuX2V4dHJhY3RFbnRyeVRvKG1vY2taaXBGaWxlLCBlbnRyeSkuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnemlwIHN0cmVhbSBlcnJvcicpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdCgnc2hvdWxkIGJlIHJlamVjdGVkIGlmIHdyaXRlIHN0cmVhbSBlbWl0cyBhbiBlcnJvcicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBtb2NrWmlwU3RyZWFtLnBpcGUgPSAod3JpdGVTdHJlYW0pID0+IHtcbiAgICAgICAgICAgIHdyaXRlU3RyZWFtLmVtaXQoJ2Vycm9yJywgbmV3IEVycm9yKCd3cml0ZSBzdHJlYW0gZXJyb3InKSk7XG4gICAgICAgICAgICBtb2NrWmlwU3RyZWFtLmVuZCgpO1xuICAgICAgICAgICAgd3JpdGVTdHJlYW0uZW5kKCk7XG4gICAgICAgICAgfTtcbiAgICAgICAgICBhd2FpdCB6aXAuX2V4dHJhY3RFbnRyeVRvKG1vY2taaXBGaWxlLCBlbnRyeSkuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnd3JpdGUgc3RyZWFtIGVycm9yJyk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKCd0b0FyY2hpdmUnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGl0KCdzaG91bGQgemlwIGFsbCBmaWxlcyBpbnRvIGFuIGFyY2hpdmUnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgY29uc3QgdGVzdEZvbGRlciA9IHBhdGgucmVzb2x2ZShhc3NldHNQYXRoLCAndW56aXBwZWQnKTtcbiAgICAgICAgICBjb25zdCBkc3RQYXRoID0gcGF0aC5yZXNvbHZlKHRtcFJvb3QsICd0ZXN0LnppcCcpO1xuICAgICAgICAgIGF3YWl0IHppcC50b0FyY2hpdmUoZHN0UGF0aCwge1xuICAgICAgICAgICAgY3dkOiB0ZXN0Rm9sZGVyLFxuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgLy8gVW56aXAgdGhlIGZpbGUgYW5kIHRlc3QgdGhhdCBpdCBoYXMgdGhlIHNhbWUgY29udGVudHMgYXMgdGhlIGRpcmVjdG9yeSB0aGF0IHdhcyB6aXBwZWRcbiAgICAgICAgICBhd2FpdCB6aXAuZXh0cmFjdEFsbFRvKGRzdFBhdGgsIHBhdGgucmVzb2x2ZSh0bXBSb290LCAnb3V0cHV0JykpO1xuICAgICAgICAgIGF3YWl0IGZzLnJlYWRGaWxlKHBhdGgucmVzb2x2ZSh0bXBSb290LCAnb3V0cHV0JywgJ3Rlc3QtZGlyJywgJ2EudHh0JyksIHtcbiAgICAgICAgICAgIGVuY29kaW5nOiAndXRmOCdcbiAgICAgICAgICB9KS5zaG91bGQuZXZlbnR1YWxseS5lcXVhbCgnSGVsbG8gV29ybGQnKTtcbiAgICAgICAgICBhd2FpdCBmcy5yZWFkRmlsZShwYXRoLnJlc29sdmUodG1wUm9vdCwgJ291dHB1dCcsICd0ZXN0LWRpcicsICdiLnR4dCcpLCB7XG4gICAgICAgICAgICBlbmNvZGluZzogJ3V0ZjgnXG4gICAgICAgICAgfSkuc2hvdWxkLmV2ZW50dWFsbHkuZXF1YWwoJ0ZvbyBCYXInKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuXG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCd1bmljb2RlIGZpbGVuYW1lIGhhbmRsaW5nJywgZnVuY3Rpb24gKCkge1xuICAgIGxldCB6aXBwZWRGaWxlUGF0aCwgYXNzZXRzUGF0aCwgdG1wUm9vdDtcblxuICAgIGJlZm9yZUVhY2goYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYXNzZXRzUGF0aCA9IGF3YWl0IHRlbXBEaXIub3BlbkRpcigpO1xuICAgICAgdG1wUm9vdCA9IGF3YWl0IHRlbXBEaXIub3BlbkRpcigpO1xuXG4gICAgICBjb25zdCB6aXBwZWRCYXNlNjQgPSAnVUVzREJCUUFDQUFJQUJGOC9FWUFBQUFBQUFBQUFCb0FBQUFUQUNBQWEyRnVhbWt0NXEyajVMaVc1TGlWTG1Gd2NGVlVEUUFIQWdPNFZWcFgrR0JaVi9oZ2RYZ0xBQUVFOVFFQUFBUVVBQUFBSzhuSUxGWUFvcno4RW9XaTFNU2NuRXFGeER5RnhJSUNMZ0JRU3djSVI5M2pQaG9BQUFBYUFBQUFVRXNCQWhRREZBQUlBQWdBRVh6OFJrZmQ0ejRhQUFBQUdnQUFBQk1BSUFBQUFBQUFBQUFBQUtTQkFBQUFBR3RoYm1wcExlYXRvK1M0bHVTNGxTNWhjSEJWVkEwQUJ3SUR1RlZhVi9oZ1dWZjRZSFY0Q3dBQkJQVUJBQUFFRkFBQUFGQkxCUVlBQUFBQUFRQUJBR0VBQUFCN0FBQUFBQUE9JztcbiAgICAgIHppcHBlZEZpbGVQYXRoID0gcGF0aC5yZXNvbHZlKHRtcFJvb3QsICd6aXBwZWQuemlwJyk7XG4gICAgICBhd2FpdCBmcy53cml0ZUZpbGUoemlwcGVkRmlsZVBhdGgsIHppcHBlZEJhc2U2NCwgJ2Jhc2U2NCcpO1xuICAgICAgYXdhaXQgemlwLmV4dHJhY3RBbGxUbyh6aXBwZWRGaWxlUGF0aCwgYXNzZXRzUGF0aCwge3VzZVN5c3RlbVVuemlwOiB0cnVlfSk7XG4gICAgfSk7XG5cbiAgICBhZnRlckVhY2goYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgZm9yIChjb25zdCB0bXBQYXRoIG9mIFthc3NldHNQYXRoLCB0bXBSb290XSkge1xuICAgICAgICBpZiAoIWF3YWl0IGZzLmV4aXN0cyh0bXBQYXRoKSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IGZzLnJpbXJhZih0bXBQYXRoKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcmV0YWluIHRoZSBwcm9wZXIgZmlsZW5hbWVzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZXhwZWN0ZWRQYXRoID0gcGF0aC5qb2luKGFzc2V0c1BhdGgsICdrYW5qaS3mraPkuJbkuJUuYXBwJyk7XG4gICAgICAvLyB3ZSBjYW5ub3QgdXNlIHRoZSBgc2hvdWxkYCBzeW50YXggYmVjYXVzZSBgZnMuZXhpc3RzYCByZXNvbHZlcyB0byBhIHByaW1pdGl2ZSAoYm9vbGVhbilcbiAgICAgIGlmICghYXdhaXQgZnMuZXhpc3RzKGV4cGVjdGVkUGF0aCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IGNoYWkuQXNzZXJ0aW9uRXJyb3IoYEV4cGVjdGVkICR7ZXhwZWN0ZWRQYXRofSB0byBleGlzdCwgYnV0IGl0IGRvZXMgbm90YCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXSwiZmlsZSI6InRlc3QvemlwLWUyZS1zcGVjcy5qcyIsInNvdXJjZVJvb3QiOiIuLi8uLiJ9
|